dsh-data-cleaning-agent 0.8.21 → 0.8.23

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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.8.23] - 2026-09-09
8
+
9
+ - 工作台顶部仅保留产品标题和展开、关闭按钮,移除重复状态与技术标识。
10
+ - 完整任务状态保留在进度卡;约束标题收缩,避免窄屏时与按钮重叠。
11
+ - 246 项测试与 10 组深浅主题、不同视口布局回归通过。
12
+
13
+ ## [0.8.22] - 2026-09-09
14
+
15
+ - 表格预览保留可读列宽、横向滚动和固定表头,避免多列挤压成竖排。
16
+ - 结果文件操作分行并留白,长文件名换行;失败计数单独展示,避免零补全被标绿。
17
+ - 失败行导出保留规范化错误码和工具名,不输出原始上游响应或凭据。
18
+ - 修复自动展开后关闭/切换会话时,排队中的尺寸回调重新写入布局留白的竞态。
19
+ - 延续 0.8.21 的实际 Host 文件地址和执行自动展开功能。
20
+
7
21
  ## [0.8.21] - 2026-09-09
8
22
 
9
23
  - 从实际 Host 请求获取文件地址的协议和主机;修复本地 HTTP 链接被补成 HTTPS 的问题。
package/README.en.md CHANGED
@@ -8,7 +8,7 @@ Related agents: [数据清洗补全](https://github.com/duhu2000/dsh-data-cleani
8
8
 
9
9
  > A data cleaning & completion agent plugin for DeepSeek Harness: local CSV/XLSX/JSON engine plus optional Qichacha (QCC) MCP enterprise-data enrichment. Initiated and maintained by the Qichacha (QCC) team.
10
10
  >
11
- > Current source version / 当前源码版本: **0.8.21** (stable release)
11
+ > Current source version / 当前源码版本: **0.8.23** (stable release)
12
12
 
13
13
  This release unifies spreadsheet previews, column mapping, and enrichment scope across the prompt wizard and workbench. Mapping statuses use color and text; mapped fields automatically enter the scope, with optional extra fields collapsed. Multiple confirmed output columns may share a non-identity field while preserving non-empty values. It fixes saved drafts resetting the scope to five defaults and detects stale Host versions. Preparing a draft does not query QCC; sending starts execution. Fully restart DSH after upgrading. Existing download artifacts are not rewritten.
14
14
 
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # dsh-data-cleaning-agent
2
2
 
3
- 本版统一向导与工作台的 Host 执行闭环:发送后自动生成新 Excel,原文件不修改,工作台入口可恢复;发布记录见 [发布说明](docs/RELEASE-0.8.21.md)。
3
+ 本版统一向导与工作台的 Host 执行闭环:发送后自动生成新 Excel,原文件不修改,工作台入口可恢复;发布记录见 [发布说明](docs/RELEASE-0.8.22.md)。
4
4
 
5
5
  ## 安装与三分钟上手
6
6
 
7
7
  数据清洗补全智能体:面向 Excel/CSV/JSON 企业名单,提供数据清洗、表格清洗、清洗补全、去重、企业数据补全与字段补全,支持企查查 MCP 和结果导出。
8
8
 
9
9
  ```sh
10
- dsh plugin --profile web add dsh-data-cleaning-agent@0.8.21
10
+ dsh plugin --profile web add dsh-data-cleaning-agent@0.8.23
11
11
  ```
12
12
 
13
13
  请先满足下文的 DSH、连接器及侧边栏依赖要求;安装后完整停止并重启对应 Profile。
@@ -25,7 +25,7 @@ dsh plugin --profile web add dsh-data-cleaning-agent@0.8.21
25
25
 
26
26
  > 在 DeepSeek Harness 中清洗、补全、画像企业名单数据的智能体插件:本地 CSV/XLSX/JSON 引擎 + 可选企查查(Qichacha/QCC)MCP 企业数据补全,由企查查(Qichacha/QCC)团队发起并维护。
27
27
  >
28
- > 当前源码版本 / Current source version: **0.8.21**(正式版本)
28
+ > 当前源码版本 / Current source version: **0.8.23**(正式版本)
29
29
 
30
30
  本版上传表格后展示完整清单及空白数量,用绿色、琥珀色、红色及文字区分已通过、待确认和未匹配映射。已映射字段自动纳入补全范围,额外字段默认折叠;多个原列可经确认使用同一非主体字段,分别补空并保留非空原值。修复 Host 草稿重置为默认五字段的问题,增加前后端版本错配提示。生成说明不查询,发送才执行;升级后需完整重启 DSH,历史下载文件不自动改写。
31
31
 
@@ -0,0 +1,11 @@
1
+ # 0.8.22 发布说明
2
+
3
+ 包含 0.8.21 的实际 Host 协议文件链接与执行自动展开功能;额外修复尺寸回调在工作台关闭后写回留白的竞态。
4
+
5
+ - 表格不压缩列宽,支持左右滚动;纵向滚动固定表头。
6
+ - 预览和下载操作分行留白,长文件名不再挤压按钮。
7
+ - 单独显示失败数量;失败行在异常清单保留规范化错误码和工具名。
8
+
9
+ 本次不改变企查查查询范围,不自动重跑历史任务;历史异常文件不会补写已遗漏的错误信息。
10
+
11
+ 升级后完整重启 DSH。历史错误链接文本不会重写,可从工作台访问原有文件,不需要重新查询。
package/lib/client.js CHANGED
@@ -89,19 +89,27 @@ window.__ModuleLoader__.load({
89
89
  const handle = drawer.querySelector('.dcAgentResizeHandle');
90
90
  if (!handle || !view) return () => {};
91
91
  const reservations = new Map();
92
+ const registryKey = Symbol.for('dsh.data-cleaning.sizing-reservations');
93
+ const registry = doc[registryKey] || (doc[registryKey] = new WeakMap());
94
+ let disposed = false;
92
95
  let requested = expanded ? 980 : preferredWidth;
93
96
  let current = 0;
94
97
  let drag = null;
95
98
  const boundsForView = () => workbenchWidthBounds(view.innerWidth,
96
99
  doc.querySelector('[data-conversation-scroll]')?.getBoundingClientRect().width || view.innerWidth);
97
100
  const reserve = () => {
101
+ if (disposed) return;
98
102
  const width = boundsForView().mobile ? 0 : drawer.getBoundingClientRect().width;
99
103
  for (const el of doc.querySelectorAll('[data-conversation-scroll]')) {
100
104
  if (!reservations.has(el)) {
101
- reservations.set(el, {
105
+ const previous = registry.get(el) || {
102
106
  value: el.style.getPropertyValue('--dc-agent-workbench-reserve'),
103
107
  priority: el.style.getPropertyPriority('--dc-agent-workbench-reserve'),
104
- });
108
+ owners: 0,
109
+ };
110
+ previous.owners += 1;
111
+ registry.set(el, previous);
112
+ reservations.set(el, previous);
105
113
  sizeObserver?.observe(el, { box: 'border-box' });
106
114
  }
107
115
  if (el.style.getPropertyValue('--dc-agent-workbench-reserve') !== `${width}px`) {
@@ -110,6 +118,7 @@ window.__ModuleLoader__.load({
110
118
  }
111
119
  };
112
120
  const apply = (value) => {
121
+ if (disposed) return;
113
122
  const bounds = boundsForView();
114
123
  const fallback = view.innerWidth <= 1040 ? Math.min(420, view.innerWidth * .48) : Math.min(460, view.innerWidth * .42);
115
124
  current = Math.round(Math.min(bounds.max, Math.max(bounds.min, Number.isFinite(value) ? value : fallback)));
@@ -173,6 +182,7 @@ window.__ModuleLoader__.load({
173
182
  observer?.observe(doc.body, { childList: true, subtree: true });
174
183
  apply(requested);
175
184
  return () => {
185
+ disposed = true;
176
186
  cancel();
177
187
  observer?.disconnect();
178
188
  sizeObserver?.disconnect();
@@ -188,6 +198,9 @@ window.__ModuleLoader__.load({
188
198
  drawer.style.removeProperty('--dc-agent-panel-width');
189
199
  delete drawer.dataset.narrow;
190
200
  for (const [el, previous] of reservations) {
201
+ previous.owners -= 1;
202
+ if (previous.owners > 0) continue;
203
+ registry.delete(el);
191
204
  if (previous.value) el.style.setProperty('--dc-agent-workbench-reserve', previous.value, previous.priority);
192
205
  else el.style.removeProperty('--dc-agent-workbench-reserve');
193
206
  }
@@ -626,6 +639,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
626
639
 
627
640
  .dcAgentWbTitle b,
628
641
  .dcAgentWbTitle small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
642
+ .dcAgentWbTitle > div { min-width: 0; }
629
643
  .dcAgentWbTitle b { display: block; font-size: 15px; }
630
644
  .dcAgentWbTitle small { display: block; max-width: 190px; color: var(--dc-muted); font-size: 12px; }
631
645
 
@@ -970,6 +984,25 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
970
984
  }
971
985
  .dcAgentFieldAction:hover, .dcAgentFieldAction:focus-visible { background: var(--dc-selected); }
972
986
  .dcAgentPreviewTable { margin-top: 12px; overflow: auto; border: 1px solid var(--dc-border); border-radius: 8px; }
987
+ .dcAgentArtifactList { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; min-width: 0; }
988
+ .dcAgentArtifactList > .dcAgentButton { display: inline-flex; align-items: center; box-sizing: border-box; max-width: 100%; min-width: 0; height: auto; white-space: normal; overflow-wrap: anywhere; line-height: 1.5; text-decoration: none; }
989
+ .dcAgentArtifactList > a.dcAgentButton { flex-basis: 100%; }
990
+ .dcAgentPreviewTable { min-width: 0; max-width: 100%; scrollbar-gutter: stable; }
991
+ .dcAgentPreviewTable > .dcAgentTable {
992
+ width: max-content; min-width: 100%; max-width: none;
993
+ table-layout: auto; border-collapse: separate; border-spacing: 0;
994
+ }
995
+ .dcAgentPreviewTable > .dcAgentTable th,
996
+ .dcAgentPreviewTable > .dcAgentTable td {
997
+ min-width: 140px; max-width: none; white-space: nowrap;
998
+ word-break: normal; overflow-wrap: normal;
999
+ border-right: 1px solid var(--dc-border);
1000
+ }
1001
+ .dcAgentPreviewTable > .dcAgentTable th:first-child,
1002
+ .dcAgentPreviewTable > .dcAgentTable td:first-child { min-width: 64px; }
1003
+ .dcAgentPreviewTable > .dcAgentTable th {
1004
+ position: sticky; top: 0; z-index: 2; background: var(--dc-table-head);
1005
+ }
973
1006
  .dcAgentHistoryTask { display: block; width: 100%; padding: 10px; text-align: left; }
974
1007
  .dcAgentHistoryTask h3 { margin: 0; font-size: 12px; }
975
1008
  /*
@@ -1863,10 +1896,11 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
1863
1896
  }
1864
1897
  function watchHostedCommand(actions, sessionId, command) {
1865
1898
  let openedForExecution = false;
1899
+ const ownerVisible = () => typeof document === 'undefined' || [...document.querySelectorAll('.dcAgentExperience')].some(node => node.dataset.sessionId === sessionId);
1866
1900
  void waitForQccCommand(command.commandId, 1800, async (status) => {
1867
1901
  if (!status || status.state === 'prepared') return;
1868
1902
  await refreshHostedTask(actions, sessionId, command.taskId, null, true).catch(() => {});
1869
- if (!openedForExecution && isCleaningSession(sessionId) && workflowTaskBySession.get(String(sessionId))?.id === command.taskId) {
1903
+ if (!openedForExecution && ownerVisible() && isCleaningSession(sessionId) && workflowTaskBySession.get(String(sessionId))?.id === command.taskId) {
1870
1904
  openedForExecution = true;
1871
1905
  openWorkbench(actions, workflowTaskBySession.get(String(sessionId))?.stage || 'match', sessionId);
1872
1906
  }
@@ -2185,6 +2219,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
2185
2219
  const WORKBENCH_DATASET_EVENT = 'dsh:data-cleaning-workbench-dataset';
2186
2220
  const WORKBENCH_DRAFT_EVENT = 'dsh:data-cleaning-workbench-draft';
2187
2221
  const WORKBENCH_PREPARE_EVENT = 'dsh:data-cleaning-workbench-prepare';
2222
+ const WORKBENCH_OWNER_LEFT_EVENT = 'dsh:data-cleaning-workbench-owner-left';
2188
2223
 
2189
2224
  // session scope 不能复用 root scope 的 store handle。DSH 当前会分别物化 root/session
2190
2225
  // 插槽组件,因此以 document 事件跨 scope 通知;闭包引用仅作为无 DOM 测试降级。
@@ -2547,6 +2582,10 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
2547
2582
  function DataCleaningExperience(props) {
2548
2583
  const { sessionId, session: ownerSession } = props;
2549
2584
  const enabled = useCleaningSession(sessionId);
2585
+ react.useEffect(() => {
2586
+ if (!enabled) return undefined;
2587
+ return () => document.dispatchEvent(new CustomEvent(WORKBENCH_OWNER_LEFT_EVENT, { detail: { sessionId } }));
2588
+ }, [enabled, sessionId]);
2550
2589
  const hero = ownerSession?.composerPhase === 'blank';
2551
2590
  const [menuMount, setMenuMount] = react.useState(null);
2552
2591
  react.useEffect(() => {
@@ -3428,7 +3467,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3428
3467
  h('p', { className: 'dcAgentHint', role: 'status' }, complete
3429
3468
  ? `共 ${total} 条,当前显示 ${total ? start + 1 : 0}–${Math.min(start + pageSize, total)} 条;共 ${columns.length} 列,可横向滚动。`
3430
3469
  : `完整清单尚未就绪:预期 ${expectedCount} 条,当前载入 ${total} 条。请等待同步;刷新后若仍缺失,请重新上传源文件。`),
3431
- h('div', { className: 'dcAgentPreviewTable', style: { overflow: 'auto', maxHeight: '420px' } },
3470
+ h('div', { className: 'dcAgentPreviewTable', tabIndex: 0, role: 'region', 'aria-label': '表格预览,可横向和纵向滚动,表头固定', style: { overflow: 'auto', maxHeight: '420px' } },
3432
3471
  h('table', { className: 'dcAgentTable' },
3433
3472
  h('thead', null, h('tr', null, h('th', null, '序号'), columns.map((key) => h('th', { key }, resultFieldLabel(key))))),
3434
3473
  h('tbody', null, rows.slice(start, start + pageSize).map((row, index) => h('tr', { key: start + index },
@@ -3493,6 +3532,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3493
3532
 
3494
3533
  react.useEffect(() => {
3495
3534
  rootWorkbenchActions = actions;
3535
+ const handleOwnerLeft = () => actions.close();
3496
3536
  const handleOpen = (event) => {
3497
3537
  event?.preventDefault?.();
3498
3538
  const detail = event?.detail ?? {};
@@ -3545,6 +3585,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3545
3585
  };
3546
3586
  if (typeof document !== 'undefined' && typeof document.addEventListener === 'function') {
3547
3587
  document.addEventListener(WORKBENCH_OPEN_EVENT, handleOpen);
3588
+ document.addEventListener(WORKBENCH_OWNER_LEFT_EVENT, handleOwnerLeft);
3548
3589
  document.addEventListener(WORKBENCH_DATASET_EVENT, handleDataset);
3549
3590
  document.addEventListener(WORKBENCH_DRAFT_EVENT, handleDraft);
3550
3591
  document.addEventListener(WORKBENCH_PREPARE_EVENT, handlePrepare);
@@ -3552,6 +3593,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
3552
3593
  return () => {
3553
3594
  if (typeof document !== 'undefined' && typeof document.removeEventListener === 'function') {
3554
3595
  document.removeEventListener(WORKBENCH_OPEN_EVENT, handleOpen);
3596
+ document.removeEventListener(WORKBENCH_OWNER_LEFT_EVENT, handleOwnerLeft);
3555
3597
  document.removeEventListener(WORKBENCH_DATASET_EVENT, handleDataset);
3556
3598
  document.removeEventListener(WORKBENCH_DRAFT_EVENT, handleDraft);
3557
3599
  document.removeEventListener(WORKBENCH_PREPARE_EVENT, handlePrepare);
@@ -4143,6 +4185,7 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4143
4185
  ? (qccRun.summary?.ambiguous ?? 0) + (qccRun.summary?.fieldReview ?? 0)
4144
4186
  : cachedTask?.enrichmentSummary?.reviewRequired
4145
4187
  ?? cachedTask?.matchSummary?.reviewRequired;
4188
+ const qccFailedCount = qccRun?.summary?.failed ?? cachedTask?.enrichmentSummary?.failed ?? cachedTask?.matchSummary?.failed ?? 0;
4146
4189
  const stat = (label, value, tone) => h('div', { className: 'dcAgentCard' },
4147
4190
  h('span', null, label),
4148
4191
  h('b', { className: tone ? `is-${tone}` : null }, displayStatValue(value))
@@ -4378,12 +4421,13 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4378
4421
  const availableArtifacts = (cachedTask?.artifacts || []).filter(artifact => artifact.kind !== 'review' || artifact.rowCount > 0);
4379
4422
  const canCreateArtifacts = Boolean(exportRows()?.length) && ['rules_confirmed', 'diagnosed', 'export_ready', 'partial'].includes(cachedTask?.state);
4380
4423
  pane = h('div', { className: 'dcAgentPane' },
4381
- h('p', { className: 'dcAgentHint' }, '结果文件由 Host 保存;仅在有待核验记录时展示异常清单。任务或插件重启后,可从任务历史继续下载;无需再次调用企查查。'),
4424
+ h('p', { className: 'dcAgentHint' }, '结果文件由 Host 保存;有失败、未匹配或待核验记录时展示异常清单。任务或插件重启后,可从任务历史继续下载;无需再次调用企查查。'),
4382
4425
  h('div', { className: 'dcAgentGrid' },
4383
4426
  stat('输入行数', dataset ? dataset.rowCount : workflowTask?.source?.rowCount ?? '—'),
4384
4427
  stat('匹配补全', qccEnrichedCount, qccEnrichedCount > 0 ? 'good' : null),
4385
4428
  stat('待核验', qccReviewCount, qccReviewCount > 0 ? 'warn' : null),
4386
4429
  stat('任务状态', WORKFLOW_STATE_LABELS[cachedTask?.state] || cachedTask?.state || '进行中'),
4430
+ stat('失败', qccFailedCount, qccFailedCount > 0 ? 'bad' : null),
4387
4431
  ),
4388
4432
  availableArtifacts.length ? h('div', { className: 'dcAgentArtifactList' },
4389
4433
  availableArtifacts.filter(artifact => artifact.format === 'xlsx').map(artifact => h('a', {
@@ -4503,15 +4547,9 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4503
4547
  h('span', { className: 'dcAgentWbIcon', 'aria-hidden': 'true' }, h(DatabaseLogo, { size: 22 })),
4504
4548
  h('div', null,
4505
4549
  h('b', null, '数据清洗补全'),
4506
- h('small', null, cachedTask ? `${WORKFLOW_STATE_LABELS[cachedTask.state] || cachedTask.state} · ${cachedTask.id.slice(0, 18)}` : '正在创建 Host taskId…'),
4507
4550
  ),
4508
4551
  ),
4509
4552
  h('div', { className: 'dcAgentWbActions' },
4510
- h('span', {
4511
- className: 'dcAgentQccBadge',
4512
- title: qccRun ? `任务 ${qccRun.runId}` : '仅在当前用户确认使用自己的企查查账号后调用',
4513
- }, qccRun ? `QCC · ${qccRun.state}` : qccCapabilities ? (qccCapabilities.capabilities?.ready ? 'QCC · 工具已就绪' : 'QCC · 能力不完整') : 'QCC · 自动校验'),
4514
- h('span', { className: 'dcAgentJobsPill', 'data-state': cachedTask?.state || 'idle', title: '当前清洗任务状态' }, cachedTask ? WORKFLOW_STATE_LABELS[cachedTask.state] || cachedTask.state : '尚未开始'),
4515
4553
  h('button', {
4516
4554
  className: 'dcAgentWbClose',
4517
4555
  type: 'button',
@@ -4560,8 +4598,8 @@ body:has(.dcAgentPromptBackdrop) { overflow: hidden; }
4560
4598
  max: commandProgress.totalUnique, value: Math.min(commandProgress.totalUnique, Math.max(0, commandProgress.completedUnique || 0)),
4561
4599
  'aria-label': '主体处理进度', style: { width: '100%', accentColor: cachedTask.state === 'completed' ? '#16845b' : cachedTask.state === 'failed' ? '#c62828' : cachedTask.state === 'partial' ? '#a66a00' : '#087dcc' },
4562
4600
  }) : null,
4563
- h('p', { style: { color: Number(qccReviewCount) > 0 ? '#a66a00' : Number.isFinite(qccEnrichedCount) ? '#16845b' : 'inherit' } },
4564
- Number.isFinite(qccEnrichedCount) ? `已处理并补全 ${qccEnrichedCount} 条 · 待核验 ${Number.isFinite(qccReviewCount) ? qccReviewCount : '统计中'} 条(按输入行统计;未披露字段保留空白)` : '结果统计中,处理结束后展示补全与待核验数量'),
4601
+ h('p', { style: { color: qccFailedCount > 0 ? '#c62828' : Number(qccReviewCount) > 0 ? '#a66a00' : qccEnrichedCount > 0 ? '#16845b' : 'inherit' } },
4602
+ Number.isFinite(qccEnrichedCount) ? `已处理并补全 ${qccEnrichedCount} 条 · 待核验 ${Number.isFinite(qccReviewCount) ? qccReviewCount : '统计中'} 条 · 失败 ${qccFailedCount} 条(按输入行统计;未披露字段保留空白)` : '结果统计中,处理结束后展示补全与待核验数量'),
4565
4603
  ) : null,
4566
4604
  error ? h('div', { className: 'dcAgentError', role: 'alert' }, error) : null,
4567
4605
  step !== 'history' ? h('details', { className: 'dcAgentSection' },
package/lib/qcc.js CHANGED
@@ -1074,7 +1074,11 @@ export class QccHostBridge {
1074
1074
  ...(result.fieldIssues ? { qcc_field_notes: Object.entries(result.fieldIssues).filter(([, issue]) => issue.reviewRequired === false).map(([field, issue]) => field + ': ' + issue.message).join(';') } : {}),
1075
1075
  };
1076
1076
  }
1077
- return { ...row, qcc_match_status: result?.status ?? 'failed' };
1077
+ return {
1078
+ ...row, qcc_match_status: result?.status ?? 'failed',
1079
+ // Only export normalized diagnostic identifiers, never raw upstream messages or credentials.
1080
+ ...(result?.error ? { qcc_error: [result.error.code, result.error.toolName, result.error.upstreamCode].filter(Boolean).join(' · ') } : {}),
1081
+ };
1078
1082
  });
1079
1083
 
1080
1084
  const indexesFor = (name) => normalized.filter((item) => item.companyName === name).map((item) => item.index);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-data-cleaning-agent",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "description": "Data cleaning and data enrichment for CSV/XLSX/JSON enterprise lists in DeepSeek Harness, including spreadsheet cleaning, deduplication, profiling, optional Qichacha MCP and exports.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -40,7 +40,7 @@
40
40
  "docs/RELEASE-0.8.1.md",
41
41
  "docs/RELEASE-0.8.16.md",
42
42
  "docs/RELEASE-0.8.17.md",
43
- "docs/RELEASE-0.8.21.md",
43
+ "docs/RELEASE-0.8.22.md",
44
44
  "docs/TEMPLATE-MAPPING-ACCEPTANCE.md",
45
45
  "docs/UI-WORKFLOW-V2.md",
46
46
  "docs/UI-WORKFLOW-V2-MIGRATION.md",
@@ -1,9 +0,0 @@
1
- # 0.8.21 发布说明
2
-
3
- 文件预览与下载地址使用实际请求的协议、主机,不硬编码 HTTPS 或端口;工具结果卡片接受同源完整地址。
4
-
5
- 检测已暂存任务开始执行后自动展开右侧工作台一次,切到当前处理步骤。生成说明不会提前打开,用户关闭后同一监听不会重复打开。
6
-
7
- 验证:246 项测试及 10 组浏览器回归。未重新执行付费查询,未修改上传文件。
8
-
9
- 升级后完整重启 DSH,并重新生成后续任务说明。历史对话中的错误 HTTPS 文本链接不会被改写,可通过工作台打开历史文件。