dsh-data-cleaning-agent 0.6.0 → 0.6.2
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 +29 -0
- package/README.en.md +12 -6
- package/README.md +11 -7
- package/docs/COMPATIBILITY.md +7 -6
- package/docs/G5-HOST-BRIDGE.md +34 -8
- package/docs/QCC-ENRICHMENT-DESIGN.md +4 -2
- package/docs/QCC-PHASES-ROADMAP.md +3 -2
- package/docs/RELEASE-0.6.0.md +14 -3
- package/docs/RELEASE-0.6.1.md +64 -0
- package/docs/RELEASE-0.6.2.md +40 -0
- package/docs/UI-WORKFLOW-V2.md +2 -3
- package/lib/artifacts.js +47 -8
- package/lib/client.js +283 -66
- package/lib/engine.js +1 -1
- package/lib/index.js +9 -4
- package/lib/jobs.js +1 -1
- package/lib/qcc-command.js +280 -0
- package/lib/qcc-runs.js +5 -1
- package/lib/qcc.js +142 -15
- package/lib/skill-enrich.js +7 -2
- package/lib/tools.js +1 -1
- package/lib/web.js +55 -1
- package/lib/workflow-contract.js +9 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.6.2] - 2026-09-04
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- 清洗补全结果 CSV/XLSX 的插件字段与状态字段统一导出为中文表头,并按任务字段选择保留空值列,
|
|
11
|
+
不再因企查查未返回某一字段而从制品中静默丢列。
|
|
12
|
+
- 将任务选择的补全字段贯穿中央工作台、Agent-owned 命令、G5 Host Bridge、任务恢复与耐久制品;
|
|
13
|
+
工商详情补充注册地址、行政区划、经营范围、行业、营业期限和企业规模映射,企业简介等画像字段按需
|
|
14
|
+
调用 `get_company_profile`,且不把未声明层级的“企查查行业”猜测为一级/二级行业。
|
|
15
|
+
|
|
16
|
+
## [0.6.1] - 2026-09-04
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- 修复 DSH Code Mode 下同源 Web 路由直接调用动态 QCC 工具会被 ToolRuntime 拒绝的问题:新增
|
|
20
|
+
`data_cleaning_qcc_run` Agent-owned 高层工具,工作台仅在 Host 暂存明细并向原生会话发送不含企业
|
|
21
|
+
名单的 commandId;真实 QCC 调用以父执行 token/Session 的 nested execution 运行。
|
|
22
|
+
- 当宿主不提供工具注册能力时 fail closed,并在 capabilities 中报告
|
|
23
|
+
`agentCommandToolRegistered:false`,不会暂存或误执行付费任务。
|
|
24
|
+
- 历史任务恢复下载页改为读取 Host 持久化的匹配/补全摘要;进程重启后不再把已补全数和待核验数
|
|
25
|
+
显示为“—”。
|
|
26
|
+
|
|
27
|
+
### Verified
|
|
28
|
+
- DSH `0.1.1-rc.2` 真实连接环境完成一次且仅一次主体检索:唯一精确匹配
|
|
29
|
+
`企查查科技股份有限公司`(统一社会信用代码 `91320594088140947F`);未查询工商详情、未重试。
|
|
30
|
+
- 同一公开主体通过工作台完整执行 Agent-owned 批次:实际 2 次 QCC 调用,1/1 精确补全,回填
|
|
31
|
+
信用代码、法定代表人、注册资本、成立日期与登记状态;0 待核验、0 失败、无重试。
|
|
32
|
+
- 结果 CSV/XLSX 与异常清单 CSV/XLSX 四件套均生成成功,下载后 checksum 与 Host 元数据一致,
|
|
33
|
+
XLSX 结构校验通过;重启 DSH Host 后任务、统计和四件套仍可从任务历史恢复。
|
|
34
|
+
- `npm run check` 通过,174/174 自动化测试全绿。
|
|
35
|
+
|
|
7
36
|
## [0.6.0] - 2026-09-04
|
|
8
37
|
|
|
9
38
|
### Added
|
package/README.en.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 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.
|
|
4
4
|
>
|
|
5
|
-
> Current source version / 当前源码版本: **0.6.
|
|
5
|
+
> Current source version / 当前源码版本: **0.6.2** (stable release)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
|
@@ -78,7 +78,7 @@ Or let an agent install it for you:
|
|
|
78
78
|
| Skill | `data-cleaning` | guides the model through the workflow |
|
|
79
79
|
| QCC Skill enrichment | `enterprise-enrichment` | 0.4.0: company panorama, ownership, governance, and historical registration |
|
|
80
80
|
| 0.4.0 preflight | web `/data-cleaning/api/phase2/capabilities` | Read-only 16+4 dynamic-tool check; makes no QCC or paid calls |
|
|
81
|
-
| QCC Host Bridge | web `/data-cleaning/api/g5/*` |
|
|
81
|
+
| QCC Host Bridge | `data_cleaning_qcc_run` + web `/data-cleaning/api/g5/*` | Web stages commands in the Host; an Agent-owned high-level tool uses nested execution for dynamic QCC tools; real OAuth/QCC path, natural-expiry refresh, and fault injection verified |
|
|
82
82
|
| Three-domain enrichment | web `/data-cleaning/api/phase3/*` | 0.5.0: risk 38 + IPR 18 + operation 35, zero-call estimate, user-owned QCC quota confirmation, candidate review, recovery/retry, and two CSV exports (no domain expansion in 0.6.0) |
|
|
83
83
|
|
|
84
84
|
## Qichacha MCP enrichment (status and roadmap)
|
|
@@ -89,10 +89,12 @@ Besides local deterministic completion, the plugin supports Qichacha MCP enterpr
|
|
|
89
89
|
`qcc-dsh-mcp-oauth`, the Skill guides the model to call
|
|
90
90
|
`mcp__qcc-company__get_company_by_query` / `mcp__qcc-company__get_company_registration_info`
|
|
91
91
|
per company name and feed the fresh registration data back into the completion tool.
|
|
92
|
-
- **Plan B (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
- **Plan B (Agent-owned batch, since 0.4.0)**: in DSH Code Mode, the workbench stages rows in the
|
|
93
|
+
local Host and sends only a typed commandId intent, containing no company list, to the native
|
|
94
|
+
conversation. The Agent calls `data_cleaning_qcc_run` exactly once; the bridge then dispatches
|
|
95
|
+
dynamic QCC tools as nested executions using the parent execution token and Session. This path
|
|
96
|
+
supports batch enrichment, idempotency, candidate-resolution resume, manual retry of retryable
|
|
97
|
+
failures, and metadata-only auditing. Command staging requires `confirmPaidCalls:true`. The flag means the current user
|
|
96
98
|
confirms use of their own QCC account quota; it does not transfer the charge to the plugin maintainer.
|
|
97
99
|
Ambiguous candidates are never auto-selected. A loopback-only, fail-closed E2E runner is ready. On 2026-09-01 an isolated rc.2
|
|
98
100
|
Host passed real OAuth, restart recovery, and 400 QCC calls across 20 public companies. Natural-expiry
|
|
@@ -115,6 +117,10 @@ See [the Phase-3 acceptance record](docs/PHASE3-ACCEPTANCE.md) and
|
|
|
115
117
|
See [the 0.5.1 release record](docs/RELEASE-0.5.1.md) for the README fix and release-text gate.
|
|
116
118
|
See [the 0.5.2 release record](docs/RELEASE-0.5.2.md) for native DSH UI alignment, verification, and rollback.
|
|
117
119
|
See [the 0.5.3 release record](docs/RELEASE-0.5.3.md) for the business landing view and prompt builder.
|
|
120
|
+
See [the 0.6.2 release record](docs/RELEASE-0.6.2.md) for Chinese export headers,
|
|
121
|
+
complete field-selection propagation, and profile-field enrichment.
|
|
122
|
+
See [the 0.6.1 release record](docs/RELEASE-0.6.1.md) for the Agent-owned QCC workbench,
|
|
123
|
+
session isolation, recovered statistics, and real end-to-end validation.
|
|
118
124
|
See [the 0.6.0 release record](docs/RELEASE-0.6.0.md) for the taskId workflow, durable artifacts,
|
|
119
125
|
restart recovery, and dual-baseline validation.
|
|
120
126
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 在 DeepSeek Harness 中清洗、补全、画像企业名单数据的智能体插件:本地 CSV/XLSX/JSON 引擎 + 可选企查查(Qichacha/QCC)MCP 企业数据补全,由企查查(Qichacha/QCC)团队发起并维护。
|
|
4
4
|
>
|
|
5
|
-
> 当前源码版本 / Current source version: **0.6.
|
|
5
|
+
> 当前源码版本 / Current source version: **0.6.2**(正式版本)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
|
@@ -71,7 +71,7 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-data-cleaning-a
|
|
|
71
71
|
| Skill | `data-cleaning` | 引导模型按工作流调度上述工具 |
|
|
72
72
|
| 企查查 Skill 补全 | `enterprise-enrichment` | 0.4.0:工商全景、股权穿透与历史工商 |
|
|
73
73
|
| 0.4.0 工具预检 | web `/data-cleaning/api/phase2/capabilities` | 只读检查 16+4 动态工具,不发起 QCC/付费调用 |
|
|
74
|
-
| QCC Host Bridge | web `/data-cleaning/api/g5/*` |
|
|
74
|
+
| QCC Host Bridge | `data_cleaning_qcc_run` + web `/data-cleaning/api/g5/*` | Web 仅在 Host 暂存任务;Agent-owned 高层工具以 nested execution 调用动态 QCC 工具;真实 OAuth/QCC 主路径、自然到期刷新与故障注入均已验收 |
|
|
75
75
|
| 三域补全 | web `/data-cleaning/api/phase3/*` | 0.5.0:风险 38 + 知产 18 + 经营 35;零调用估算、显式付费确认、候选复核、恢复/重试与双 CSV 导出(当前按用户要求暂不扩展工具域) |
|
|
76
76
|
|
|
77
77
|
## 企查查 MCP 补全(状态与路线图)
|
|
@@ -83,9 +83,11 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-data-cleaning-a
|
|
|
83
83
|
`mcp__qcc-company__get_company_registration_info`,把返回的最新工商信息回填到补全工具。
|
|
84
84
|
0.4.0 已将 16 个工商工具和 4 个历史工商工具固化为可测契约,
|
|
85
85
|
按 `panorama` / `ownership` / `governance` / `history` 维度组按需调用;未显式选择时不会默认打满全部付费工具。
|
|
86
|
-
- **方案 B
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
- **方案 B(Agent-owned 批量,0.4.0 起)**:DSH Code Mode 下,工作台先把名单安全暂存在本机
|
|
87
|
+
Host,并只把不含企业名单的 commandId 类型化意图发送到原生会话;Agent 随后准确调用一次
|
|
88
|
+
`data_cleaning_qcc_run`,Bridge 使用该父执行的 token/Session 以 nested execution 调度动态 QCC 工具。
|
|
89
|
+
该路径实现批量补全、请求幂等、多候选人工确认续跑、retryable 失败人工重试与安全审计。
|
|
90
|
+
暂存命令前要求 `confirmPaidCalls:true`;该字段表示当前用户确认
|
|
89
91
|
使用自己的 QCC 账号额度,不代表插件开发者代客户付款;多候选绝不自动选择。
|
|
90
92
|
默认关闭的本机 E2E Runner 已就绪;2026-09-01 已在隔离 rc.2 Host 完成真实 OAuth、跨重启恢复和
|
|
91
93
|
20 家公开企业的 400 次 QCC 调用;自然过期 token 的真实刷新、动态工具恢复及 1 行续期后调用也已通过。
|
|
@@ -111,8 +113,10 @@ bash <(curl -fsSL https://raw.githubusercontent.com/duhu2000/dsh-data-cleaning-a
|
|
|
111
113
|
0.5.1 文档补丁与防回归发布门见 [docs/RELEASE-0.5.1.md](docs/RELEASE-0.5.1.md)。
|
|
112
114
|
0.5.2 DSH 原生 UI 对齐范围、验收与回滚见 [docs/RELEASE-0.5.2.md](docs/RELEASE-0.5.2.md)。
|
|
113
115
|
0.5.3 业务首页、提示词生成和输入框下方流程栏见 [docs/RELEASE-0.5.3.md](docs/RELEASE-0.5.3.md)。
|
|
114
|
-
0.6.
|
|
115
|
-
[docs/RELEASE-0.6.
|
|
116
|
+
0.6.2 中文导出表头、完整字段选择传递与画像字段补全见
|
|
117
|
+
[docs/RELEASE-0.6.2.md](docs/RELEASE-0.6.2.md)。0.6.1 Agent-owned QCC 工作台、会话隔离、恢复统计及真实闭环验收见
|
|
118
|
+
[docs/RELEASE-0.6.1.md](docs/RELEASE-0.6.1.md)。0.6.0 五步 taskId 工作流、耐久制品、
|
|
119
|
+
跨重启恢复与双基线验收见 [docs/RELEASE-0.6.0.md](docs/RELEASE-0.6.0.md)。
|
|
116
120
|
|
|
117
121
|
## 本地开发
|
|
118
122
|
|
package/docs/COMPATIBILITY.md
CHANGED
|
@@ -33,7 +33,7 @@ MVP 路由、Phase-3 capabilities、estimate 与未确认 enrich 阻断均通过
|
|
|
33
33
|
`conversation.createDraftImages` / `input.shell(sessionId).addImages` 做运行时探测,视为隔离兼容层,
|
|
34
34
|
不承诺 alpha 实验面稳定。
|
|
35
35
|
|
|
36
|
-
2026-09-04
|
|
36
|
+
2026-09-04 已发布的 0.6.0 v2 工作流在 rc.2(43190)与 alpha.2(43191)完成发布 tarball
|
|
37
37
|
隔离安装:两条基线均创建 `dc_workflows_v2` 任务与结果/异常 CSV+XLSX 四类制品,停止并重启 Host
|
|
38
38
|
后可按原 taskId 下载,XLSX 反向解析工作表为“清洗补全结果”。稳定发布判断仍以 rc.2 为主,
|
|
39
39
|
alpha.2 只作兼容探针。全程未触碰生产 43120,未调用 QCC。
|
|
@@ -56,7 +56,7 @@ alpha.2 只作兼容探针。全程未触碰生产 43120,未调用 QCC。
|
|
|
56
56
|
| 存储 | `ctx.storageDomain` | `open({name,version,tables})` → `table('jobs')` |
|
|
57
57
|
| web 路由 | `webServer.register({kind:'prefix', path, handler})` | 最长前缀匹配;前缀需以 `/` 结尾且匹配 `pathname.startsWith(prefix + '/')` |
|
|
58
58
|
| 同源守卫 | `isTrusted(req)` | `sec-fetch-site !== 'cross-site'` 且 origin 为 127.0.0.1/localhost |
|
|
59
|
-
|
|
|
59
|
+
| Agent-owned 动态工具调用 | `ctx.tools.register()` 高层工具 + `ctx.tools.get()` + 带 `parent/agent/rootCallId` 的 `ctx.tools.execute()` | rc.2 Code Mode 实测要求 nested execution;每次调用重新解析,不缓存动态 MCP 工具 |
|
|
60
60
|
|
|
61
61
|
## 4. 与企查查 MCP OAuth 插件的共存
|
|
62
62
|
|
|
@@ -72,8 +72,9 @@ alpha.2 只作兼容探针。全程未触碰生产 43120,未调用 QCC。
|
|
|
72
72
|
`mcp__qcc-company__*` / `mcp__qcc-risk__*`(授权成功后由 mcp-client 动态提供)。
|
|
73
73
|
- 若 qcc-dsh-mcp-oauth 未安装或未授权,`enterprise-enrichment` Skill 的第一步
|
|
74
74
|
`qcc_oauth_status` 即会中断并引导用户先连接,不会假装补全。
|
|
75
|
-
- G5 Host Bridge 不读取 grant/token,也不访问 mcp-client 私有 client
|
|
76
|
-
|
|
75
|
+
- G5 Host Bridge 不读取 grant/token,也不访问 mcp-client 私有 client。Web 路由只暂存已确认任务,
|
|
76
|
+
原生会话中的 `data_cleaning_qcc_run` 高层工具持有 Agent 父执行上下文,再经共享 `ctx.tools`
|
|
77
|
+
nested execution 调用动态注册的 `mcp__qcc-*` 工具。G5-2 增加幂等、候选续跑、人工重试与安全审计;
|
|
77
78
|
run 明细仅驻留 Host 内存。Bridge 会把 OAuth 0.1.7 的 legacy `mcp__company__*` / `mcp__history__*`
|
|
78
79
|
映射到规范名称,并在 capabilities 中同时报告两者。
|
|
79
80
|
- 0.5.0 三域 Bridge 同时兼容 `mcp__qcc-{risk,ipr,operation}__*`、OAuth 0.1.7 实测 legacy
|
|
@@ -107,11 +108,11 @@ Portal、原生会话、五能力按钮、跨 scope 状态桥、窄桌面布局
|
|
|
107
108
|
插件只做运行时能力探测并保留 `sessions.create` 安全降级,不承诺 alpha 实验面稳定。Portal 失败时
|
|
108
109
|
仍保留 footer 降级按钮。
|
|
109
110
|
|
|
110
|
-
0.5.3
|
|
111
|
+
0.5.3 新增业务首页和提示词生成器,并把流程栏移出输入框。0.6.0 v2 已在 rc.2 真实页面完成
|
|
111
112
|
浅色、深色及 820×900 窄屏回归;窄屏页面无横向溢出,最近完成任务可恢复原 taskId 并显示四个
|
|
112
113
|
Host 制品下载按钮。alpha.2 继续只检查 Host/路由/制品 Bridge,不作为精确视觉基线。
|
|
113
114
|
|
|
114
|
-
### 4.4
|
|
115
|
+
### 4.4 0.6.0 v2 制品兼容面(2026-09-04)
|
|
115
116
|
|
|
116
117
|
| 能力 | rc.2 | alpha.2 | 备注 |
|
|
117
118
|
| --- | --- | --- | --- |
|
package/docs/G5-HOST-BRIDGE.md
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
# G5 Host Bridge:方案 B 批量补全基础层
|
|
2
2
|
|
|
3
3
|
- 日期:2026-09-02
|
|
4
|
-
- 状态:**G5-2.1~G5-2.5、真实 OAuth/QCC 主路径、token 自然到期刷新与 401/429/配额故障注入已验收**
|
|
4
|
+
- 状态:**G5-2.1~G5-2.5、Agent-owned nested execution、真实 OAuth/QCC 主路径、token 自然到期刷新与 401/429/配额故障注入已验收**
|
|
5
5
|
- 发布状态:✅ 已随 `v0.4.0` 发布到 npm 与 GitHub Release
|
|
6
6
|
- 决策依据:`docs/adr/0002-programmatic-mcp-tool-execution.md`
|
|
7
7
|
|
|
8
8
|
## 本阶段交付
|
|
9
9
|
|
|
10
|
-
`lib/qcc.js`
|
|
10
|
+
`lib/qcc-command.js` 与 `lib/qcc.js` 基于 DSH 公共工具运行时实现 Host Bridge。2026-09-04
|
|
11
|
+
在真实 rc.2 Code Mode 验证发现:动态 MCP 工具必须作为 Agent-owned 父工具调用的 nested execution
|
|
12
|
+
运行,普通 Web handler 不能直接成为其父执行。因此正式 UI 路径采用「Host 暂存 + 类型化会话意图 +
|
|
13
|
+
高层工具」:
|
|
11
14
|
|
|
12
15
|
1. 仅允许 `qcc_oauth_*`、规范 `mcp__qcc-*__*` 与 OAuth 0.1.7 已验证 legacy serverName,拒绝任意工具代理。
|
|
13
16
|
2. 每次调用重新解析工具,兼容 OAuth 刷新造成的注销/重注册窗口;只对 `UNKNOWN_TOOL` 做一次安全重试,其他失败不自动重试,避免重复计费。
|
|
@@ -15,19 +18,26 @@
|
|
|
15
18
|
4. 解析 MCP `structuredContent` 或 QCC 文本 JSON,复用一期字段契约。
|
|
16
19
|
5. 批量输入按企业名去重调用;唯一精确主体才继续工商/风险补全,多候选进入 `reviewQueue`,未匹配保留为 `unresolved`。
|
|
17
20
|
6. 单企业失败隔离,不中断其他企业;原始/补全明细只在 Host/Web 同源边界内流转。
|
|
21
|
+
7. Web 暂存任务不产生 QCC 调用;发送给模型的提示只含 commandId/taskId/kind,不含企业名单和字段值。
|
|
22
|
+
8. `data_cleaning_qcc_run` 由 Agent 调用一次,并把父执行的 `token / agent / rootCallId` 传给每个
|
|
23
|
+
动态 QCC nested execution;重复调用同一 commandId 复用同一 Promise/结果,不重复计费。
|
|
18
24
|
|
|
19
25
|
## 数据流
|
|
20
26
|
|
|
21
27
|
```text
|
|
22
|
-
同源 Web
|
|
23
|
-
→
|
|
24
|
-
|
|
28
|
+
同源 Web 请求(显式确认使用当前用户自己的 QCC 额度)
|
|
29
|
+
→ Host 暂存 rows,返回不含 rows 的 commandId 类型化提示(零 QCC 调用)
|
|
30
|
+
→ 原生 conversation.send(prompt)
|
|
31
|
+
→ Agent 调用一次 data_cleaning_qcc_run(commandId)
|
|
32
|
+
→ QccHostBridge.enrichRows
|
|
33
|
+
→ 企业名去重 + 受控并发(1–4)
|
|
25
34
|
→ ctx.tools.get(每次重新解析)
|
|
26
|
-
→ ctx.tools.execute(
|
|
35
|
+
→ ctx.tools.execute(..., parent=exec.token, agent=exec.agent)
|
|
27
36
|
├─ 唯一精确 → 锁定信用代码 → 工商详情 → 可选风险扫描
|
|
28
37
|
├─ 多候选 → reviewQueue,停止该主体下游调用
|
|
29
38
|
└─ 未匹配 → unresolved
|
|
30
|
-
→
|
|
39
|
+
→ 高层工具只向对话返回摘要
|
|
40
|
+
→ 同源 UI 轮询 commandId,取得 Host run 明细并进入候选/补全/导出
|
|
31
41
|
```
|
|
32
42
|
|
|
33
43
|
## Web 契约
|
|
@@ -38,8 +48,21 @@
|
|
|
38
48
|
|
|
39
49
|
只检查工具是否注册,不调用 OAuth 或任何计费 QCC 工具。返回 Bridge marker、连接态推断和批量限制。
|
|
40
50
|
同时声明 `idempotencyRequired / candidateResume / manualRetry`,run 状态仅为 `host-memory`。
|
|
51
|
+
还会返回 `agentCommandTool / agentCommandToolRegistered / agentOwnedExecutionRequired`;若当前 Host
|
|
52
|
+
不支持工具注册,命令准备接口以 `503 QCC_AGENT_COMMAND_UNAVAILABLE` 关闭,不会产生 QCC 调用。
|
|
41
53
|
|
|
42
|
-
###
|
|
54
|
+
### Agent-owned 命令(正式工作台路径)
|
|
55
|
+
|
|
56
|
+
- `POST /data-cleaning/api/g5/commands`:要求 `confirmPaidCalls:true`,把 enrich/resolve/retry 输入暂存
|
|
57
|
+
在 Host;返回 commandId 与不含企业名单的可见会话提示,本步骤 `paidCalls:false`。
|
|
58
|
+
- `data_cleaning_qcc_run({commandId})`:只能在 Agent tool execution 内运行,缺少父执行 token/Session
|
|
59
|
+
时返回 `QCC_AGENT_EXECUTION_REQUIRED`。
|
|
60
|
+
- `GET /data-cleaning/api/g5/commands/<commandId>`:同源读取 prepared/running/completed/failed 和完成后的
|
|
61
|
+
Host run,不调用 QCC。
|
|
62
|
+
|
|
63
|
+
命令默认 30 分钟过期、最多 50 个;同一 commandId 在运行中和完成后都不会重复派发。
|
|
64
|
+
|
|
65
|
+
### 兼容批量端点(非 Code Mode UI 主路径)
|
|
43
66
|
|
|
44
67
|
`POST /data-cleaning/api/g5/enrich`
|
|
45
68
|
|
|
@@ -57,6 +80,9 @@
|
|
|
57
80
|
|
|
58
81
|
约束:
|
|
59
82
|
|
|
83
|
+
- 该端点保留给 Mock/Contract、Runner 与非 Code Mode 兼容场景;rc.2 Code Mode 的工作台不得用它
|
|
84
|
+
直接派发动态 QCC 工具,应使用上面的 Agent-owned 命令路径。
|
|
85
|
+
|
|
60
86
|
- `confirmPaidCalls` 必须严格为 `true`,否则在任何工具调用前返回 `QCC_CONFIRM_REQUIRED`。
|
|
61
87
|
- `idempotencyKey` 必填;相同键与相同请求复用首个结果,不重复调用工具;同键不同请求返回冲突。
|
|
62
88
|
- 单批最多 100 行,并发范围 1–4;重复企业只检索一次。
|
|
@@ -208,8 +208,10 @@ content:
|
|
|
208
208
|
## 9. 与方案 B 的边界与预留
|
|
209
209
|
|
|
210
210
|
- 方案 A 不改 `lib/`(最多可选加 `data_rows_to_csv` 工具)。
|
|
211
|
-
- 方案 B 已新增 `lib/qcc.js
|
|
212
|
-
|
|
211
|
+
- 方案 B 已新增 `lib/qcc.js` 与 `lib/qcc-command.js`:工作台通过同源 Web 路由把名单暂存在
|
|
212
|
+
Host,只向原生会话发送 commandId;`data_cleaning_qcc_run` 持有 Agent 父执行 token/Session 后,
|
|
213
|
+
才可通过公共 `ctx.tools.execute()` 以 nested execution 调度动态 MCP 工具。G5-2 幂等、候选续跑、
|
|
214
|
+
人工重试与安全 Runner 的 Mock/Contract 已通过。
|
|
213
215
|
禁止访问 mcp-client 私有 client;真实 OAuth/QCC 主路径已验收,token 到期刷新与
|
|
214
216
|
2026-09-02 已完成自然过期 token refresh 与 401/429/配额故障注入验收;
|
|
215
217
|
故障注入使用本地 ToolRuntime,不重复真实付费批次。
|
|
@@ -191,8 +191,9 @@ v1 字段契约(方案 A):
|
|
|
191
191
|
### 4.4 三期并行 · 方案 B 批量后端
|
|
192
192
|
|
|
193
193
|
一期/二期/三期均为模型中介式(模型逐个调 QCC 工具)。当名单规模进入百级/千级,模型逐调成本高,
|
|
194
|
-
方案 B 已启动:插件内 `lib/qcc.js`
|
|
195
|
-
|
|
194
|
+
方案 B 已启动:插件内 `lib/qcc-command.js` 注册 Agent-owned 高层工具,由 `lib/qcc.js` 使用父执行
|
|
195
|
+
token/Session,经公共 `ctx.tools.execute()` 以 nested execution 调用 mcp-client 动态注册的工具;
|
|
196
|
+
Web 路由只暂存任务,不直接派发动态 QCC 工具,也不访问 `ctx.loader` 条目或 mcp-client 私有 client。
|
|
196
197
|
|
|
197
198
|
- Spike #7:rc.2 / alpha.2 双基线 PASS。
|
|
198
199
|
- G5-2:在 G5-1 基础上完成默认关闭 E2E Runner、脱敏、请求幂等、多候选确认续跑、
|
package/docs/RELEASE-0.6.0.md
CHANGED
|
@@ -41,6 +41,17 @@
|
|
|
41
41
|
|
|
42
42
|
## 外部发布核验
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
- PR [#1](https://github.com/duhu2000/dsh-data-cleaning-agent/pull/1) 全部 CI 通过后合并;
|
|
45
|
+
`v0.6.0` 指向合并提交 `084efd0`。
|
|
46
|
+
- Release workflow [33817341580](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/runs/33817341580)
|
|
47
|
+
全绿,npm OIDC publish 与 GitHub Release 两个发布步骤均成功。
|
|
48
|
+
- npm `latest` 为 `0.6.0`;发布时间为 2026-09-03T23:23:12Z(北京时间 2026-09-04 07:23)。
|
|
49
|
+
- tarball SHA-1:`559db5f3de6ef799b0d7549d0bebb144e8cfb91d`。
|
|
50
|
+
- tarball integrity:
|
|
51
|
+
`sha512-ib83dgrBNnubouISvnzJb/zbjuBnJXEuee/fVgSzlZZcZLdA/5aB8fb4YF0L+DmOINIJfb44akUMBnBajv7lVg==`。
|
|
52
|
+
- npm Registry 返回 SLSA v1 provenance attestation;隔离安装后的 `npm audit signatures` 验证
|
|
53
|
+
10 个 Registry 签名和 1 个 attestation。
|
|
54
|
+
- 从公共 Registry 全新安装 `dsh-data-cleaning-agent@0.6.0` 成功;包版本、五步工作流契约和
|
|
55
|
+
`WorkflowArtifactStore` 导入验证通过。
|
|
56
|
+
- GitHub Release [v0.6.0](https://github.com/duhu2000/dsh-data-cleaning-agent/releases/tag/v0.6.0)
|
|
57
|
+
已发布,非 draft、非 prerelease。
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 0.6.1 Agent-owned QCC 工作台修复发布记录
|
|
2
|
+
|
|
3
|
+
> 版本:**0.6.1**
|
|
4
|
+
> 发布日期:2026-09-04
|
|
5
|
+
> 发布来源:`v0.6.1` Tag 触发 GitHub Actions,使用 npm OIDC Trusted Publishing。
|
|
6
|
+
|
|
7
|
+
## 目标
|
|
8
|
+
|
|
9
|
+
0.6.1 是 0.6.0 的兼容性补丁,不扩大企查查工具域,重点修复真实 DSH Code Mode 下的工作台调度和
|
|
10
|
+
多智能体共存:
|
|
11
|
+
|
|
12
|
+
1. Web 工作台只在 Host 暂存企业名单,并向原生会话发送不含明细的 commandId 类型化意图;
|
|
13
|
+
2. Agent 准确调用一次 `data_cleaning_qcc_run`,Bridge 使用父执行 token/Session,以 nested execution
|
|
14
|
+
调用动态 QCC 工具;
|
|
15
|
+
3. 新会话及其它智能体入口默认不显示数据清洗补全内容,点击本插件入口后才进入独立业务子系统;
|
|
16
|
+
4. 本地清洗任务跳过 QCC 匹配页,统计卡只渲染可读标量;
|
|
17
|
+
5. Host 重启恢复任务时,下载页继续显示已补全数和待核验数。
|
|
18
|
+
|
|
19
|
+
## 兼容与安全
|
|
20
|
+
|
|
21
|
+
- 稳定发布基线仍为 DSH `0.1.1-rc.2`;`0.1.2-alpha.2` 只作兼容探针。
|
|
22
|
+
- 工作台命令缺少 Agent 父执行上下文时 fail closed,不从普通 Web handler 直接派发动态 QCC 工具。
|
|
23
|
+
- 暂存命令默认 30 分钟过期、最多 50 个;同一 commandId 重放复用同一 Promise/结果,不重复计费。
|
|
24
|
+
- 企业名单与字段值不进入可见提示词;OAuth token、QCC 原始响应和凭据不进入仓库或审计日志。
|
|
25
|
+
- QCC 继续采用 BYO 账号:客户使用自己的企查查 MCP 连接与额度,插件不共享 Key、不代付。
|
|
26
|
+
- 历史域、人员域和招投标域继续延期,本补丁不新增这些工具或权限依赖。
|
|
27
|
+
|
|
28
|
+
## 验收证据
|
|
29
|
+
|
|
30
|
+
- `npm run check` 全绿,174/174 自动化测试通过;
|
|
31
|
+
- npm dry-run 包全部命中白名单;
|
|
32
|
+
- PR #2 的 Linux Node 22、Linux Node 24、Windows Node 24 和 PR 打包检查均通过;
|
|
33
|
+
- DSH `0.1.1-rc.2` 真实工作台完成上传、映射、质量体检、零调用估算、额度确认、Agent-owned 调度、
|
|
34
|
+
主体定位、工商补全、结果回填与四件套导出;
|
|
35
|
+
- 公开主体批次实际 2 次 QCC 调用,1/1 精确补全、0 待核验、0 失败、无重试;
|
|
36
|
+
- 结果 CSV/XLSX 与异常清单 CSV/XLSX checksum 一致,XLSX 可反向解析;Host 重启后任务、统计和
|
|
37
|
+
四件套仍可从任务历史恢复。
|
|
38
|
+
|
|
39
|
+
## 升级与回滚
|
|
40
|
+
|
|
41
|
+
- 升级:安装 `dsh-data-cleaning-agent@0.6.1` 并完全重启 DSH。
|
|
42
|
+
- 回滚:重新安装 `dsh-data-cleaning-agent@0.6.0` 并完全重启 DSH。
|
|
43
|
+
- 本补丁不引入数据库迁移;回滚不会删除 `dc_workflows_v2` 或工作区耐久制品。
|
|
44
|
+
- 完整迁移说明见 `docs/UI-WORKFLOW-V2-MIGRATION.md`。
|
|
45
|
+
|
|
46
|
+
## 外部发布核验
|
|
47
|
+
|
|
48
|
+
- PR [#3](https://github.com/duhu2000/dsh-data-cleaning-agent/pull/3) 四项 CI 全绿后合并;
|
|
49
|
+
`v0.6.1` 指向合并提交 `77a19aa`。
|
|
50
|
+
- Release workflow [33880569564](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/runs/33880569564)
|
|
51
|
+
全绿;版本校验、发布模式门禁、npm OIDC publish 与 GitHub Release 均成功。
|
|
52
|
+
- npm `latest` 为 `0.6.1`;发布时间为 2026-09-04T13:53:39Z(北京时间 2026-09-04 21:53)。
|
|
53
|
+
- tarball SHA-1:`ab9aaff6738e3ede08768138bc7a9000ccc28ed2`。
|
|
54
|
+
- tarball integrity:
|
|
55
|
+
`sha512-VWsVelLCxpGYDZ1TZrxlZWLGC86IjtOJDZAszukCs5LaPwkos8UcJn0IWmYtdKF7S3a8TsQGN1KhOhDL0OCHFw==`。
|
|
56
|
+
- npm Registry 返回 SLSA v1 provenance;隔离安装后的 `npm audit signatures` 验证 10 个 Registry
|
|
57
|
+
签名和 1 个 attestation。
|
|
58
|
+
- 从公共 Registry 全新安装成功;包版本为 0.6.1,主入口可导入,浏览器 client 语法门通过,
|
|
59
|
+
`lib/qcc-command.js` 与本发布记录均存在。
|
|
60
|
+
- DSH `0.1.1-rc.2` 全新隔离 Profile 安装 `dsh-data-cleaning-agent@0.6.1` 成功并加载 Host 插件。
|
|
61
|
+
第二个临时 Web Host 因本机全局文件监听资源耗尽(`EMFILE`)未完成 HTTP seam;未停止或改动用户
|
|
62
|
+
正在运行的 3080 实例。真实工作台闭环证据见上方「验收证据」。
|
|
63
|
+
- GitHub Release [v0.6.1](https://github.com/duhu2000/dsh-data-cleaning-agent/releases/tag/v0.6.1)
|
|
64
|
+
已发布,为 Latest,非 draft、非 prerelease。
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 0.6.2 中文字段导出与完整补全字段修复
|
|
2
|
+
|
|
3
|
+
> 版本:**0.6.2**
|
|
4
|
+
> 发布日期:2026-09-04
|
|
5
|
+
> 发布来源:`v0.6.2` Tag 触发 GitHub Actions,使用 npm OIDC Trusted Publishing。
|
|
6
|
+
|
|
7
|
+
## 目标
|
|
8
|
+
|
|
9
|
+
0.6.2 是 0.6.1 的结果正确性补丁,不扩大企查查工具域,修复真实任务中结果 XLSX 仅出现少量
|
|
10
|
+
英文字段的问题:
|
|
11
|
+
|
|
12
|
+
1. 任务选中的补全维度贯穿工作台、Agent-owned 命令、G5 Host Bridge、恢复/重试与耐久制品;
|
|
13
|
+
2. CSV/XLSX 的插件补全字段和系统状态字段统一使用中文表头;
|
|
14
|
+
3. 即使企查查未返回某个已选字段,结果文件也保留对应中文空列,不再静默丢列;
|
|
15
|
+
4. 工商工具补充注册地址、行政区划、经营范围、行业、营业期限和企业规模映射;
|
|
16
|
+
5. 企业简介及明确的一/二级行业字段按需调用 `get_company_profile`;未声明层级的“企查查行业”
|
|
17
|
+
不会被猜测填入一级或二级行业。
|
|
18
|
+
|
|
19
|
+
## 兼容与调用边界
|
|
20
|
+
|
|
21
|
+
- 稳定发布基线仍为 DSH `0.1.1-rc.2`;`0.1.2-alpha.2` 继续通过隔离 Bridge 兼容。
|
|
22
|
+
- 只有选择企业简介、一级行业或二级行业时才增加企业画像调用,工作台调用估算同步调整。
|
|
23
|
+
- QCC 继续采用 BYO 账号;插件不内置、不记录也不发布 OAuth token 或客户 Key。
|
|
24
|
+
- 历史域、人员域和招投标域仍按既定范围延期,本补丁不新增相关工具。
|
|
25
|
+
|
|
26
|
+
## 验收
|
|
27
|
+
|
|
28
|
+
- 14 个目标维度按选择顺序完整进入结果数据和导出制品;
|
|
29
|
+
- CSV/XLSX 表头为统一社会信用代码、登记状态、法定代表人、注册资本、成立日期、注册地址、
|
|
30
|
+
省份地区、城市、经营范围、一级行业、二级行业、营业期限、企业规模、企业简介;
|
|
31
|
+
- 画像接口未明确返回层级时,一/二级行业保留空值而不是生成数据;
|
|
32
|
+
- 未选择风险能力时不额外输出风险标签;
|
|
33
|
+
- `npm run check` 全绿,176/176 自动化测试通过,npm dry-run 包内容命中白名单。
|
|
34
|
+
|
|
35
|
+
## 升级与回滚
|
|
36
|
+
|
|
37
|
+
- 升级:安装 `dsh-data-cleaning-agent@0.6.2` 并完全重启 DSH。
|
|
38
|
+
- 回滚:重新安装 `dsh-data-cleaning-agent@0.6.1` 并完全重启 DSH。
|
|
39
|
+
- 本补丁不修改 `dc_workflows_v2` 存储 schema,也不删除既有任务或工作区耐久制品。
|
|
40
|
+
- 0.6.1 已生成的旧 XLSX 不会被自动重写;升级后重新生成制品即可获得中文完整表头。
|
package/docs/UI-WORKFLOW-V2.md
CHANGED
|
@@ -130,7 +130,7 @@ draft → uploaded → rules_confirmed → diagnosed(可选)
|
|
|
130
130
|
| T6 | rc.2 深色、浅色、820×900 窄屏无横向溢出 | 真实浏览器通过 |
|
|
131
131
|
| T7 | 多候选人工核验、`partial` 显式重试、补全后回到 `export_ready` | 自动化覆盖 |
|
|
132
132
|
| T8 | 最近任务携带原 taskId 恢复、无原始 runtime 行时下载四类 Host 制品 | 自动化 + rc.2 浏览器通过 |
|
|
133
|
-
| T9 | 迁移/回滚、兼容矩阵、发布检查和版本决策 |
|
|
133
|
+
| T9 | 迁移/回滚、兼容矩阵、发布检查和版本决策 | 文档完成;0.6.0 已发布并完成公共安装核验 |
|
|
134
134
|
|
|
135
135
|
### 真实 Host 证据(2026-09-03)
|
|
136
136
|
|
|
@@ -167,8 +167,7 @@ draft → uploaded → rules_confirmed → diagnosed(可选)
|
|
|
167
167
|
4. T6(完成):Host 耐久下载制品、XLSX 与异常清单、双基线、视觉回归、迁移与回滚。
|
|
168
168
|
5. T7(完成):候选人工核验、部分失败重试、匹配与补全状态闭环。
|
|
169
169
|
6. T8(完成):四类制品导出、最近任务恢复及跨 Host 重启下载。
|
|
170
|
-
7. T9
|
|
171
|
-
Tag、npm 和 GitHub Release。
|
|
170
|
+
7. T9(完成):`0.6.0` 已完成代码审查、合并、Tag、npm OIDC 发布、GitHub Release 与公共安装核验。
|
|
172
171
|
|
|
173
172
|
详细验收见 `docs/UI-WORKFLOW-V2-ACCEPTANCE.md`,升级/回滚见
|
|
174
173
|
`docs/UI-WORKFLOW-V2-MIGRATION.md`。
|
package/lib/artifacts.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { createHash, randomUUID } from 'node:crypto';
|
|
9
9
|
import XLSX from 'xlsx';
|
|
10
|
+
import { FIELD_LABELS, normalizeFieldSelection } from './workflow-contract.js';
|
|
10
11
|
|
|
11
12
|
const ROOT = '.dsh-data-cleaning-artifacts/v1';
|
|
12
13
|
const MAX_ARTIFACT_BYTES = 32 * 1024 * 1024;
|
|
@@ -15,6 +16,17 @@ const MAX_ARTIFACT_BYTES = 32 * 1024 * 1024;
|
|
|
15
16
|
const MAX_STORED_BYTES = Math.ceil(MAX_ARTIFACT_BYTES / 3) * 4 + 4;
|
|
16
17
|
const SAFE_ID = /^(?:dcw|dca)-[a-zA-Z0-9-]{8,80}$/;
|
|
17
18
|
|
|
19
|
+
const SYSTEM_FIELD_LABELS = Object.freeze({
|
|
20
|
+
biz_status: '经营状态',
|
|
21
|
+
risk_tags: '风险标签',
|
|
22
|
+
qcc_match_status: '匹配状态',
|
|
23
|
+
qcc_source: '数据来源',
|
|
24
|
+
qcc_error: '错误原因',
|
|
25
|
+
match_status: '匹配状态',
|
|
26
|
+
error: '错误原因',
|
|
27
|
+
_exception_reason: '异常原因',
|
|
28
|
+
});
|
|
29
|
+
|
|
18
30
|
export class ArtifactError extends Error {
|
|
19
31
|
constructor(code, message, status = 400) {
|
|
20
32
|
super(message);
|
|
@@ -44,10 +56,11 @@ function sha256(buffer) {
|
|
|
44
56
|
return createHash('sha256').update(buffer).digest('hex');
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
function normalizeHeaders(headers, rows) {
|
|
59
|
+
function normalizeHeaders(headers, rows, fieldSelection = []) {
|
|
48
60
|
const fromInput = Array.isArray(headers) ? headers.map((item) => String(item ?? '').trim()).filter(Boolean) : [];
|
|
61
|
+
const selected = normalizeFieldSelection(fieldSelection);
|
|
49
62
|
const discovered = [];
|
|
50
|
-
const seen = new Set(fromInput);
|
|
63
|
+
const seen = new Set([...fromInput, ...selected]);
|
|
51
64
|
for (const row of rows) {
|
|
52
65
|
for (const key of Object.keys(row ?? {})) {
|
|
53
66
|
if (!seen.has(key)) {
|
|
@@ -56,7 +69,27 @@ function normalizeHeaders(headers, rows) {
|
|
|
56
69
|
}
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
|
-
return [...fromInput, ...discovered].slice(0, 256);
|
|
72
|
+
return [...fromInput, ...selected.filter((field) => !fromInput.includes(field)), ...discovered].slice(0, 256);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function exportLabel(key) {
|
|
76
|
+
return FIELD_LABELS[key] ?? SYSTEM_FIELD_LABELS[key] ?? key;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function exportColumns(headers) {
|
|
80
|
+
const used = new Set();
|
|
81
|
+
return headers.map((key) => {
|
|
82
|
+
const base = exportLabel(key);
|
|
83
|
+
let label = base;
|
|
84
|
+
if (used.has(label)) {
|
|
85
|
+
const suffix = FIELD_LABELS[key] || SYSTEM_FIELD_LABELS[key] ? '(补全)' : '(原字段)';
|
|
86
|
+
label = `${base}${suffix}`;
|
|
87
|
+
let index = 2;
|
|
88
|
+
while (used.has(label)) label = `${base}${suffix.slice(0, -1)}${index++})`;
|
|
89
|
+
}
|
|
90
|
+
used.add(label);
|
|
91
|
+
return { key, label };
|
|
92
|
+
});
|
|
60
93
|
}
|
|
61
94
|
|
|
62
95
|
function normalizeRows(value) {
|
|
@@ -104,8 +137,13 @@ export function deriveExceptionRows(rows) {
|
|
|
104
137
|
|
|
105
138
|
function workbookBytes(rows, headers, sheetName) {
|
|
106
139
|
const workbook = XLSX.utils.book_new();
|
|
107
|
-
const
|
|
108
|
-
|
|
140
|
+
const columns = exportColumns(headers);
|
|
141
|
+
const values = [
|
|
142
|
+
columns.map((column) => column.label),
|
|
143
|
+
...rows.map((row) => columns.map((column) => row?.[column.key] ?? '')),
|
|
144
|
+
];
|
|
145
|
+
const worksheet = XLSX.utils.aoa_to_sheet(values);
|
|
146
|
+
worksheet['!cols'] = columns.map((column) => ({ wch: Math.min(42, Math.max(12, String(column.label).length * 2 + 4)) }));
|
|
109
147
|
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName.slice(0, 31));
|
|
110
148
|
workbook.Props = {
|
|
111
149
|
Title: sheetName,
|
|
@@ -129,9 +167,10 @@ function csvBytes(rows, headers) {
|
|
|
129
167
|
if (/^[\u0009\u000d\u000a ]*[=+\-@]/.test(text)) text = `'${text}`;
|
|
130
168
|
return /[",\r\n]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
|
|
131
169
|
};
|
|
170
|
+
const columns = exportColumns(headers);
|
|
132
171
|
const lines = [
|
|
133
|
-
|
|
134
|
-
...rows.map((row) =>
|
|
172
|
+
columns.map((column) => escapeCell(column.label)).join(','),
|
|
173
|
+
...rows.map((row) => columns.map((column) => escapeCell(row?.[column.key])).join(',')),
|
|
135
174
|
];
|
|
136
175
|
return Buffer.from(`\uFEFF${lines.join('\r\n')}`, 'utf8');
|
|
137
176
|
}
|
|
@@ -180,7 +219,7 @@ export class WorkflowArtifactStore {
|
|
|
180
219
|
async createBundle(taskId, input = {}) {
|
|
181
220
|
assertId(taskId, 'taskId');
|
|
182
221
|
const rows = normalizeRows(input.rows);
|
|
183
|
-
const headers = normalizeHeaders(input.headers, rows);
|
|
222
|
+
const headers = normalizeHeaders(input.headers, rows, input.fieldSelection);
|
|
184
223
|
if (!headers.length) throw new ArtifactError('DC_ARTIFACT_HEADERS_REQUIRED', 'At least one export column is required.', 400);
|
|
185
224
|
const exceptions = input.exceptionRows === undefined
|
|
186
225
|
? deriveExceptionRows(rows)
|