dsh-data-cleaning-agent 0.8.6 → 0.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * - `sidebar.footer.action` 仅托管入口生命周期和降级渲染;实际入口 Portal 到
10
10
  * `sidebar.workspaces` 前,位于「新会话」与「工作区」之间。
11
11
  * - DSH 原生会话保持在中间,能力入口使用 `conversation.input.dock` 并通过稳定
12
- * `data-slot` 排到输入框下方;右侧非模态工作台使用 `shell.overlay`。
12
+ * `data-composer-seat/card` 将自有菜单 Portal 到输入框下方;右侧工作台使用 `shell.overlay`。
13
13
  * - 提示词生成器使用 `conversation.input.overlay`,只对本插件创建的会话生效。
14
14
  * Hero 标题没有公开替换槽位,故以可恢复、精确文本匹配的 DOM Bridge 对齐业务首页。
15
15
  *
@@ -32,7 +32,6 @@ window.__ModuleLoader__.load({
32
32
  IconArchiveOutline20,
33
33
  IconChecklistOutline14,
34
34
  IconCloseOutline16,
35
- IconDataOutline16,
36
35
  IconDownloadOutline16,
37
36
  IconFullscreenOutline16,
38
37
  IconPaperclipOutline16,
@@ -55,6 +54,23 @@ window.__ModuleLoader__.load({
55
54
 
56
55
  const h = react.createElement;
57
56
 
57
+ // 同一数据库图形用于入口、业务首页和工作台;不注册 root/single 品牌槽位。
58
+ const DATABASE_PATH = 'M4 6c0-4 16-4 16 0s-16 4-16 0v12c0 4 16 4 16 0V6M4 12c0 4 16 4 16 0';
59
+ function DatabaseLogo({ size = 20 } = {}) {
60
+ return h('svg', { width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
61
+ stroke: 'currentColor', strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round',
62
+ 'aria-hidden': true, focusable: false, className: 'dcAgentDatabaseLogo' },
63
+ h('path', { d: DATABASE_PATH }));
64
+ }
65
+
66
+ // 搜索仅改变可见字段,绝不清除已选字段或改变 Host 的字段目录。
67
+ function visibleCatalogFields(group, query) {
68
+ const needle = String(query || '').trim().toLowerCase();
69
+ const [, label, fields, tool] = group;
70
+ if (!needle || `${label} ${tool || ''}`.toLowerCase().includes(needle)) return fields;
71
+ return fields.filter(([id, fieldLabel]) => `${id} ${fieldLabel}`.toLowerCase().includes(needle));
72
+ }
73
+
58
74
  /** 客户端所需服务:与 mcp-connector 对齐(槽位 + 会话/工作区/输入机)。 */
59
75
  const inject = ['slots', 'sessions', 'workspaces', 'conversation'];
60
76
 
@@ -62,6 +78,31 @@ window.__ModuleLoader__.load({
62
78
  const SIDEBAR_WORKSPACES_SELECTOR = '[data-slot="sidebar.workspaces"]';
63
79
  const TOP_MOUNT_SELECTOR = '[data-data-cleaning-top-mount="true"]';
64
80
  const stylesCss = `
81
+ /* QCC-blue candidate tokens from shared DSH-UX-001; never theme the global shell. */
82
+ :where(.dcAgentTopMount, .dcAgentLauncher, .dcAgentExperience, .dcAgentCapabilityMount,
83
+ .dcAgentOverlay, .dcAgentPromptLayer, .dcAgentPromptBackdrop, .dcAgentHeaderAction,
84
+ .dcAgentToolCard, [data-dc-agent-hero-row="true"]) {
85
+ --dc-action: light-dark(#0875d1, #82c3ff);
86
+ --dc-hover: light-dark(#0666b7, #acd7ff);
87
+ --dc-on-action: light-dark(#fff, #101820);
88
+ --dc-selected: light-dark(#e6f4ff, #173449);
89
+ --dc-surface: light-dark(#fff, #18232e);
90
+ --dc-page: light-dark(#f6f8fa, #101820);
91
+ --dc-table-head: light-dark(#f2f9fc, #172c3b);
92
+ --dc-text: light-dark(#202c3b, #e7eef6);
93
+ --dc-muted: light-dark(#626f80, #a2b1c2);
94
+ --dc-border: light-dark(#dce4ec, #344657);
95
+ --dc-success: light-dark(#12805c, #78d8b3);
96
+ --dc-success-bg: light-dark(#edf8f2, #193a30);
97
+ --dc-review: light-dark(#946000, #f3c66c);
98
+ accent-color: var(--dc-action);
99
+ }
100
+ .dcAgentLauncherContent { display: inline-flex; align-items: center; gap: 8px; }
101
+ .dcAgentDatabaseLogo { display: block; flex: none; color: var(--dc-action); }
102
+ [data-dc-agent-hero-row="true"] { display: flex; align-items: center; justify-content: center; gap: 12px; }
103
+ [data-dc-agent-hero-title="true"] { min-width: 0; font-size: 28px; line-height: 1.3; color: var(--dc-text); }
104
+ .dcAgentHeroLogo { width: 48px; height: 48px; border-radius: 12px; background: var(--dc-selected); color: var(--dc-action); display: grid; place-items: center; flex: none; }
105
+
65
106
  .dcAgentTopMount {
66
107
  flex: none;
67
108
  min-width: 0;
@@ -111,16 +152,17 @@ window.__ModuleLoader__.load({
111
152
  }
112
153
 
113
154
  .dcAgentWorkbench {
155
+ box-sizing: border-box;
114
156
  display: flex;
115
157
  flex-direction: column;
116
158
  width: min(460px, 42vw);
117
159
  max-width: calc(100vw - 420px);
118
160
  min-width: 360px;
119
161
  height: 100vh;
120
- border: 1px solid light-dark(#d5dae4, #2a3038);
162
+ border: 1px solid var(--dc-border);
121
163
  border-radius: 12px 0 0 12px;
122
- background: light-dark(#ffffff, #161b23);
123
- color: light-dark(#172033, #edf2fa);
164
+ background: var(--dc-surface);
165
+ color: var(--dc-text);
124
166
  box-shadow: light-dark(-10px 0 32px rgba(33, 55, 88, .12), -12px 0 40px rgba(0, 0, 0, .32));
125
167
  overflow: hidden;
126
168
  pointer-events: auto;
@@ -129,7 +171,7 @@ window.__ModuleLoader__.load({
129
171
 
130
172
  .dcAgentCapabilities {
131
173
  display: flex;
132
- justify-content: center;
174
+ justify-content: safe center;
133
175
  align-items: center;
134
176
  gap: 8px;
135
177
  width: 100%;
@@ -153,10 +195,10 @@ window.__ModuleLoader__.load({
153
195
  padding: 7px 12px;
154
196
  flex-direction: column;
155
197
  justify-content: center;
156
- border: 1px solid light-dark(#e4e8f0, #303947);
198
+ border: 1px solid var(--dc-border);
157
199
  border-radius: 12px;
158
- background: light-dark(rgba(255,255,255,.86), rgba(22,27,35,.86));
159
- color: light-dark(#5d687a, #aab5c7);
200
+ background: var(--dc-surface);
201
+ color: var(--dc-muted);
160
202
  font: inherit;
161
203
  font-size: 12px;
162
204
  cursor: pointer;
@@ -164,78 +206,23 @@ window.__ModuleLoader__.load({
164
206
  .dcAgentCapability:hover,
165
207
  .dcAgentCapability:focus-visible,
166
208
  .dcAgentCapability.is-active {
167
- border-color: light-dark(#c9d9f8, #365681);
168
- background: light-dark(#edf4ff, #172841);
169
- color: light-dark(#1556cf, #8cb3ff);
209
+ border-color: var(--dc-border);
210
+ background: var(--dc-selected);
211
+ color: var(--dc-action);
170
212
  }
171
213
  .dcAgentCapability svg { flex: 0 0 auto; }
172
214
 
173
- /* DSH 官方 input.dock 默认在 composer 上方;只把本插件自己的 cell 排到下方。 */
174
- [data-slot="conversation.input.dock"]:has(.dcAgentExperience) {
175
- order: 20;
176
- }
215
+ /* 原生 input.dock 保留轻量简介;菜单独立 Portal 到 composer 后,不重排共享 slot。 */
177
216
 
178
217
  .dcAgentExperience {
179
218
  width: 100%;
180
219
  box-sizing: border-box;
181
220
  }
221
+ .dcAgentCapabilityMount { width: 100%; padding: 8px 0; flex: none; }
222
+ .dcAgentHomeSummary { margin: 0 20px 8px; text-align: center; color: var(--dc-muted); font-size: 13px; line-height: 20px; }
223
+ .dcAgentPromptBackdrop { position: fixed; inset: 0; z-index: 2000; display: grid; place-items: center; padding: 16px; box-sizing: border-box; background: rgba(8, 15, 28, .36); pointer-events: auto; }
224
+ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
182
225
 
183
- .dcAgentProductHome {
184
- width: 100%;
185
- max-width: 980px;
186
- box-sizing: border-box;
187
- margin: 10px auto 0;
188
- padding: 16px 18px;
189
- border: 1px solid light-dark(#e4e8f0, #303947);
190
- border-radius: 16px;
191
- background: light-dark(rgba(255,255,255,.82), rgba(20,25,33,.86));
192
- box-shadow: light-dark(0 10px 30px rgba(42,75,120,.06), 0 14px 34px rgba(0,0,0,.14));
193
- }
194
- .dcAgentProductHome h2 {
195
- margin: 0;
196
- color: light-dark(#172033, #edf2fa);
197
- font-size: 16px;
198
- line-height: 24px;
199
- }
200
- .dcAgentProductHome > p {
201
- margin: 4px 0 12px;
202
- color: light-dark(#697386, #aab5c7);
203
- font-size: 12px;
204
- line-height: 18px;
205
- }
206
- .dcAgentHomeFlow {
207
- display: grid;
208
- grid-template-columns: repeat(7, minmax(0, 1fr));
209
- gap: 8px;
210
- }
211
- .dcAgentHomeStep {
212
- min-width: 0;
213
- padding: 9px 8px;
214
- border-radius: 10px;
215
- background: light-dark(#f4f7fc, #1c2330);
216
- color: light-dark(#33415a, #c9d4e5);
217
- font-size: 12px;
218
- line-height: 18px;
219
- }
220
- .dcAgentHomeStep b {
221
- display: block;
222
- margin-bottom: 2px;
223
- color: light-dark(#1556cf, #8cb3ff);
224
- font-size: 11px;
225
- }
226
- .dcAgentHomeTrust {
227
- display: flex;
228
- flex-wrap: wrap;
229
- gap: 6px;
230
- margin-top: 10px;
231
- }
232
- .dcAgentHomeTrust span {
233
- padding: 3px 8px;
234
- border: 1px solid light-dark(#dce4f1, #344052);
235
- border-radius: 999px;
236
- color: light-dark(#59677c, #b1bdd0);
237
- font-size: 11px;
238
- }
239
226
 
240
227
  /* input.overlay 是 DSH 官方浮层锚点;给触发器让出输入卡片顶部空间。 */
241
228
  [data-composer-card]:has(.dcAgentPromptTrigger) {
@@ -253,31 +240,34 @@ window.__ModuleLoader__.load({
253
240
  left: 16px;
254
241
  min-height: 28px;
255
242
  padding: 3px 10px;
256
- border: 1px solid light-dark(#c9d9f8, #365681);
243
+ border: 1px solid var(--dc-border);
257
244
  border-radius: 999px;
258
- background: light-dark(#edf4ff, #172841);
259
- color: light-dark(#1556cf, #8cb3ff);
245
+ background: var(--dc-selected);
246
+ color: var(--dc-action);
260
247
  font: inherit;
261
248
  font-size: 12px;
262
249
  cursor: pointer;
263
250
  pointer-events: auto;
264
251
  }
265
252
  .dcAgentPromptPanel {
266
- position: absolute;
267
- top: 44px;
268
- left: 16px;
269
- width: min(660px, calc(100vw - 120px));
270
- max-height: min(68vh, 660px);
253
+ position: relative;
254
+ display: flex;
255
+ flex-direction: column;
256
+ width: min(860px, 100%);
257
+ max-height: calc(100dvh - 32px);
271
258
  box-sizing: border-box;
272
- overflow: auto;
259
+ overflow: hidden;
273
260
  padding: 16px;
274
- border: 1px solid light-dark(#d5dae4, #303947);
275
- border-radius: 16px;
276
- background: light-dark(#ffffff, #161b23);
277
- color: light-dark(#172033, #edf2fa);
261
+ border: 1px solid var(--dc-border);
262
+ border-radius: 12px;
263
+ background: var(--dc-surface);
264
+ color: var(--dc-text);
278
265
  box-shadow: light-dark(0 18px 48px rgba(33,55,88,.20), 0 20px 54px rgba(0,0,0,.40));
279
266
  pointer-events: auto;
280
267
  }
268
+ .dcAgentPromptBody { min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 0 2px; }
269
+ .dcAgentPromptHead, .dcAgentPromptActions { flex: none; }
270
+ .dcAgentPromptActions { border-top: 1px solid var(--dc-border); padding-top: 12px; }
281
271
  .dcAgentPromptHead {
282
272
  display: flex;
283
273
  align-items: flex-start;
@@ -286,7 +276,7 @@ window.__ModuleLoader__.load({
286
276
  margin-bottom: 12px;
287
277
  }
288
278
  .dcAgentPromptHead h3 { margin: 0; font-size: 16px; line-height: 22px; }
289
- .dcAgentPromptHead p { margin: 3px 0 0; color: light-dark(#697386, #aab5c7); font-size: 11px; line-height: 17px; }
279
+ .dcAgentPromptHead p { margin: 3px 0 0; color: var(--dc-muted); font-size: 12px; line-height: 17px; }
290
280
  .dcAgentPromptClose {
291
281
  width: 28px;
292
282
  height: 28px;
@@ -297,7 +287,7 @@ window.__ModuleLoader__.load({
297
287
  color: inherit;
298
288
  cursor: pointer;
299
289
  }
300
- .dcAgentPromptClose:hover { background: light-dark(#f1f4f8, #222a36); }
290
+ .dcAgentPromptClose:hover { background: var(--dc-page); }
301
291
  .dcAgentPromptTabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
302
292
  .dcAgentPromptTab,
303
293
  .dcAgentPromptChoice {
@@ -306,8 +296,8 @@ window.__ModuleLoader__.load({
306
296
  gap: 5px;
307
297
  min-height: 32px;
308
298
  padding: 5px 10px;
309
- border: 1px solid light-dark(#d9dee8, #394352);
310
- border-radius: 9px;
299
+ border: 1px solid var(--dc-border);
300
+ border-radius: 6px;
311
301
  background: transparent;
312
302
  color: inherit;
313
303
  font: inherit;
@@ -316,9 +306,9 @@ window.__ModuleLoader__.load({
316
306
  }
317
307
  .dcAgentPromptTab.is-active,
318
308
  .dcAgentPromptChoice.is-selected {
319
- border-color: light-dark(#2869e6, #6d9eff);
320
- background: light-dark(#edf4ff, #172841);
321
- color: light-dark(#1556cf, #8cb3ff);
309
+ border-color: var(--dc-action);
310
+ background: var(--dc-selected);
311
+ color: var(--dc-action);
322
312
  }
323
313
  .dcAgentPromptField { display: grid; gap: 6px; margin: 10px 0; }
324
314
  .dcAgentPromptField > span { font-size: 12px; font-weight: 600; }
@@ -328,9 +318,9 @@ window.__ModuleLoader__.load({
328
318
  min-height: 104px;
329
319
  resize: vertical;
330
320
  padding: 10px 12px;
331
- border: 1px solid light-dark(#d9dee8, #394352);
332
- border-radius: 10px;
333
- background: light-dark(#fbfcfe, #11171f);
321
+ border: 1px solid var(--dc-border);
322
+ border-radius: 8px;
323
+ background: var(--dc-page);
334
324
  color: inherit;
335
325
  font: inherit;
336
326
  font-size: 12px;
@@ -342,8 +332,8 @@ window.__ModuleLoader__.load({
342
332
  gap: 10px;
343
333
  padding: 12px;
344
334
  border: 1px dashed light-dark(#b9c5d8, #43516a);
345
- border-radius: 10px;
346
- color: light-dark(#59677c, #b1bdd0);
335
+ border-radius: 8px;
336
+ color: var(--dc-muted);
347
337
  font-size: 12px;
348
338
  }
349
339
  .dcAgentPromptFile input { max-width: 100%; }
@@ -353,17 +343,17 @@ window.__ModuleLoader__.load({
353
343
  padding: 12px;
354
344
  border: 1px dashed light-dark(#b9c5d8, #43516a);
355
345
  border-radius: 12px;
356
- background: light-dark(#fbfcfe, #11171f);
346
+ background: var(--dc-page);
357
347
  outline: none;
358
348
  }
359
349
  .dcAgentPromptImageDrop.is-active {
360
- border-color: #2869e6;
361
- background: light-dark(#edf4ff, #172841);
350
+ border-color: var(--dc-action);
351
+ background: var(--dc-selected);
362
352
  }
363
353
  .dcAgentPromptImageDrop > p {
364
354
  margin: 0;
365
- color: light-dark(#697386, #aab5c7);
366
- font-size: 11px;
355
+ color: var(--dc-muted);
356
+ font-size: 12px;
367
357
  line-height: 17px;
368
358
  }
369
359
  .dcAgentPromptImagePreview {
@@ -378,31 +368,31 @@ window.__ModuleLoader__.load({
378
368
  flex: 0 0 auto;
379
369
  overflow: hidden;
380
370
  padding: 0;
381
- border: 1px solid light-dark(#d9dee8, #394352);
382
- border-radius: 10px;
383
- background: light-dark(#f3f6fa, #202733);
371
+ border: 1px solid var(--dc-border);
372
+ border-radius: 8px;
373
+ background: var(--dc-page);
384
374
  cursor: zoom-in;
385
375
  }
386
376
  .dcAgentPromptImageThumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
387
377
  .dcAgentPromptImageMeta { min-width: 0; flex: 1 1 auto; }
388
378
  .dcAgentPromptImageMeta b,
389
379
  .dcAgentPromptImageMeta small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
390
- .dcAgentPromptImageMeta small { margin-top: 3px; color: light-dark(#697386, #aab5c7); }
380
+ .dcAgentPromptImageMeta small { margin-top: 3px; color: var(--dc-muted); }
391
381
  .dcAgentPromptImageRemove {
392
382
  flex: 0 0 auto;
393
383
  padding: 5px 9px;
394
- border: 1px solid light-dark(#d9dee8, #394352);
384
+ border: 1px solid var(--dc-border);
395
385
  border-radius: 8px;
396
386
  background: transparent;
397
387
  color: inherit;
398
388
  font: inherit;
399
- font-size: 11px;
389
+ font-size: 12px;
400
390
  cursor: pointer;
401
391
  }
402
392
  .dcAgentImageLightbox {
403
393
  position: fixed;
404
394
  inset: 0;
405
- z-index: 1400;
395
+ z-index: 2100;
406
396
  display: grid;
407
397
  place-items: center;
408
398
  padding: 32px;
@@ -427,25 +417,25 @@ window.__ModuleLoader__.load({
427
417
  margin: 10px 0 0;
428
418
  padding: 8px 10px;
429
419
  border-radius: 8px;
430
- background: light-dark(#f6f8fb, #1c2330);
431
- color: light-dark(#697386, #aab5c7);
432
- font-size: 11px;
420
+ background: var(--dc-page);
421
+ color: var(--dc-muted);
422
+ font-size: 12px;
433
423
  line-height: 17px;
434
424
  }
435
- .dcAgentPromptError { margin: 8px 0 0; color: light-dark(#b42318, #ff8d86); font-size: 11px; }
425
+ .dcAgentPromptError { margin: 8px 0 0; color: light-dark(#b42318, #ff8d86); font-size: 12px; }
436
426
  .dcAgentPromptActions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
437
427
  .dcAgentPromptAction {
438
428
  min-height: 34px;
439
429
  padding: 6px 13px;
440
- border: 1px solid light-dark(#d9dee8, #394352);
441
- border-radius: 9px;
430
+ border: 1px solid var(--dc-border);
431
+ border-radius: 6px;
442
432
  background: transparent;
443
433
  color: inherit;
444
434
  font: inherit;
445
435
  font-size: 12px;
446
436
  cursor: pointer;
447
437
  }
448
- .dcAgentPromptAction.is-primary { border-color: #2869e6; background: #2869e6; color: white; }
438
+ .dcAgentPromptAction.is-primary { border-color: var(--dc-action); background: var(--dc-action); color: var(--dc-on-action); }
449
439
  .dcAgentPromptAction:disabled { opacity: .5; cursor: default; }
450
440
 
451
441
  .dcAgentHeaderAction {
@@ -454,9 +444,9 @@ window.__ModuleLoader__.load({
454
444
  gap: 6px;
455
445
  min-height: 30px;
456
446
  padding: 4px 9px;
457
- border: 1px solid light-dark(#d9dee8, #394352);
447
+ border: 1px solid var(--dc-border);
458
448
  border-radius: 8px;
459
- background: light-dark(#ffffff, #191f28);
449
+ background: var(--dc-surface);
460
450
  color: inherit;
461
451
  font: inherit;
462
452
  font-size: 12px;
@@ -464,8 +454,8 @@ window.__ModuleLoader__.load({
464
454
  }
465
455
  .dcAgentHeaderAction:hover,
466
456
  .dcAgentHeaderAction:focus-visible {
467
- border-color: light-dark(#2869e6, #6d9eff);
468
- color: light-dark(#1556cf, #8cb3ff);
457
+ border-color: var(--dc-action);
458
+ color: var(--dc-action);
469
459
  }
470
460
 
471
461
  .dcAgentWbHeader {
@@ -473,7 +463,7 @@ window.__ModuleLoader__.load({
473
463
  align-items: center;
474
464
  gap: 8px;
475
465
  padding: 12px 14px;
476
- border-bottom: 1px solid light-dark(#e4e8f0, #303947);
466
+ border-bottom: 1px solid var(--dc-border);
477
467
  }
478
468
 
479
469
  .dcAgentWbTitle {
@@ -490,15 +480,15 @@ window.__ModuleLoader__.load({
490
480
  display: grid;
491
481
  place-items: center;
492
482
  flex: 0 0 auto;
493
- border-radius: 11px;
483
+ border-radius: 8px;
494
484
  font-size: 18px;
495
- background: light-dark(#edf4ff, #172841);
485
+ background: var(--dc-selected);
496
486
  }
497
487
 
498
488
  .dcAgentWbTitle b,
499
489
  .dcAgentWbTitle small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
500
490
  .dcAgentWbTitle b { display: block; font-size: 15px; }
501
- .dcAgentWbTitle small { display: block; max-width: 190px; color: light-dark(#697386, #aab5c7); font-size: 11px; }
491
+ .dcAgentWbTitle small { display: block; max-width: 190px; color: var(--dc-muted); font-size: 12px; }
502
492
 
503
493
  .dcAgentWbActions {
504
494
  display: flex;
@@ -511,10 +501,10 @@ window.__ModuleLoader__.load({
511
501
  .dcAgentQccBadge {
512
502
  flex: 0 0 auto;
513
503
  padding: 4px 10px;
514
- border: 1px solid light-dark(#e4e8f0, #303947);
504
+ border: 1px solid var(--dc-border);
515
505
  border-radius: 999px;
516
- color: light-dark(#697386, #aab5c7);
517
- font-size: 11px;
506
+ color: var(--dc-muted);
507
+ font-size: 12px;
518
508
  white-space: nowrap;
519
509
  }
520
510
 
@@ -524,22 +514,22 @@ window.__ModuleLoader__.load({
524
514
  height: 30px;
525
515
  display: grid;
526
516
  place-items: center;
527
- border: 1px solid light-dark(#e4e8f0, #303947);
517
+ border: 1px solid var(--dc-border);
528
518
  border-radius: 8px;
529
519
  background: transparent;
530
520
  color: inherit;
531
521
  font-size: 15px;
532
522
  cursor: pointer;
533
523
  }
534
- .dcAgentWbClose:hover, .dcAgentWbClose:focus-visible { background: light-dark(#f6f8fb, #202733); }
524
+ .dcAgentWbClose:hover, .dcAgentWbClose:focus-visible { background: var(--dc-page); }
535
525
 
536
526
  .dcAgentStepper {
537
527
  display: grid;
538
528
  grid-template-columns: repeat(4, minmax(0, 1fr));
539
529
  gap: 8px;
540
530
  padding: 12px 18px;
541
- border-bottom: 1px solid light-dark(#e4e8f0, #303947);
542
- background: light-dark(#fbfcfe, #12171e);
531
+ border-bottom: 1px solid var(--dc-border);
532
+ background: var(--dc-page);
543
533
  }
544
534
 
545
535
  .dcAgentStep {
@@ -548,18 +538,18 @@ window.__ModuleLoader__.load({
548
538
  justify-content: center;
549
539
  gap: 6px;
550
540
  padding: 9px 6px;
551
- border: 1px solid light-dark(#e4e8f0, #303947);
552
- border-radius: 9px;
541
+ border: 1px solid var(--dc-border);
542
+ border-radius: 6px;
553
543
  background: transparent;
554
- color: light-dark(#697386, #aab5c7);
544
+ color: var(--dc-muted);
555
545
  font-size: 12px;
556
546
  cursor: pointer;
557
547
  white-space: nowrap;
558
548
  }
559
549
  .dcAgentStep.is-active {
560
- color: light-dark(#1556cf, #8cb3ff);
561
- border-color: light-dark(#2869e6, #6d9eff);
562
- background: light-dark(#edf4ff, #172841);
550
+ color: var(--dc-action);
551
+ border-color: var(--dc-action);
552
+ background: var(--dc-selected);
563
553
  }
564
554
 
565
555
  .dcAgentWbBody {
@@ -569,16 +559,16 @@ window.__ModuleLoader__.load({
569
559
  }
570
560
 
571
561
  .dcAgentPane { display: flex; flex-direction: column; gap: 14px; }
572
- .dcAgentHint { margin: 0; color: light-dark(#697386, #aab5c7); font-size: 13px; line-height: 1.6; }
562
+ .dcAgentHint { margin: 0; color: var(--dc-muted); font-size: 13px; line-height: 1.6; }
573
563
 
574
564
  .dcAgentTextarea {
575
565
  width: 100%;
576
566
  box-sizing: border-box;
577
567
  min-height: 132px;
578
568
  padding: 12px;
579
- border: 1px solid light-dark(#cfd6e2, #485364);
580
- border-radius: 10px;
581
- background: light-dark(#ffffff, #191f28);
569
+ border: 1px solid var(--dc-border);
570
+ border-radius: 8px;
571
+ background: var(--dc-surface);
582
572
  color: inherit;
583
573
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
584
574
  font-size: 12px;
@@ -591,29 +581,29 @@ window.__ModuleLoader__.load({
591
581
  box-sizing: border-box;
592
582
  min-width: 0;
593
583
  padding: 8px 12px;
594
- border: 1px solid light-dark(#cfd6e2, #485364);
595
- border-radius: 9px;
584
+ border: 1px solid var(--dc-border);
585
+ border-radius: 6px;
596
586
  font-size: 12px;
597
- background: light-dark(#ffffff, #191f28);
587
+ background: var(--dc-surface);
598
588
  color: inherit;
599
589
  }
600
590
 
601
591
  .dcAgentButton {
602
592
  padding: 9px 16px;
603
- border: 1px solid light-dark(#cfd6e2, #485364);
604
- border-radius: 9px;
605
- background: light-dark(#ffffff, #191f28);
593
+ border: 1px solid var(--dc-border);
594
+ border-radius: 6px;
595
+ background: var(--dc-surface);
606
596
  color: inherit;
607
597
  font-size: 13px;
608
598
  cursor: pointer;
609
599
  }
610
- .dcAgentButton:hover, .dcAgentButton:focus-visible { border-color: light-dark(#2869e6, #6d9eff); }
600
+ .dcAgentButton:hover, .dcAgentButton:focus-visible { border-color: var(--dc-action); }
611
601
  .dcAgentButton.is-primary {
612
602
  border-color: transparent;
613
- color: #ffffff;
614
- background: light-dark(#2869e6, #3d7bf0);
603
+ color: var(--dc-on-action);
604
+ background: var(--dc-action);
615
605
  }
616
- .dcAgentButton.is-primary:hover, .dcAgentButton.is-primary:focus-visible { background: light-dark(#1556cf, #6d9eff); }
606
+ .dcAgentButton.is-primary:hover, .dcAgentButton.is-primary:focus-visible { background: var(--dc-hover); }
617
607
  .dcAgentButton:disabled { opacity: 0.5; cursor: not-allowed; }
618
608
 
619
609
  .dcAgentGrid {
@@ -624,14 +614,14 @@ window.__ModuleLoader__.load({
624
614
 
625
615
  .dcAgentCard {
626
616
  padding: 12px 14px;
627
- border: 1px solid light-dark(#e4e8f0, #303947);
628
- border-radius: 11px;
629
- background: light-dark(#fbfcfe, #191f28);
617
+ border: 1px solid var(--dc-border);
618
+ border-radius: 8px;
619
+ background: var(--dc-page);
630
620
  }
631
- .dcAgentCard span { display: block; color: light-dark(#697386, #aab5c7); font-size: 11px; }
621
+ .dcAgentCard span { display: block; color: var(--dc-muted); font-size: 12px; }
632
622
  .dcAgentCard b { display: block; margin-top: 3px; font-size: 18px; }
633
- .dcAgentCard b.is-good { color: light-dark(#118a5b, #56d39b); }
634
- .dcAgentCard b.is-warn { color: light-dark(#c17412, #f4b85d); }
623
+ .dcAgentCard b.is-good { color: var(--dc-success); }
624
+ .dcAgentCard b.is-warn { color: var(--dc-review); }
635
625
  .dcAgentCard b.is-bad { color: light-dark(#d2454f, #ff838b); }
636
626
 
637
627
  .dcAgentTable {
@@ -642,9 +632,9 @@ window.__ModuleLoader__.load({
642
632
  .dcAgentTable th, .dcAgentTable td {
643
633
  padding: 7px 9px;
644
634
  text-align: left;
645
- border-bottom: 1px solid light-dark(#eef1f6, #242b36);
635
+ border-bottom: 1px solid var(--dc-border);
646
636
  }
647
- .dcAgentTable th { color: light-dark(#697386, #aab5c7); font-weight: 600; }
637
+ .dcAgentTable th { color: var(--dc-muted); font-weight: 600; }
648
638
  .dcAgentTable td.num { font-variant-numeric: tabular-nums; }
649
639
  .dcAgentTableWrap { max-width: 100%; overflow-x: auto; }
650
640
  .dcAgentTableWrap .dcAgentTable { min-width: 720px; table-layout: auto; }
@@ -656,7 +646,7 @@ window.__ModuleLoader__.load({
656
646
  .dcAgentError {
657
647
  padding: 10px 12px;
658
648
  border: 1px solid light-dark(#ffd6d8, #5b2f33);
659
- border-radius: 9px;
649
+ border-radius: 6px;
660
650
  background: light-dark(#fff0f0, #351d21);
661
651
  color: light-dark(#d2454f, #ff838b);
662
652
  font-size: 12px;
@@ -665,22 +655,22 @@ window.__ModuleLoader__.load({
665
655
  .dcAgentChips { display: flex; flex-wrap: wrap; gap: 6px; }
666
656
  .dcAgentChip {
667
657
  padding: 4px 10px;
668
- border: 1px solid light-dark(#e4e8f0, #303947);
658
+ border: 1px solid var(--dc-border);
669
659
  border-radius: 999px;
670
- font-size: 11px;
671
- color: light-dark(#697386, #aab5c7);
660
+ font-size: 12px;
661
+ color: var(--dc-muted);
672
662
  }
673
663
  .dcAgentChip.is-selected {
674
- color: light-dark(#1556cf, #8cb3ff);
675
- border-color: light-dark(#2869e6, #6d9eff);
676
- background: light-dark(#edf4ff, #172841);
664
+ color: var(--dc-action);
665
+ border-color: var(--dc-action);
666
+ background: var(--dc-selected);
677
667
  }
678
668
  .dcAgentCheck { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; }
679
669
  .dcAgentSection {
680
670
  padding: 14px;
681
- border: 1px solid light-dark(#e4e8f0, #303947);
682
- border-radius: 11px;
683
- background: light-dark(#fbfcfe, #191f28);
671
+ border: 1px solid var(--dc-border);
672
+ border-radius: 8px;
673
+ background: var(--dc-page);
684
674
  }
685
675
  .dcAgentSection h3 { margin: 0 0 8px; font-size: 13px; }
686
676
  .dcAgentCandidate {
@@ -689,32 +679,32 @@ window.__ModuleLoader__.load({
689
679
  gap: 10px;
690
680
  align-items: center;
691
681
  padding: 10px 0;
692
- border-bottom: 1px solid light-dark(#eef1f6, #242b36);
682
+ border-bottom: 1px solid var(--dc-border);
693
683
  }
694
684
  .dcAgentCandidate:last-child { border-bottom: 0; }
695
- .dcAgentCandidate small { color: light-dark(#697386, #aab5c7); }
685
+ .dcAgentCandidate small { color: var(--dc-muted); }
696
686
  .dcAgentProgress { height: 8px; overflow: hidden; border-radius: 99px; background: light-dark(#e8edf5, #293240); }
697
- .dcAgentProgress > span { display: block; height: 100%; background: #2869e6; }
687
+ .dcAgentProgress > span { display: block; height: 100%; background: var(--dc-action); }
698
688
 
699
689
  /* M3 · overlay 头部 jobs 状态 pill(轮询 /mvp/jobs,不接计费遥测)。 */
700
690
  .dcAgentJobsPill {
701
691
  flex: 0 0 auto;
702
692
  padding: 4px 10px;
703
- border: 1px solid light-dark(#e4e8f0, #303947);
693
+ border: 1px solid var(--dc-border);
704
694
  border-radius: 999px;
705
- font-size: 11px;
695
+ font-size: 12px;
706
696
  white-space: nowrap;
707
- color: light-dark(#697386, #aab5c7);
697
+ color: var(--dc-muted);
708
698
  }
709
699
  .dcAgentJobsPill[data-state='running'] {
710
- color: light-dark(#1556cf, #8cb3ff);
711
- border-color: light-dark(#2869e6, #6d9eff);
712
- background: light-dark(#edf4ff, #172841);
700
+ color: var(--dc-action);
701
+ border-color: var(--dc-action);
702
+ background: var(--dc-selected);
713
703
  }
714
704
  .dcAgentJobsPill[data-state='completed'] {
715
- color: light-dark(#118a5b, #56d39b);
716
- border-color: light-dark(#118a5b, #2f7d5e);
717
- background: light-dark(#eefaf3, #12261d);
705
+ color: var(--dc-success);
706
+ border-color: var(--dc-success);
707
+ background: var(--dc-success-bg);
718
708
  }
719
709
  .dcAgentJobsPill[data-state='failed'] {
720
710
  color: light-dark(#d2454f, #ff838b);
@@ -728,9 +718,9 @@ window.__ModuleLoader__.load({
728
718
  flex-direction: column;
729
719
  gap: 8px;
730
720
  padding: 12px 14px;
731
- border: 1px solid light-dark(#e4e8f0, #303947);
732
- border-radius: 11px;
733
- background: light-dark(#fbfcfe, #191f28);
721
+ border: 1px solid var(--dc-border);
722
+ border-radius: 8px;
723
+ background: var(--dc-page);
734
724
  margin: 4px 0;
735
725
  }
736
726
  .dcAgentToolCardHead {
@@ -750,45 +740,34 @@ window.__ModuleLoader__.load({
750
740
  flex: 0 0 auto;
751
741
  padding: 1px 8px;
752
742
  border-radius: 999px;
753
- font-size: 11px;
754
- color: light-dark(#697386, #aab5c7);
755
- border: 1px solid light-dark(#e4e8f0, #303947);
743
+ font-size: 12px;
744
+ color: var(--dc-muted);
745
+ border: 1px solid var(--dc-border);
756
746
  }
757
- .dcAgentToolCardState.is-ok { color: light-dark(#118a5b, #56d39b); }
747
+ .dcAgentToolCardState.is-ok { color: var(--dc-success); }
758
748
  .dcAgentToolCardState.is-error { color: light-dark(#d2454f, #ff838b); }
759
- .dcAgentToolCardState.is-running { color: light-dark(#1556cf, #8cb3ff); }
760
- .dcAgentToolCardState.is-stopped { color: light-dark(#697386, #aab5c7); }
749
+ .dcAgentToolCardState.is-running { color: var(--dc-action); }
750
+ .dcAgentToolCardState.is-stopped { color: var(--dc-muted); }
761
751
  .dcAgentToolCardBody {
762
752
  margin: 0;
763
753
  white-space: pre-wrap;
764
754
  word-break: break-word;
765
755
  font-size: 12px;
766
756
  line-height: 1.6;
767
- color: light-dark(#33415a, #c9d4e5);
768
- }
769
- .dcAgentHomeHero { display: flex; align-items: center; justify-content: space-between; gap: 18px; }
770
- .dcAgentHomeHero p { margin: 5px 0 0; color: light-dark(#697386, #aab5c7); font-size: 12px; line-height: 18px; }
771
- .dcAgentHomeEyebrow { display: block; margin-bottom: 4px; color: light-dark(#2869e6, #8cb3ff); font-size: 11px; font-weight: 700; letter-spacing: .08em; }
772
- .dcAgentHomeActions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
773
- .dcAgentHomeActions button,
774
- .dcAgentHomeRecent button,
775
- .dcAgentHistoryTask { border: 1px solid light-dark(#dce4f1, #344052); border-radius: 9px; background: light-dark(#fff, #1b222e); color: inherit; font: inherit; cursor: pointer; }
776
- .dcAgentHomeActions button { padding: 6px 9px; font-size: 11px; }
777
- .dcAgentHomeRecent { display: grid; gap: 6px; margin-top: 12px; }
778
- .dcAgentHomeRecent > b { font-size: 12px; }
779
- .dcAgentHomeRecent button { display: flex; justify-content: space-between; gap: 12px; padding: 7px 9px; text-align: left; font-size: 11px; }
780
- .dcAgentHomeRecent small { color: light-dark(#697386, #aab5c7); }
757
+ color: var(--dc-text);
758
+ }
759
+ .dcAgentHistoryTask { border: 1px solid var(--dc-border); border-radius: 6px; background: var(--dc-surface); color: inherit; font: inherit; cursor: pointer; }
781
760
  .dcAgentWizardNav { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-bottom: 12px; }
782
- .dcAgentWizardStep { display: flex; align-items: center; gap: 6px; padding: 7px; border: 1px solid light-dark(#d9dee8, #394352); border-radius: 9px; background: transparent; color: inherit; font: inherit; font-size: 11px; cursor: pointer; }
783
- .dcAgentWizardStep b { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: light-dark(#eef1f6, #252e3b); color: light-dark(#607088, #b9c6da); }
784
- .dcAgentWizardStep.is-active { border-color: #2869e6; background: light-dark(#edf4ff, #172841); color: light-dark(#1556cf, #8cb3ff); }
785
- .dcAgentWizardStep.is-active b { background: #2869e6; color: white; }
761
+ .dcAgentWizardStep { display: flex; align-items: center; gap: 6px; padding: 7px; border: 1px solid var(--dc-border); border-radius: 6px; background: transparent; color: inherit; font: inherit; font-size: 12px; cursor: pointer; }
762
+ .dcAgentWizardStep b { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: var(--dc-border); color: var(--dc-muted); }
763
+ .dcAgentWizardStep.is-active { border-color: var(--dc-action); background: var(--dc-selected); color: var(--dc-action); }
764
+ .dcAgentWizardStep.is-active b { background: var(--dc-action); color: var(--dc-on-action); }
786
765
  .dcAgentWizardPane { min-height: 230px; }
787
766
  .dcAgentWizardPane h4 { margin: 0 0 3px; font-size: 14px; }
788
- .dcAgentWizardPane > p { margin: 0 0 12px; color: light-dark(#697386, #aab5c7); font-size: 11px; line-height: 17px; }
767
+ .dcAgentWizardPane > p { margin: 0 0 12px; color: var(--dc-muted); font-size: 12px; line-height: 17px; }
789
768
  .dcAgentPromptRules { display: grid; gap: 8px; margin-top: 14px; }
790
769
  .dcAgentPromptRules label { font-size: 12px; }
791
- .dcAgentPromptPreview { max-height: 260px; overflow: auto; margin: 10px 0 0; padding: 12px; border-radius: 10px; background: light-dark(#f6f8fb, #11171f); white-space: pre-wrap; word-break: break-word; font: inherit; font-size: 11px; line-height: 18px; }
770
+ .dcAgentPromptPreview { max-height: 260px; overflow: auto; margin: 10px 0 0; padding: 12px; border-radius: 8px; background: var(--dc-page); white-space: pre-wrap; word-break: break-word; font: inherit; font-size: 12px; line-height: 18px; }
792
771
  .dcAgentFormField { display: grid; gap: 6px; font-size: 12px; font-weight: 600; }
793
772
  .dcAgentMappingRow { display: grid; grid-template-columns: minmax(0, 1fr) 24px minmax(180px, 1fr); align-items: center; gap: 8px; margin-top: 7px; font-size: 12px; }
794
773
  .dcAgentMappingRow > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -804,13 +783,13 @@ window.__ModuleLoader__.load({
804
783
  border: 0;
805
784
  border-radius: 6px;
806
785
  background: transparent;
807
- color: light-dark(#2869e6, #8cb3ff);
786
+ color: var(--dc-action);
808
787
  font: inherit;
809
- font-size: 11px;
788
+ font-size: 12px;
810
789
  cursor: pointer;
811
790
  }
812
- .dcAgentFieldAction:hover, .dcAgentFieldAction:focus-visible { background: light-dark(#edf4ff, #172841); }
813
- .dcAgentPreviewTable { margin-top: 12px; overflow: auto; border: 1px solid light-dark(#e4e8f0, #303947); border-radius: 10px; }
791
+ .dcAgentFieldAction:hover, .dcAgentFieldAction:focus-visible { background: var(--dc-selected); }
792
+ .dcAgentPreviewTable { margin-top: 12px; overflow: auto; border: 1px solid var(--dc-border); border-radius: 8px; }
814
793
  .dcAgentHistoryTask { display: block; width: 100%; padding: 10px; text-align: left; }
815
794
  .dcAgentHistoryTask h3 { margin: 0; font-size: 12px; }
816
795
  /*
@@ -830,6 +809,12 @@ window.__ModuleLoader__.load({
830
809
  padding-right: min(420px, 48vw);
831
810
  }
832
811
  }
812
+ @media (min-width: 761px) {
813
+ body:has(.dcAgentWorkbench.is-expanded) [data-conversation-scroll] {
814
+ box-sizing: border-box;
815
+ padding-right: min(980px, calc(100vw - 420px));
816
+ }
817
+ }
833
818
  @media (max-width: 760px) {
834
819
  .dcAgentWorkbench, .dcAgentWorkbench.is-expanded { width: 100vw; max-width: none; min-width: 0; border-radius: 0; }
835
820
  .dcAgentOverlay { background: rgba(8, 10, 14, 0.22); pointer-events: auto; }
@@ -838,9 +823,8 @@ window.__ModuleLoader__.load({
838
823
  .dcAgentCandidate { grid-template-columns: 1fr; }
839
824
  .dcAgentCapabilities { justify-content: flex-start; padding-inline: 12px; }
840
825
  .dcAgentCapability { min-width: 92px; }
841
- .dcAgentPromptPanel { left: 8px; width: calc(100vw - 88px); max-height: 72vh; }
842
- .dcAgentHomeFlow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
843
- .dcAgentHomeHero { align-items: flex-start; flex-direction: column; }
826
+ .dcAgentPromptBackdrop { padding: 0; }
827
+ .dcAgentPromptPanel { width: 100%; height: 100dvh; max-height: 100dvh; border-radius: 0; }
844
828
  .dcAgentWizardNav { grid-template-columns: repeat(2, 1fr); }
845
829
  .dcAgentRulesGrid { grid-template-columns: 1fr; }
846
830
  .dcAgentMappingRow { grid-template-columns: 1fr; }
@@ -850,6 +834,38 @@ window.__ModuleLoader__.load({
850
834
  .dcAgentWorkbench { width: 420px; max-width: 48vw; min-width: 360px; }
851
835
  .dcAgentQccBadge, .dcAgentJobsPill { display: none; }
852
836
  }
837
+ /* Distinct levels: management tabs → compact task steps → working content. */
838
+ .dcAgentWorkbench, .dcAgentPromptPanel { font-size: 14px; line-height: 1.5; }
839
+ .dcAgentWbHeader, .dcAgentManagement, .dcAgentStepper { flex: none; }
840
+ .dcAgentManagement { display: flex; gap: 24px; padding: 0 18px; border-bottom: 1px solid var(--dc-border); }
841
+ .dcAgentManagement .dcAgentButton { border: 0; border-bottom: 3px solid transparent; border-radius: 0; padding: 10px 0; background: transparent; }
842
+ .dcAgentManagement .dcAgentButton[aria-pressed="true"] { border-bottom-color: var(--dc-action); color: var(--dc-action); font-weight: 600; }
843
+ .dcAgentStepper { display: flex; overflow-x: auto; gap: 4px; padding: 10px 12px; }
844
+ .dcAgentStep { flex: 0 0 auto; border-color: transparent; padding: 7px 8px; }
845
+ .dcAgentStep.is-active { border-color: transparent; }
846
+ .dcAgentCapability { border-radius: 8px; }
847
+ .dcAgentWbBody { min-height: 0; }
848
+ .dcAgentTable th { background: var(--dc-table-head); color: var(--dc-text); }
849
+ .dcAgentTable th, .dcAgentTable td { height: 44px; box-sizing: border-box; font-size: 13px; }
850
+ .dcAgentTable tbody tr:hover { background: var(--dc-selected); }
851
+ .dcAgentSection, .dcAgentCard { background: var(--dc-surface); }
852
+ .dcAgentFieldGroup { background: var(--dc-page); padding: 12px; border-radius: 8px; }
853
+ .dcAgentPromptFieldGrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; margin-top: 10px; }
854
+ .dcAgentPromptFieldGrid .dcAgentPromptChoice { border: 0; border-radius: 4px; min-width: 0; align-items: flex-start; font-size: 13px; }
855
+ .dcAgentFieldGroup .dcAgentChips { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
856
+ .dcAgentFieldGroup .dcAgentChip { border-radius: 4px; }
857
+ .dcAgentPromptText, .dcAgentTextarea, .dcAgentField { font-size: 14px; }
858
+ .dcAgentPromptTrigger { border-radius: 6px; }
859
+ .dcAgentPromptAction.is-primary:hover:not(:disabled) { background: var(--dc-hover); }
860
+ :is(.dcAgentWorkbench, .dcAgentPromptPanel, .dcAgentCapabilities, .dcAgentPromptLayer) :is(button, input, select, textarea, summary):focus-visible,
861
+ .dcAgentLauncher:focus-visible { outline: 2px solid var(--dc-action); outline-offset: 2px; }
862
+ @media (max-width: 760px) {
863
+ [data-dc-agent-hero-title="true"] { font-size: 20px; }
864
+ .dcAgentHeroLogo { width: 40px; height: 40px; border-radius: 8px; }
865
+ .dcAgentPromptText, .dcAgentTextarea, .dcAgentField { font-size: 16px; }
866
+ .dcAgentPromptFieldGrid { grid-template-columns: 1fr; }
867
+ }
868
+
853
869
  `;
854
870
 
855
871
  /** 安装入口、会话能力按钮与右侧工作台样式。 */
@@ -897,18 +913,18 @@ window.__ModuleLoader__.load({
897
913
  }
898
914
 
899
915
  const STEPS = [
900
- { key: 'upload', label: '上传数据', icon: '📄' },
901
- { key: 'rules', label: '规则确认', icon: '' },
902
- { key: 'match', label: '数据匹配', icon: '🔎' },
903
- { key: 'enrich', label: '清洗补全', icon: '' },
904
- { key: 'download', label: '下载数据', icon: '⬇️' },
916
+ { key: 'upload', label: '导入与核验', icon: '1' },
917
+ { key: 'rules', label: '规则与体检', icon: '2' },
918
+ { key: 'match', label: '主体匹配', icon: '3' },
919
+ { key: 'enrich', label: '字段补全', icon: '4' },
920
+ { key: 'download', label: '结果下载', icon: '5' },
905
921
  ];
906
922
 
907
923
  const CAPABILITIES = [
908
- { key: 'upload', label: '上传清洗', icon: IconPaperclipOutline16, fallback: '+' },
924
+ { key: 'upload', label: '导入名单', icon: IconPaperclipOutline16, fallback: '+' },
909
925
  { key: 'profile', label: '质量体检', icon: IconChecklistOutline14, fallback: '✓' },
910
926
  { key: 'match', label: '匹配核验', icon: IconSearchOutline16, fallback: '⌕' },
911
- { key: 'enrich', label: '字段补全', icon: IconDataOutline16, fallback: '▦' },
927
+ { key: 'enrich', label: '字段补全', icon: DatabaseLogo, fallback: '▦' },
912
928
  { key: 'history', label: '任务历史', icon: IconArchiveOutline20, fallback: '◷' },
913
929
  ];
914
930
 
@@ -1792,7 +1808,7 @@ window.__ModuleLoader__.load({
1792
1808
  console.error('[dc-agent] open failed:', error);
1793
1809
  }
1794
1810
  },
1795
- children: wide ? '🧹 数据清洗补全' : '🧹',
1811
+ children: h('span', { className: 'dcAgentLauncherContent' }, h(DatabaseLogo), wide ? h('span', null, '数据清洗补全') : null),
1796
1812
  });
1797
1813
  if (!topMount || typeof reactDom.createPortal !== 'function') return launcher;
1798
1814
  return reactDom.createPortal(h('div', {
@@ -1801,7 +1817,7 @@ window.__ModuleLoader__.load({
1801
1817
  }, launcher), topMount);
1802
1818
  }
1803
1819
 
1804
- /** Mockup 五能力入口:由 input.dock 承载,并在 CSS 中排到原生 composer 下方。 */
1820
+ /** 快捷菜单只切换同一工作台视图,由自有 Portal 挂载在原生 composer 下方。 */
1805
1821
  function CapabilityBar(props) {
1806
1822
  const { sessionId } = props;
1807
1823
  return h('div', { className: 'dcAgentCapabilities', 'aria-label': '数据清洗补全智能体能力' },
@@ -1826,66 +1842,109 @@ window.__ModuleLoader__.load({
1826
1842
  authorization_required: '待连接企查查', cancelled: '已取消', parse_failed: '解析失败',
1827
1843
  };
1828
1844
 
1829
- function ProductHome(props = {}) {
1830
- const { sessionId } = props;
1831
- const [recentTasks, setRecentTasks] = react.useState([]);
1832
- const flow = [
1833
- ['01', '任务设置', '提示词向导明确目标'],
1834
- ['02', '上传数据', '文本、Excel、JSON 或图片'],
1835
- ['03', '规则确认', '字段映射与匹配主键'],
1836
- ['04', '质量体检', '缺失、重复与格式诊断'],
1837
- ['05', '数据匹配', '精确优先,多候选复核'],
1838
- ['06', '清洗补全', '按需选择当前企业字段'],
1839
- ['07', '下载数据', '保留原值、依据与状态'],
1840
- ];
1845
+ function ProductHome() {
1846
+ return h('p', { className: 'dcAgentHomeSummary' },
1847
+ '导入企业名单或图片,核验主体、补全字段,并导出可追溯结果。');
1848
+ }
1849
+
1850
+ function workflowNavigationIssue(step, task, hasData, profile, qccRun) {
1851
+ if (['upload', 'history'].includes(step)) return null;
1852
+ if (step === 'download' && task?.artifacts?.length) return null;
1853
+ if (!hasData) return '请先在「导入与核验」载入并核对完整名单。';
1854
+ if (step === 'rules') return null;
1855
+ if (!task || ['draft', 'uploaded'].includes(task.state)) return '请先在「规则与体检」确认字段映射和处理规则。';
1856
+ if (step === 'profile') return null;
1857
+ if (!profile && task.state === 'rules_confirmed') return '请先生成质量体检报告,再推进主体匹配。';
1858
+ const requiresQcc = Array.isArray(task.objectives)
1859
+ ? task.objectives.some((key) => ['validate_identity', 'complete_fields'].includes(key))
1860
+ : Boolean(task.fieldSelection?.length);
1861
+ if (step === 'enrich' && requiresQcc && !['matched', 'enriching', 'export_ready', 'completed', 'partial'].includes(task.state)) {
1862
+ return '请先在「主体匹配」确认企业;多候选需要人工核验。';
1863
+ }
1864
+ if (step === 'download' && !['export_ready', 'completed', 'partial'].includes(task.state) && !['completed', 'partial'].includes(qccRun?.state)) {
1865
+ return '请先完成清洗或字段补全。原始清单可在「导入与核验」下载。';
1866
+ }
1867
+ return null;
1868
+ }
1869
+
1870
+ // 只新增自己的 Portal 容器,不移动 DSH/其他插件拥有的 DOM。
1871
+ function installCapabilityMount(marker, onMount) {
1872
+ const owned = new Set();
1873
+ const sync = () => {
1874
+ const seat = marker?.closest?.('[data-composer-seat]');
1875
+ const card = seat?.querySelector?.('[data-composer-card]');
1876
+ if (!card) { onMount(null); return; }
1877
+ let branch = card;
1878
+ while (branch.parentElement && branch.parentElement !== seat && !branch.parentElement.contains(marker)) {
1879
+ branch = branch.parentElement;
1880
+ }
1881
+ const parent = branch.parentElement;
1882
+ if (!parent?.contains(marker) || branch.contains(marker)) { onMount(null); return; }
1883
+ let mount = [...owned].find((node) => node.parentElement === parent);
1884
+ if (!mount) {
1885
+ for (const node of owned) node.remove();
1886
+ owned.clear();
1887
+ mount = document.createElement('div');
1888
+ mount.className = 'dcAgentCapabilityMount';
1889
+ owned.add(mount);
1890
+ }
1891
+ if (branch.nextSibling !== mount) parent.insertBefore(mount, branch.nextSibling);
1892
+ onMount(mount);
1893
+ };
1894
+ sync();
1895
+ const observer = typeof MutationObserver === 'function' ? new MutationObserver(sync) : null;
1896
+ observer?.observe(marker.closest('[data-composer-seat]') || marker, { childList: true, subtree: true });
1897
+ return () => { observer?.disconnect(); for (const node of owned) node.remove(); };
1898
+ }
1899
+
1900
+ function PromptDialog({ sessionId, onClose, children }) {
1841
1901
  react.useEffect(() => {
1842
- let disposed = false;
1843
- requestJson('/data-cleaning/api/workflow/tasks').then((response) => {
1844
- if (!disposed) setRecentTasks((response.tasks || []).slice(0, 3));
1845
- }).catch(() => {});
1846
- return () => { disposed = true; };
1902
+ const panel = [...(document.querySelectorAll?.('.dcAgentPromptPanel') || [])]
1903
+ .find((node) => node.dataset.sessionId === sessionId);
1904
+ if (!panel) return undefined;
1905
+ const previous = document.activeElement;
1906
+ const focusable = () => [...panel.querySelectorAll('button:not(:disabled), input:not(:disabled), textarea:not(:disabled), select:not(:disabled), [tabindex="0"]')]
1907
+ .filter((node) => node.getClientRects().length);
1908
+ (focusable()[0] || panel).focus();
1909
+ const keydown = (event) => {
1910
+ if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); onClose(); }
1911
+ if (event.key !== 'Tab') return;
1912
+ const nodes = focusable();
1913
+ const first = nodes[0] || panel, last = nodes[nodes.length - 1] || panel;
1914
+ if (event.shiftKey && (document.activeElement === first || document.activeElement === panel)) {
1915
+ event.preventDefault(); last.focus();
1916
+ } else if (!event.shiftKey && (document.activeElement === last || !panel.contains(document.activeElement))) {
1917
+ event.preventDefault(); first.focus();
1918
+ }
1919
+ };
1920
+ panel.addEventListener('keydown', keydown);
1921
+ return () => {
1922
+ panel.removeEventListener('keydown', keydown);
1923
+ if (panel.contains(document.activeElement) && previous?.isConnected) previous.focus();
1924
+ };
1847
1925
  }, [sessionId]);
1848
- return h('section', { className: 'dcAgentProductHome', 'aria-label': '数据清洗补全产品介绍' },
1849
- h('div', { className: 'dcAgentHomeHero' },
1850
- h('div', null,
1851
- h('span', { className: 'dcAgentHomeEyebrow' }, '企业主数据治理工作台'),
1852
- h('h2', null, '把企业名单变成可核验、可回写的标准数据'),
1853
- h('p', null, '面向销售线索、客户尽调、供应商管理与 CRM / ERP 数据治理,先确认任务和规则,再按需使用当前用户连接的企查查 MCP。'),
1854
- ),
1855
- h('button', { type: 'button', className: 'dcAgentButton is-primary', onClick: () => requestWorkbenchOpen('upload', sessionId) }, '开始新任务'),
1856
- ),
1857
- h('div', { className: 'dcAgentHomeFlow', 'aria-label': '数据清洗补全工作流' },
1858
- flow.map(([index, title, hint]) => h('div', { className: 'dcAgentHomeStep', key: index },
1859
- h('b', null, index),
1860
- h('span', null, title),
1861
- h('small', { style: { display: 'block', opacity: .72 } }, hint),
1862
- )),
1863
- ),
1864
- h('div', { className: 'dcAgentHomeTrust' },
1865
- h('span', null, '本地解析与确定性清洗'),
1866
- h('span', null, '匹配候选人工确认'),
1867
- h('span', null, '客户自带企查查连接与额度'),
1868
- h('span', null, '结果与待复核清单可导出'),
1869
- ),
1870
- h('div', { className: 'dcAgentHomeActions' },
1871
- h('button', { type: 'button', onClick: () => requestWorkbenchOpen('profile', sessionId) }, '🩺 查看质量体检'),
1872
- h('button', { type: 'button', onClick: () => requestWorkbenchOpen('match', sessionId) }, '🔎 进入匹配核验'),
1873
- h('button', { type: 'button', onClick: () => requestWorkbenchOpen('history', sessionId) }, '◷ 查看任务历史'),
1874
- ),
1875
- recentTasks.length ? h('div', { className: 'dcAgentHomeRecent', 'aria-label': '最近任务' },
1876
- h('b', null, '最近任务'),
1877
- recentTasks.map((task) => h('button', {
1878
- key: task.id,
1879
- type: 'button',
1880
- onClick: () => requestWorkbenchOpen(task.stage || 'upload', sessionId, task),
1881
- },
1882
- h('span', null, task.title || '未命名任务'),
1883
- h('small', null, WORKFLOW_STATE_LABELS[task.state] || task.state),
1884
- )),
1885
- ) : null,
1886
- );
1926
+ const dialog = h('div', { className: 'dcAgentPromptBackdrop' },
1927
+ h('section', { className: 'dcAgentPromptPanel', role: 'dialog', 'aria-modal': 'true',
1928
+ 'aria-label': '数据清洗补全任务生成器', 'data-session-id': sessionId, tabIndex: -1 }, children));
1929
+ return document.body && typeof reactDom.createPortal === 'function'
1930
+ ? reactDom.createPortal(dialog, document.body) : dialog;
1887
1931
  }
1888
1932
 
1933
+ function ImagePreview({ src, alt, onClose, sessionId }) {
1934
+ react.useEffect(() => () => {
1935
+ const panel = [...(document.querySelectorAll?.('.dcAgentPromptPanel') || [])]
1936
+ .find((node) => node.dataset.sessionId === sessionId);
1937
+ panel?.querySelector('.dcAgentPromptImageThumb')?.focus();
1938
+ }, [sessionId]);
1939
+ const view = h('button', { type: 'button', className: 'dcAgentImageLightbox',
1940
+ 'aria-label': '关闭图片预览', onClick: onClose, autoFocus: true,
1941
+ onKeyDown: (event) => {
1942
+ if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); onClose(); }
1943
+ if (event.key === 'Tab') event.preventDefault();
1944
+ },
1945
+ }, h('img', { src, alt }));
1946
+ return document.body && typeof reactDom.createPortal === 'function' ? reactDom.createPortal(view, document.body) : view;
1947
+ }
1889
1948
  /**
1890
1949
  * DSH 当前只公开 hero brand.mark,没有 headline slot。这里仅在本插件会话且 blank hero
1891
1950
  * 阶段替换标题,并在卸载时恢复,避免污染普通会话。
@@ -1903,6 +1962,9 @@ window.__ModuleLoader__.load({
1903
1962
  if (!hero) return () => {};
1904
1963
  const changedTitles = new Map();
1905
1964
  const changedBadges = new Map();
1965
+ const changedMarks = new Map();
1966
+ const changedRows = new Map();
1967
+ const ownedLogos = new Map();
1906
1968
  const hiddenForeignDocks = new Map();
1907
1969
  const composerStack = marker?.parentElement?.parentElement;
1908
1970
  // 单一会话所有权由入口的 enabled 参数(useCleaningSession(sessionId) && composerPhase==='blank')
@@ -1924,6 +1986,29 @@ window.__ModuleLoader__.load({
1924
1986
  if (!changedTitles.has(title)) changedTitles.set(title, title.textContent ?? '');
1925
1987
  title.dataset.dcAgentHeroTitle = 'true';
1926
1988
  if (title.textContent !== '数据清洗补全智能体') { title.textContent = '数据清洗补全智能体'; mutated = true; }
1989
+ // 只适配本会话已确认的 DSH headline;未知宿主结构保留原状。
1990
+ const row = title.parentElement;
1991
+ const nativeMark = row?.querySelector?.('[class*="fishHitbox"]');
1992
+ if (nativeMark && typeof document.createElementNS === 'function') {
1993
+ if (!changedRows.has(row)) changedRows.set(row, row.getAttribute('data-dc-agent-hero-row'));
1994
+ row.setAttribute('data-dc-agent-hero-row', 'true');
1995
+ if (!changedMarks.has(nativeMark)) changedMarks.set(nativeMark, nativeMark.style.display);
1996
+ nativeMark.style.display = 'none';
1997
+ if (!ownedLogos.get(row)?.isConnected) {
1998
+ const logo = document.createElement('span');
1999
+ logo.className = 'dcAgentHeroLogo';
2000
+ logo.setAttribute('aria-hidden', 'true');
2001
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
2002
+ for (const [name, value] of Object.entries({ viewBox: '0 0 24 24', width: '26', height: '26', fill: 'none', stroke: 'currentColor', 'stroke-width': '1.7', 'stroke-linecap': 'round', 'stroke-linejoin': 'round', focusable: 'false' })) svg.setAttribute(name, value);
2003
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
2004
+ path.setAttribute('d', DATABASE_PATH);
2005
+ svg.appendChild(path);
2006
+ logo.appendChild(svg);
2007
+ row.insertBefore(logo, title);
2008
+ ownedLogos.set(row, logo);
2009
+ mutated = true;
2010
+ }
2011
+ }
1927
2012
  }
1928
2013
  if (badge) {
1929
2014
  if (!changedBadges.has(badge)) changedBadges.set(badge, badge.style?.display ?? '');
@@ -1961,6 +2046,12 @@ window.__ModuleLoader__.load({
1961
2046
  observer?.observe?.(hero, { childList: true, subtree: true });
1962
2047
  return () => {
1963
2048
  observer?.disconnect?.();
2049
+ for (const logo of ownedLogos.values()) logo.remove();
2050
+ for (const [mark, originalDisplay] of changedMarks) mark.style.display = originalDisplay;
2051
+ for (const [row, originalValue] of changedRows) {
2052
+ if (originalValue === null) row.removeAttribute('data-dc-agent-hero-row');
2053
+ else row.setAttribute('data-dc-agent-hero-row', originalValue);
2054
+ }
1964
2055
  for (const [title, originalText] of changedTitles) {
1965
2056
  if (title.textContent === '数据清洗补全智能体') title.textContent = originalText;
1966
2057
  delete title.dataset.dcAgentHeroTitle;
@@ -1979,6 +2070,13 @@ window.__ModuleLoader__.load({
1979
2070
  const { sessionId, session: ownerSession } = props;
1980
2071
  const enabled = useCleaningSession(sessionId);
1981
2072
  const hero = ownerSession?.composerPhase === 'blank';
2073
+ const [menuMount, setMenuMount] = react.useState(null);
2074
+ react.useEffect(() => {
2075
+ if (!enabled) return undefined;
2076
+ const marker = [...document.querySelectorAll('.dcAgentExperience')]
2077
+ .find((node) => node.dataset.sessionId === sessionId);
2078
+ return marker ? installCapabilityMount(marker, (mount) => setMenuMount((current) => current === mount ? current : mount)) : undefined;
2079
+ }, [enabled, sessionId, hero]);
1982
2080
  react.useEffect(
1983
2081
  () => rewriteHeroChrome(sessionId, enabled && hero),
1984
2082
  [sessionId, enabled, hero, ownerSession?.openState]
@@ -1988,7 +2086,7 @@ window.__ModuleLoader__.load({
1988
2086
  className: `dcAgentExperience${hero ? ' is-home' : ''}`,
1989
2087
  'data-session-id': sessionId,
1990
2088
  },
1991
- h(CapabilityBar, { sessionId }),
2089
+ menuMount ? reactDom.createPortal(h(CapabilityBar, { sessionId }), menuMount) : h(CapabilityBar, { sessionId }),
1992
2090
  hero ? h(ProductHome, { sessionId }) : null,
1993
2091
  );
1994
2092
  }
@@ -2071,6 +2169,7 @@ window.__ModuleLoader__.load({
2071
2169
  const [imageLightbox, setImageLightbox] = react.useState(false);
2072
2170
  const [cleaningKeys, setCleaningKeys] = react.useState(DEFAULT_CLEANING_KEYS);
2073
2171
  const [enrichmentKeys, setEnrichmentKeys] = react.useState(DEFAULT_ENRICHMENT_KEYS);
2172
+ const [fieldQuery, setFieldQuery] = react.useState('');
2074
2173
  const [anchorKeys, setAnchorKeys] = react.useState(['company_name', 'credit_no']);
2075
2174
  const [matchRules, setPromptMatchRules] = react.useState({
2076
2175
  normalizeNames: true,
@@ -2276,6 +2375,12 @@ window.__ModuleLoader__.load({
2276
2375
  }, sessionId);
2277
2376
  setError(null);
2278
2377
  setOpen(false);
2378
+ setTimeout(() => {
2379
+ if (typeof document === 'undefined' || !isCleaningSession(sessionId)) return;
2380
+ const marker = [...(document.querySelectorAll?.('.dcAgentExperience') || [])]
2381
+ .find((node) => node.dataset.sessionId === sessionId);
2382
+ marker?.closest?.('[data-composer-seat]')?.querySelector?.('textarea, [contenteditable="true"], [role="textbox"]')?.focus();
2383
+ }, 0);
2279
2384
  setWizardStep(1);
2280
2385
  };
2281
2386
 
@@ -2332,6 +2437,16 @@ window.__ModuleLoader__.load({
2332
2437
  // 右侧工作台共用此图片入口;仅由当前会话确认接收,不把图片交给表格解析器。
2333
2438
  react.useEffect(() => {
2334
2439
  if (!enabled) return undefined;
2440
+ const receiveNewTask = (event) => {
2441
+ if (event.detail?.sessionId !== sessionId || busy || imageCommand?.state === 'running') return;
2442
+ event.preventDefault();
2443
+ discardCurrentImage();
2444
+ setMode('text'); setRawText(''); setEntries([]); setEntryCount(0); setSpreadsheetFileName('');
2445
+ setCleaningKeys(DEFAULT_CLEANING_KEYS); setEnrichmentKeys(DEFAULT_ENRICHMENT_KEYS);
2446
+ setAnchorKeys(['company_name', 'credit_no']);
2447
+ setPromptMatchRules({ normalizeNames: true, preferCreditNo: true, deduplicate: true, manualReviewAmbiguous: true });
2448
+ setWizardStep(1); setOpen(true); setError(null);
2449
+ };
2335
2450
  const receiveImage = (event) => {
2336
2451
  if (event.detail?.sessionId !== sessionId || busy || imageCommand?.state === 'running') return;
2337
2452
  event.preventDefault();
@@ -2342,7 +2457,11 @@ window.__ModuleLoader__.load({
2342
2457
  if (event.detail.file) acceptImageFiles([event.detail.file]);
2343
2458
  };
2344
2459
  document.addEventListener('dsh:data-cleaning-prompt-image', receiveImage);
2345
- return () => document.removeEventListener('dsh:data-cleaning-prompt-image', receiveImage);
2460
+ document.addEventListener('dsh:data-cleaning-prompt-new', receiveNewTask);
2461
+ return () => {
2462
+ document.removeEventListener('dsh:data-cleaning-prompt-image', receiveImage);
2463
+ document.removeEventListener('dsh:data-cleaning-prompt-new', receiveNewTask);
2464
+ };
2346
2465
  }, [enabled, sessionId, busy, imageCommand, imageAttachment]);
2347
2466
 
2348
2467
  if (!enabled) return null;
@@ -2376,18 +2495,7 @@ window.__ModuleLoader__.load({
2376
2495
  'aria-expanded': open,
2377
2496
  onClick: () => setOpen(!open),
2378
2497
  }, '✨ 提示词生成'),
2379
- open ? h('section', {
2380
- className: 'dcAgentPromptPanel',
2381
- role: 'dialog',
2382
- 'aria-modal': 'false',
2383
- 'aria-label': '数据清洗补全任务生成器',
2384
- onKeyDown: (event) => {
2385
- if (event.key === 'Escape') {
2386
- event.preventDefault();
2387
- setOpen(false);
2388
- }
2389
- },
2390
- },
2498
+ open ? h(PromptDialog, { sessionId, onClose: () => setOpen(false) },
2391
2499
  h('div', { className: 'dcAgentPromptHead' },
2392
2500
  h('div', null,
2393
2501
  h('h3', null, '生成数据清洗补全任务'),
@@ -2395,6 +2503,7 @@ window.__ModuleLoader__.load({
2395
2503
  ),
2396
2504
  h('button', { type: 'button', className: 'dcAgentPromptClose', 'aria-label': '关闭提示词生成', onClick: () => setOpen(false) }, '✕'),
2397
2505
  ),
2506
+ h('div', { className: 'dcAgentPromptBody' },
2398
2507
  h('nav', { className: 'dcAgentWizardNav', 'aria-label': '任务设置步骤' },
2399
2508
  [['1', '数据来源'], ['2', '匹配规则'], ['3', '清洗与补全'], ['4', '确认描述']].map(([index, label]) => h('button', {
2400
2509
  key: index,
@@ -2498,18 +2607,27 @@ window.__ModuleLoader__.load({
2498
2607
  h('b', null, '清洗目标'),
2499
2608
  h('div', { className: 'dcAgentPromptChoices' }, choice(CLEANING_OPTIONS, cleaningKeys, setCleaningKeys)),
2500
2609
  ),
2501
- FIELD_GROUPS.map(([groupId, label, fields, sourceTool]) => h('div', { className: 'dcAgentPromptGroup', key: groupId },
2610
+ h('label', { className: 'dcAgentPromptField' },
2611
+ h('span', null, `查找补全字段 · 已选 ${enrichmentKeys.length}`),
2612
+ h('input', { type: 'search', className: 'dcAgentField', value: fieldQuery, 'aria-label': '查找补全字段',
2613
+ placeholder: '搜索维度、字段或工具名称', onChange: (event) => setFieldQuery(event.target.value) })),
2614
+ !FIELD_GROUPS.some((group) => visibleCatalogFields(group, fieldQuery).length) ? h('p', { className: 'dcAgentHint', role: 'status' }, '没有匹配的字段;已选字段保持不变。') : null,
2615
+ FIELD_GROUPS.filter((group) => visibleCatalogFields(group, fieldQuery).length).map(([groupId, label, fields, sourceTool]) => h('div', { className: 'dcAgentPromptGroup dcAgentFieldGroup', key: groupId },
2502
2616
  h('div', { className: 'dcAgentFieldGroupHead' },
2503
2617
  h('div', null,
2504
2618
  h('b', null, `${label} · ${fields.filter(([id]) => enrichmentKeys.includes(id)).length}/${fields.length}`),
2505
2619
  sourceTool ? h('small', { className: 'dcAgentHint' }, `来源:${sourceTool}`) : null,
2506
2620
  ),
2507
2621
  h('div', { className: 'dcAgentFieldGroupActions' },
2508
- h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setPromptFieldGroup(fields, true) }, '全选'),
2509
- h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setPromptFieldGroup(fields, false) }, '清空'),
2622
+ h('button', { type: 'button', className: 'dcAgentFieldAction', title: '选中本维度全部字段,不受搜索过滤影响', onClick: () => setPromptFieldGroup(fields, true) }, '全选'),
2623
+ h('button', { type: 'button', className: 'dcAgentFieldAction', title: '清空本维度全部字段,不受搜索过滤影响', onClick: () => setPromptFieldGroup(fields, false) }, '清空'),
2510
2624
  ),
2511
2625
  ),
2512
- h('div', { className: 'dcAgentPromptChoices' }, choice(fields, enrichmentKeys, setEnrichmentKeys)),
2626
+ h('div', { className: 'dcAgentPromptFieldGrid' }, visibleCatalogFields([groupId, label, fields, sourceTool], fieldQuery).map(([id, fieldLabel]) => h('label', {
2627
+ key: id, className: `dcAgentPromptChoice${enrichmentKeys.includes(id) ? ' is-selected' : ''}`,
2628
+ }, h('input', { type: 'checkbox', checked: enrichmentKeys.includes(id),
2629
+ onChange: (event) => setEnrichmentKeys((current) => event.target.checked ? [...new Set([...current, id])] : current.filter((key) => key !== id)),
2630
+ }), fieldLabel))),
2513
2631
  )),
2514
2632
  ) : null,
2515
2633
  wizardStep === 4 ? h('div', { className: 'dcAgentWizardPane' },
@@ -2522,6 +2640,7 @@ window.__ModuleLoader__.load({
2522
2640
  ? h('p', { className: 'dcAgentPromptNote', role: 'status' }, `图片已载入,可继续选择规则和字段;暂存有效期 15 分钟。${imageCommand.providerIssue.message}`)
2523
2641
  : null,
2524
2642
  error ? h('p', { className: 'dcAgentPromptError', role: 'alert' }, error) : null,
2643
+ ),
2525
2644
  h('div', { className: 'dcAgentPromptActions' },
2526
2645
  h('button', { type: 'button', className: 'dcAgentPromptAction', disabled: wizardStep === 1, onClick: () => setWizardStep(Math.max(1, wizardStep - 1)) }, '上一步'),
2527
2646
  h('button', { type: 'button', className: 'dcAgentPromptAction is-primary', disabled: busy || imageCommand?.state === 'running', onClick: nextWizard }, busy
@@ -2531,11 +2650,9 @@ window.__ModuleLoader__.load({
2531
2650
  : wizardStep === 4 ? '回填到对话框' : '下一步'),
2532
2651
  ),
2533
2652
  ) : null,
2534
- imageLightbox && imageAttachment?.previewUrl ? h('button', {
2535
- type: 'button', className: 'dcAgentImageLightbox',
2536
- 'aria-label': '关闭图片预览',
2537
- onClick: () => setImageLightbox(false),
2538
- }, h('img', { src: imageAttachment.previewUrl, alt: imageFileName })) : null,
2653
+ imageLightbox && imageAttachment?.previewUrl ? h(ImagePreview, {
2654
+ src: imageAttachment.previewUrl, alt: imageFileName, sessionId, onClose: () => setImageLightbox(false),
2655
+ }) : null,
2539
2656
  );
2540
2657
  }
2541
2658
 
@@ -2551,9 +2668,7 @@ window.__ModuleLoader__.load({
2551
2668
  title: '打开数据清洗补全工作台',
2552
2669
  onClick: () => requestWorkbenchOpen(null, sessionId),
2553
2670
  },
2554
- typeof IconDataOutline16 === 'function'
2555
- ? h(IconDataOutline16, { size: 16, 'aria-hidden': 'true' })
2556
- : h('span', { 'aria-hidden': 'true' }, '▦'),
2671
+ h(DatabaseLogo, { size: 16 }),
2557
2672
  h('span', null, '清洗补全工作台'),
2558
2673
  );
2559
2674
  }
@@ -2828,6 +2943,7 @@ window.__ModuleLoader__.load({
2828
2943
  const paidConfirmed = useStore((state) => state.paidConfirmed);
2829
2944
  const jobs = useStore((state) => state.jobs);
2830
2945
  const activeSessionId = useStore((state) => state.activeSessionId);
2946
+ const [fieldQuery, setFieldQuery] = react.useState('');
2831
2947
 
2832
2948
  react.useEffect(() => {
2833
2949
  rootWorkbenchActions = actions;
@@ -3378,10 +3494,18 @@ window.__ModuleLoader__.load({
3378
3494
  };
3379
3495
 
3380
3496
  const startNewWorkflow = () => {
3497
+ const event = document.createEvent('CustomEvent');
3498
+ event.initCustomEvent('dsh:data-cleaning-prompt-new', false, true, { sessionId: activeSessionId });
3499
+ if (document.dispatchEvent(event)) {
3500
+ actions.setError('当前会话的任务向导尚未就绪或正在解析图片,请稍后重试。');
3501
+ return;
3502
+ }
3381
3503
  if (cachedTask?.id) runtimeTasks.delete(String(cachedTask.id));
3504
+ runtimeTasks.delete(`session:${activeSessionId || 'unassigned'}`);
3382
3505
  runtimeTasks.delete('unassigned');
3383
3506
  workflowTaskBySession.delete(String(activeSessionId || 'unassigned'));
3384
3507
  actions.resetWorkflow();
3508
+ actions.close();
3385
3509
  };
3386
3510
 
3387
3511
  const exportRows = () => runtime.resultRows.qcc
@@ -3566,18 +3690,22 @@ window.__ModuleLoader__.load({
3566
3690
  h('span', { className: 'dcAgentChip' }, '第一批 40'),
3567
3691
  h('span', { className: 'dcAgentChip' }, '第二批 58'),
3568
3692
  ),
3569
- uiFieldGroups.map(([groupId, label, fields, sourceTool]) => h('div', { key: groupId, className: 'dcAgentFieldGroup' },
3693
+ h('label', { className: 'dcAgentPromptField' }, h('span', null, '查找补全字段'),
3694
+ h('input', { type: 'search', className: 'dcAgentField', value: fieldQuery, 'aria-label': '查找补全字段',
3695
+ placeholder: '搜索维度、字段或工具名称', onChange: (event) => setFieldQuery(event.target.value) })),
3696
+ !uiFieldGroups.some((group) => visibleCatalogFields(group, fieldQuery).length) ? h('p', { className: 'dcAgentHint', role: 'status' }, '没有匹配的字段;已选字段保持不变。') : null,
3697
+ uiFieldGroups.filter((group) => visibleCatalogFields(group, fieldQuery).length).map(([groupId, label, fields, sourceTool]) => h('div', { key: groupId, className: 'dcAgentFieldGroup' },
3570
3698
  h('div', { className: 'dcAgentFieldGroupHead' },
3571
3699
  h('div', null,
3572
3700
  h('b', null, `${label} · ${fields.filter(([id]) => fieldSelection.includes(id)).length}/${fields.length}`),
3573
3701
  sourceTool ? h('small', { className: 'dcAgentHint' }, `来源:${sourceTool}`) : null,
3574
3702
  ),
3575
3703
  h('div', { className: 'dcAgentFieldGroupActions' },
3576
- h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setWorkbenchFieldGroup(fields, true) }, '全选'),
3577
- h('button', { type: 'button', className: 'dcAgentFieldAction', onClick: () => setWorkbenchFieldGroup(fields, false) }, '清空'),
3704
+ h('button', { type: 'button', className: 'dcAgentFieldAction', title: '选中本维度全部字段,不受搜索过滤影响', onClick: () => setWorkbenchFieldGroup(fields, true) }, '全选'),
3705
+ h('button', { type: 'button', className: 'dcAgentFieldAction', title: '清空本维度全部字段,不受搜索过滤影响', onClick: () => setWorkbenchFieldGroup(fields, false) }, '清空'),
3578
3706
  ),
3579
3707
  ),
3580
- h('div', { className: 'dcAgentChips' }, fields.map(([key, fieldLabel]) => h('label', { key, className: `dcAgentChip${fieldSelection.includes(key) ? ' is-selected' : ''}` },
3708
+ h('div', { className: 'dcAgentChips' }, visibleCatalogFields([groupId, label, fields, sourceTool], fieldQuery).map(([key, fieldLabel]) => h('label', { key, className: `dcAgentChip${fieldSelection.includes(key) ? ' is-selected' : ''}` },
3581
3709
  h('input', { type: 'checkbox', checked: fieldSelection.includes(key), onChange: () => actions.toggleField(key) }), ` ${fieldLabel}`,
3582
3710
  ))),
3583
3711
  )),
@@ -3779,7 +3907,7 @@ window.__ModuleLoader__.load({
3779
3907
  title: runtime.source?.type === 'image' ? '图片识别原始名单(尚未匹配)' : '导入原始清单',
3780
3908
  onError: actions.setError,
3781
3909
  }) : null,
3782
- hasData ? h('p', { className: 'dcAgentHint' }, '请核对完整名单。识别清单不代表已完成企查查匹配。核对后进入「字段映射与规则」,确认规则生成质量体检;再进入「数据匹配」估算调用量并确认账号额度,点击「生成可编辑任务说明」自动回填中央对话框,无需手工复制任务凭证。') : null,
3910
+ hasData ? h('p', { className: 'dcAgentHint' }, '请核对完整名单。识别清单不代表已完成企查查匹配。核对后进入「规则与体检」,确认规则生成质量体检;再进入「主体匹配」估算调用量并确认账号额度,点击「生成可编辑任务说明」自动回填中央对话框,无需手工复制任务凭证。') : null,
3783
3911
  h('div', { className: 'dcAgentRow' },
3784
3912
  h('button', { type: 'button', className: 'dcAgentButton is-primary', disabled: busy, 'aria-label': '解析数据', onClick: handleParse }, busy ? '解析中…' : '解析数据'),
3785
3913
  hasData ? h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || sourceRows.length !== dataset.rowCount, onClick: () => actions.setStep('rules') }, '已核对清单,下一步:字段映射与规则') : null,
@@ -3813,7 +3941,7 @@ window.__ModuleLoader__.load({
3813
3941
  },
3814
3942
  h('header', { className: 'dcAgentWbHeader' },
3815
3943
  h('div', { className: 'dcAgentWbTitle' },
3816
- h('span', { className: 'dcAgentWbIcon', 'aria-hidden': 'true' }, '🧹'),
3944
+ h('span', { className: 'dcAgentWbIcon', 'aria-hidden': 'true' }, h(DatabaseLogo, { size: 22 })),
3817
3945
  h('div', null,
3818
3946
  h('b', null, '数据清洗补全'),
3819
3947
  h('small', null, cachedTask ? `${WORKFLOW_STATE_LABELS[cachedTask.state] || cachedTask.state} · ${cachedTask.id.slice(0, 18)}` : '正在创建 Host taskId…'),
@@ -3843,19 +3971,39 @@ window.__ModuleLoader__.load({
3843
3971
  }, '✕'),
3844
3972
  ),
3845
3973
  ),
3846
- h('nav', { className: 'dcAgentStepper', 'aria-label': '清洗流程' },
3974
+ h('nav', { className: 'dcAgentManagement', 'aria-label': '工作台管理' },
3975
+ h('button', { type: 'button', className: 'dcAgentButton', 'aria-pressed': step !== 'history',
3976
+ onClick: () => actions.setStep(cachedTask?.stage || 'upload') }, '当前任务'),
3977
+ h('button', { type: 'button', className: 'dcAgentButton', 'aria-pressed': step === 'history',
3978
+ onClick: () => actions.setStep('history') }, '任务历史'),
3979
+ ),
3980
+ step !== 'history' ? h('nav', { className: 'dcAgentStepper', 'aria-label': '清洗流程' },
3847
3981
  STEPS.map((st) => h('button', {
3848
3982
  key: st.key,
3849
3983
  type: 'button',
3850
- className: `dcAgentStep${step === st.key ? ' is-active' : ''}`,
3984
+ className: `dcAgentStep${(step === 'profile' ? 'rules' : step) === st.key ? ' is-active' : ''}`,
3851
3985
  'aria-label': st.label,
3852
- 'aria-current': step === st.key ? 'step' : undefined,
3986
+ 'aria-current': (step === 'profile' ? 'rules' : step) === st.key ? 'step' : undefined,
3853
3987
  onClick: () => actions.setStep(st.key),
3854
3988
  }, `${st.icon} ${st.label}`)),
3855
- ),
3989
+ ) : null,
3856
3990
  h('div', { className: 'dcAgentWbBody' },
3857
3991
  error ? h('div', { className: 'dcAgentError', role: 'alert' }, error) : null,
3858
- pane,
3992
+ step !== 'history' ? h('details', { className: 'dcAgentSection' },
3993
+ h('summary', null, '使用说明与任务流程'),
3994
+ h('p', { className: 'dcAgentHint' }, '导入与核验 → 规则与体检 → 主体匹配 → 字段补全 → 结果下载。菜单只切换视图,不启动调用;按页面主按钮逐步确认。'),
3995
+ h('p', { className: 'dcAgentHint' }, '支持文本、Excel、JSON 和图片名单。原值保留、多候选人工核验;企查查调用使用当前用户自己的连接与额度。'),
3996
+ ) : null,
3997
+ ['rules', 'profile'].includes(step) ? h('nav', { className: 'dcAgentRow', 'aria-label': '规则与体检视图' },
3998
+ h('button', { type: 'button', className: 'dcAgentButton', 'aria-pressed': step === 'rules', onClick: () => actions.setStep('rules') }, '字段映射与规则'),
3999
+ h('button', { type: 'button', className: 'dcAgentButton', 'aria-pressed': step === 'profile', onClick: () => actions.setStep('profile') }, '质量体检报告'),
4000
+ ) : null,
4001
+ workflowNavigationIssue(step, cachedTask, hasData, profile, qccRun)
4002
+ ? h('section', { className: 'dcAgentSection', role: 'status' },
4003
+ h('p', null, workflowNavigationIssue(step, cachedTask, hasData, profile, qccRun)),
4004
+ h('button', { type: 'button', className: 'dcAgentButton',
4005
+ onClick: () => actions.setStep(!hasData ? 'upload' : !cachedTask || ['draft', 'uploaded'].includes(cachedTask.state) ? 'rules' : cachedTask.state === 'rules_confirmed' ? 'profile' : step === 'download' ? 'enrich' : 'match') }, '前往前置步骤'))
4006
+ : pane,
3859
4007
  ),
3860
4008
  ),
3861
4009
  );
@@ -3902,7 +4050,7 @@ window.__ModuleLoader__.load({
3902
4050
  inject: () => ({ startSession: () => startCleaningSession(ctx) }),
3903
4051
  }, SidebarEntry));
3904
4052
 
3905
- // 独立 dock 行:对齐 Mockup 的五个能力 ICON,CSS 只把本 cell 排到输入框下方。
4053
+ // dock 托管会话生命周期;菜单 Portal 到输入框后,不重排共享槽位。
3906
4054
  ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({
3907
4055
  name: 'conversation.input.dock',
3908
4056
  id: 'data-cleaning-agent-capabilities',
@@ -3954,6 +4102,12 @@ window.__ModuleLoader__.load({
3954
4102
  exports.inject = inject;
3955
4103
  // 测试用纯函数,不构成 Host / DSH 稳定 API。
3956
4104
  exports.__testing = {
4105
+ DatabaseLogo,
4106
+ visibleCatalogFields,
4107
+ installCapabilityMount,
4108
+ PromptDialog,
4109
+ ProductHome,
4110
+ workflowNavigationIssue,
3957
4111
  buildTaskPrompt,
3958
4112
  DatasetReview,
3959
4113
  reviewColumns,