@liuhange/dsh-generate-registration-docs 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/lib/__tests__/docGenerator.test.js +59 -0
- package/lib/docGenerator.js +112 -0
- package/lib/docPackager.js +22 -0
- package/lib/index.js +59 -0
- package/lib/types/__tests__/docGenerator.test.d.ts +2 -0
- package/lib/types/docGenerator.d.ts +12 -0
- package/lib/types/docPackager.d.ts +5 -0
- package/lib/types/index.d.ts +5 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @liuhange/dsh-generate-registration-docs
|
|
2
|
+
|
|
3
|
+
登记材料生成插件:根据体检报告自动生成国家登记系统所需的申请材料。
|
|
4
|
+
|
|
5
|
+
## 功能说明
|
|
6
|
+
|
|
7
|
+
生成三份登记申请材料:
|
|
8
|
+
1. 《数据描述》:从盘点报告和包装说明书提取数据集基本信息
|
|
9
|
+
2. 《来源合法性声明》:从脱敏报告提取来源声明
|
|
10
|
+
3. 《产权归属说明》:基于三权分置(持有权/加工使用权/经营权)
|
|
11
|
+
|
|
12
|
+
## 依赖
|
|
13
|
+
|
|
14
|
+
- `@liuhange/dsh-data-asset-shared: ^3.0.0`
|
|
15
|
+
- `@deepseek-ai/cordis: ^4.0.0`
|
|
16
|
+
- `@deepseek-ai/dsh-tools: 0.0.1-rc.1`
|
|
17
|
+
|
|
18
|
+
## 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @liuhange/dsh-generate-registration-docs
|
|
22
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { DocGenerator } from '../docGenerator.js';
|
|
3
|
+
const validResult = {
|
|
4
|
+
maskingReport: '脱敏报告,来源合法,合规声明',
|
|
5
|
+
cleaningReport: '清洗报告',
|
|
6
|
+
inventoryReport: '盘点报告,记录数:1000',
|
|
7
|
+
packagingManual: '产品名称:测试数据产品\n格式:csv',
|
|
8
|
+
completedStages: 4,
|
|
9
|
+
};
|
|
10
|
+
const fullOwnership = {
|
|
11
|
+
holder: '某公司',
|
|
12
|
+
processor: '某公司技术部',
|
|
13
|
+
operator: '某公司数据部',
|
|
14
|
+
hasDispute: false,
|
|
15
|
+
confirmedAt: '2026-09-12T10:00:00Z',
|
|
16
|
+
};
|
|
17
|
+
describe('DocGenerator', () => {
|
|
18
|
+
const generator = new DocGenerator();
|
|
19
|
+
it('预检通过 → 生成三份材料', () => {
|
|
20
|
+
const docs = generator.generate(validResult, fullOwnership);
|
|
21
|
+
expect(docs).toHaveLength(3);
|
|
22
|
+
expect(docs.map(d => d.name)).toEqual([
|
|
23
|
+
'DATA_DESCRIPTION',
|
|
24
|
+
'SOURCE_LEGALITY_STATEMENT',
|
|
25
|
+
'OWNERSHIP_EXPLANATION',
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
it('字段缺失 → 标注"待企业补充"', () => {
|
|
29
|
+
const incomplete = {
|
|
30
|
+
...validResult,
|
|
31
|
+
inventoryReport: '无记录数信息',
|
|
32
|
+
packagingManual: '无产品名称',
|
|
33
|
+
};
|
|
34
|
+
const docs = generator.generate(incomplete, fullOwnership);
|
|
35
|
+
const dataDesc = docs.find(d => d.name === 'DATA_DESCRIPTION');
|
|
36
|
+
expect(dataDesc?.status).toBe('PENDING_FIELDS');
|
|
37
|
+
expect(dataDesc?.missingFields).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
it('部分材料失败 → 保留已生成材料', () => {
|
|
40
|
+
const partialOwnership = {
|
|
41
|
+
holder: '',
|
|
42
|
+
processor: '',
|
|
43
|
+
operator: '',
|
|
44
|
+
hasDispute: false,
|
|
45
|
+
confirmedAt: '2026-09-12T10:00:00Z',
|
|
46
|
+
};
|
|
47
|
+
const docs = generator.generate(validResult, partialOwnership);
|
|
48
|
+
const ownership = docs.find(d => d.name === 'OWNERSHIP_EXPLANATION');
|
|
49
|
+
expect(ownership?.status).toBe('PENDING_FIELDS');
|
|
50
|
+
expect(ownership?.missingFields).toContain('持有权主体');
|
|
51
|
+
});
|
|
52
|
+
it('材料含政策依据章节', () => {
|
|
53
|
+
const docs = generator.generate(validResult, fullOwnership);
|
|
54
|
+
for (const doc of docs) {
|
|
55
|
+
expect(doc.content).toContain('政策依据');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=docGenerator.test.js.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { PolicyReferenceResolver } from '@liuhange/dsh-data-asset-shared';
|
|
2
|
+
export class DocGenerator {
|
|
3
|
+
generate(orchestrationResult, ownership) {
|
|
4
|
+
const policyRefs = PolicyReferenceResolver.getInstance().resolve('DOC_GENERATION');
|
|
5
|
+
const docs = [];
|
|
6
|
+
docs.push(this.generateDataDescription(orchestrationResult, policyRefs));
|
|
7
|
+
docs.push(this.generateSourceLegalityStatement(orchestrationResult, policyRefs));
|
|
8
|
+
docs.push(this.generateOwnershipExplanation(ownership, policyRefs));
|
|
9
|
+
return docs;
|
|
10
|
+
}
|
|
11
|
+
generateDataDescription(result, policyRefs) {
|
|
12
|
+
const missingFields = [];
|
|
13
|
+
const inventoryMatch = result.inventoryReport.match(/记录数[::]\s*(\d+)/);
|
|
14
|
+
const formatMatch = result.packagingManual.match(/格式[::]\s*(\w+)/);
|
|
15
|
+
const nameMatch = result.packagingManual.match(/产品名称[::]\s*(.+)/);
|
|
16
|
+
const datasetName = nameMatch?.[1]?.trim() || '待企业填报';
|
|
17
|
+
const recordCount = inventoryMatch?.[1] || '待企业填报';
|
|
18
|
+
const format = formatMatch?.[1] || '待企业填报';
|
|
19
|
+
if (datasetName === '待企业填报')
|
|
20
|
+
missingFields.push('数据集名称');
|
|
21
|
+
if (recordCount === '待企业填报')
|
|
22
|
+
missingFields.push('记录数');
|
|
23
|
+
if (format === '待企业填报')
|
|
24
|
+
missingFields.push('数据格式');
|
|
25
|
+
const content = `# 数据描述
|
|
26
|
+
|
|
27
|
+
## 一、数据集基本信息
|
|
28
|
+
- 数据集名称:${datasetName}
|
|
29
|
+
- 数据记录数:${recordCount}
|
|
30
|
+
- 数据格式:${format}
|
|
31
|
+
- 内容概述:${result.inventoryReport.substring(0, 200)}...
|
|
32
|
+
- 更新频率:待企业填报
|
|
33
|
+
|
|
34
|
+
## 二、数据内容说明
|
|
35
|
+
${result.packagingManual.substring(0, 500)}
|
|
36
|
+
|
|
37
|
+
## 三、政策依据
|
|
38
|
+
${policyRefs.map(d => `- 《${d.name}》(${d.docNumber})`).join('\n')}
|
|
39
|
+
`;
|
|
40
|
+
return {
|
|
41
|
+
name: 'DATA_DESCRIPTION',
|
|
42
|
+
label: '数据描述',
|
|
43
|
+
content,
|
|
44
|
+
status: missingFields.length > 0 ? 'PENDING_FIELDS' : 'GENERATED',
|
|
45
|
+
...(missingFields.length > 0 ? { missingFields } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
generateSourceLegalityStatement(result, policyRefs) {
|
|
49
|
+
const hasSourceInfo = result.maskingReport.includes('来源') || result.maskingReport.includes('合规');
|
|
50
|
+
const content = `# 来源合法性声明
|
|
51
|
+
|
|
52
|
+
## 声明内容
|
|
53
|
+
本数据集来源合法,数据获取方式符合相关法律法规规定。
|
|
54
|
+
|
|
55
|
+
## 脱敏处理说明
|
|
56
|
+
${result.maskingReport.substring(0, 300)}
|
|
57
|
+
|
|
58
|
+
## 来源合规依据
|
|
59
|
+
${hasSourceInfo ? '脱敏报告中已包含来源合法性声明' : '待企业补充来源合法性证明材料'}
|
|
60
|
+
|
|
61
|
+
## 政策依据
|
|
62
|
+
${policyRefs.map(d => `- 《${d.name}》(${d.docNumber})`).join('\n')}
|
|
63
|
+
`;
|
|
64
|
+
return {
|
|
65
|
+
name: 'SOURCE_LEGALITY_STATEMENT',
|
|
66
|
+
label: '来源合法性声明',
|
|
67
|
+
content,
|
|
68
|
+
status: hasSourceInfo ? 'GENERATED' : 'PENDING_FIELDS',
|
|
69
|
+
...(!hasSourceInfo ? { missingFields: ['来源合法性证明材料'] } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
generateOwnershipExplanation(ownership, policyRefs) {
|
|
73
|
+
const missingFields = [];
|
|
74
|
+
if (!ownership.holder)
|
|
75
|
+
missingFields.push('持有权主体');
|
|
76
|
+
if (!ownership.processor)
|
|
77
|
+
missingFields.push('加工使用权主体');
|
|
78
|
+
if (!ownership.operator)
|
|
79
|
+
missingFields.push('经营权主体');
|
|
80
|
+
const content = `# 产权归属说明
|
|
81
|
+
|
|
82
|
+
## 一、数据产权三权分置
|
|
83
|
+
|
|
84
|
+
### 1. 持有权
|
|
85
|
+
- 权利主体:${ownership.holder || '待企业填报'}
|
|
86
|
+
- 权利内容:对数据资源的持有、控制和支配
|
|
87
|
+
|
|
88
|
+
### 2. 加工使用权
|
|
89
|
+
- 权利主体:${ownership.processor || '待企业填报'}
|
|
90
|
+
- 权利内容:对数据资源进行加工、使用和获益
|
|
91
|
+
|
|
92
|
+
### 3. 经营权
|
|
93
|
+
- 权利主体:${ownership.operator || '待企业填报'}
|
|
94
|
+
- 权利内容:对数据产品进行经营、交易和处分
|
|
95
|
+
|
|
96
|
+
## 二、权属确认
|
|
97
|
+
- 确认不存在权属纠纷
|
|
98
|
+
- 确认数据来源合法
|
|
99
|
+
|
|
100
|
+
## 三、政策依据
|
|
101
|
+
${policyRefs.map(d => `- 《${d.name}》(${d.docNumber})`).join('\n')}
|
|
102
|
+
`;
|
|
103
|
+
return {
|
|
104
|
+
name: 'OWNERSHIP_EXPLANATION',
|
|
105
|
+
label: '产权归属说明',
|
|
106
|
+
content,
|
|
107
|
+
status: missingFields.length > 0 ? 'PENDING_FIELDS' : 'GENERATED',
|
|
108
|
+
...(missingFields.length > 0 ? { missingFields } : {}),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=docGenerator.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { PolicyReferenceResolver } from '@liuhange/dsh-data-asset-shared';
|
|
4
|
+
export class DocPackager {
|
|
5
|
+
async package(docs) {
|
|
6
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
7
|
+
const packageDir = path.resolve(process.cwd(), 'output', `registration-docs-${timestamp}`);
|
|
8
|
+
fs.mkdirSync(packageDir, { recursive: true });
|
|
9
|
+
for (const doc of docs) {
|
|
10
|
+
const fileName = `${doc.label}.txt`;
|
|
11
|
+
fs.writeFileSync(path.join(packageDir, fileName), doc.content, 'utf-8');
|
|
12
|
+
}
|
|
13
|
+
const policyRefs = PolicyReferenceResolver.getInstance().resolve('DOC_GENERATION');
|
|
14
|
+
return {
|
|
15
|
+
docs,
|
|
16
|
+
packagePath: packageDir,
|
|
17
|
+
policyReferences: policyRefs,
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=docPackager.js.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
2
|
+
import { AuditLogger, } from '@liuhange/dsh-data-asset-shared';
|
|
3
|
+
import { DocGenerator } from './docGenerator.js';
|
|
4
|
+
import { DocPackager } from './docPackager.js';
|
|
5
|
+
export const name = 'generate-registration-docs';
|
|
6
|
+
export const inject = ['tools'];
|
|
7
|
+
export function apply(ctx) {
|
|
8
|
+
const auditLogger = new AuditLogger();
|
|
9
|
+
const docGenerator = new DocGenerator();
|
|
10
|
+
const docPackager = new DocPackager();
|
|
11
|
+
ctx.tools.register(defineTool({
|
|
12
|
+
name: 'generate_registration_docs',
|
|
13
|
+
description: '根据体检报告自动生成国家登记系统所需的申请材料(《数据描述》《来源合法性声明》《产权归属说明》)',
|
|
14
|
+
parameters: {
|
|
15
|
+
orchestrationResult: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
required: true,
|
|
18
|
+
description: '体检全流程产物JSON',
|
|
19
|
+
},
|
|
20
|
+
precheckReport: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
required: true,
|
|
23
|
+
description: '登记预检报告JSON(结论须为 CAN_REGISTER)',
|
|
24
|
+
},
|
|
25
|
+
ownershipConfirmation: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
required: true,
|
|
28
|
+
description: '权属确认信息JSON',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
output: {
|
|
32
|
+
schema: { type: 'string' },
|
|
33
|
+
render: (_args, value) => [{ type: 'text', text: value }],
|
|
34
|
+
},
|
|
35
|
+
async execute(args) {
|
|
36
|
+
const orchestrationResult = JSON.parse(args.orchestrationResult);
|
|
37
|
+
const precheckReport = JSON.parse(args.precheckReport);
|
|
38
|
+
const ownershipConfirmation = JSON.parse(args.ownershipConfirmation);
|
|
39
|
+
if (precheckReport.conclusion !== 'CAN_REGISTER') {
|
|
40
|
+
return JSON.stringify({
|
|
41
|
+
error: '预检未通过,无法生成登记材料',
|
|
42
|
+
failedItems: precheckReport.failedItems,
|
|
43
|
+
}, null, 2);
|
|
44
|
+
}
|
|
45
|
+
const docs = docGenerator.generate(orchestrationResult, ownershipConfirmation);
|
|
46
|
+
const pkg = await docPackager.package(docs);
|
|
47
|
+
auditLogger.log({
|
|
48
|
+
pluginName: 'generate-registration-docs',
|
|
49
|
+
operation: 'generate_registration_docs',
|
|
50
|
+
inputPath: '-',
|
|
51
|
+
outputPath: pkg.packagePath,
|
|
52
|
+
result: 'SUCCESS',
|
|
53
|
+
});
|
|
54
|
+
return JSON.stringify(pkg, null, 2);
|
|
55
|
+
},
|
|
56
|
+
}));
|
|
57
|
+
console.log('[generate-registration-docs] 登记材料生成插件已加载');
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OrchestrationResult, RegistrationDoc } from '@liuhange/dsh-data-asset-shared';
|
|
2
|
+
export declare class DocGenerator {
|
|
3
|
+
generate(orchestrationResult: OrchestrationResult, ownership: {
|
|
4
|
+
holder: string;
|
|
5
|
+
processor: string;
|
|
6
|
+
operator: string;
|
|
7
|
+
}): RegistrationDoc[];
|
|
8
|
+
private generateDataDescription;
|
|
9
|
+
private generateSourceLegalityStatement;
|
|
10
|
+
private generateOwnershipExplanation;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=docGenerator.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@liuhange/dsh-generate-registration-docs",
|
|
3
|
+
"description": "Generate registration documents: data description, source legality statement, ownership explanation",
|
|
4
|
+
"version": "3.0.0",
|
|
5
|
+
"publishConfig": { "access": "public" },
|
|
6
|
+
"repository": { "type": "git", "url": "git+https://github.com/liuhange789/data-asset-inspector.git", "directory": "packages/data-asset/generate-registration-docs" },
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "lib/index.js",
|
|
9
|
+
"types": "lib/types/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": { "types": "./lib/types/index.d.ts", "default": "./lib/index.js" },
|
|
12
|
+
"./src/*": "./src/*",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": ["lib/**/*.js", "lib/types/**/*.d.ts"],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"build": "tsc"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@deepseek-ai/cordis": "^4.0.0",
|
|
24
|
+
"@deepseek-ai/dsh-tools": "0.0.1-rc.1",
|
|
25
|
+
"@liuhange/dsh-data-asset-shared": "^3.0.0"
|
|
26
|
+
},
|
|
27
|
+
"dsh": { "bundle": { "patch": true } }
|
|
28
|
+
}
|