@neobiotechlabs/neobiotech-dev-agent 0.1.7
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/.claude-plugin/marketplace.json +22 -0
- package/.claude-plugin/plugin.json +58 -0
- package/.mcp.json +14 -0
- package/README.md +442 -0
- package/dist/__tests__/adf.test.d.ts +1 -0
- package/dist/__tests__/adf.test.js +68 -0
- package/dist/__tests__/adf.test.js.map +1 -0
- package/dist/__tests__/annex-ii-template.test.d.ts +1 -0
- package/dist/__tests__/annex-ii-template.test.js +39 -0
- package/dist/__tests__/annex-ii-template.test.js.map +1 -0
- package/dist/__tests__/doc-render.test.d.ts +1 -0
- package/dist/__tests__/doc-render.test.js +93 -0
- package/dist/__tests__/doc-render.test.js.map +1 -0
- package/dist/__tests__/help.test.d.ts +1 -0
- package/dist/__tests__/help.test.js +31 -0
- package/dist/__tests__/help.test.js.map +1 -0
- package/dist/__tests__/jira-fields.test.d.ts +1 -0
- package/dist/__tests__/jira-fields.test.js +81 -0
- package/dist/__tests__/jira-fields.test.js.map +1 -0
- package/dist/__tests__/plugin-manifest.test.d.ts +1 -0
- package/dist/__tests__/plugin-manifest.test.js +91 -0
- package/dist/__tests__/plugin-manifest.test.js.map +1 -0
- package/dist/__tests__/setup.test.d.ts +1 -0
- package/dist/__tests__/setup.test.js +7 -0
- package/dist/__tests__/setup.test.js.map +1 -0
- package/dist/__tests__/sync-version.test.d.ts +1 -0
- package/dist/__tests__/sync-version.test.js +37 -0
- package/dist/__tests__/sync-version.test.js.map +1 -0
- package/dist/clients/risk-client.d.ts +17 -0
- package/dist/clients/risk-client.js +54 -0
- package/dist/clients/risk-client.js.map +1 -0
- package/dist/clients/xray-client.d.ts +34 -0
- package/dist/clients/xray-client.js +127 -0
- package/dist/clients/xray-client.js.map +1 -0
- package/dist/config/project-config.d.ts +14 -0
- package/dist/config/project-config.js +45 -0
- package/dist/config/project-config.js.map +1 -0
- package/dist/confluence-client.d.ts +16 -0
- package/dist/confluence-client.js +97 -0
- package/dist/confluence-client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/jira-client.d.ts +35 -0
- package/dist/jira-client.js +119 -0
- package/dist/jira-client.js.map +1 -0
- package/dist/tools/annex-ii-template.d.ts +30 -0
- package/dist/tools/annex-ii-template.js +129 -0
- package/dist/tools/annex-ii-template.js.map +1 -0
- package/dist/tools/confluence.d.ts +2 -0
- package/dist/tools/confluence.js +54 -0
- package/dist/tools/confluence.js.map +1 -0
- package/dist/tools/cvss.d.ts +2 -0
- package/dist/tools/cvss.js +59 -0
- package/dist/tools/cvss.js.map +1 -0
- package/dist/tools/doc-render.d.ts +2 -0
- package/dist/tools/doc-render.js +96 -0
- package/dist/tools/doc-render.js.map +1 -0
- package/dist/tools/doc-validation.d.ts +2 -0
- package/dist/tools/doc-validation.js +221 -0
- package/dist/tools/doc-validation.js.map +1 -0
- package/dist/tools/help-data.d.ts +7 -0
- package/dist/tools/help-data.js +144 -0
- package/dist/tools/help-data.js.map +1 -0
- package/dist/tools/help.d.ts +2 -0
- package/dist/tools/help.js +39 -0
- package/dist/tools/help.js.map +1 -0
- package/dist/tools/iec.d.ts +2 -0
- package/dist/tools/iec.js +203 -0
- package/dist/tools/iec.js.map +1 -0
- package/dist/tools/init.d.ts +2 -0
- package/dist/tools/init.js +38 -0
- package/dist/tools/init.js.map +1 -0
- package/dist/tools/jira-crud.d.ts +2 -0
- package/dist/tools/jira-crud.js +142 -0
- package/dist/tools/jira-crud.js.map +1 -0
- package/dist/tools/risk.d.ts +2 -0
- package/dist/tools/risk.js +172 -0
- package/dist/tools/risk.js.map +1 -0
- package/dist/tools/traceability.d.ts +2 -0
- package/dist/tools/traceability.js +85 -0
- package/dist/tools/traceability.js.map +1 -0
- package/dist/tools/types.d.ts +13 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/usability.d.ts +2 -0
- package/dist/tools/usability.js +149 -0
- package/dist/tools/usability.js.map +1 -0
- package/dist/tools/xray.d.ts +2 -0
- package/dist/tools/xray.js +35 -0
- package/dist/tools/xray.js.map +1 -0
- package/dist/utils/adf.d.ts +27 -0
- package/dist/utils/adf.js +104 -0
- package/dist/utils/adf.js.map +1 -0
- package/dist/utils/cvss.d.ts +15 -0
- package/dist/utils/cvss.js +86 -0
- package/dist/utils/cvss.js.map +1 -0
- package/dist/utils/doc-render.d.ts +28 -0
- package/dist/utils/doc-render.js +50 -0
- package/dist/utils/doc-render.js.map +1 -0
- package/dist/utils/jira-fields.d.ts +38 -0
- package/dist/utils/jira-fields.js +53 -0
- package/dist/utils/jira-fields.js.map +1 -0
- package/dist/utils/sync-version.d.ts +2 -0
- package/dist/utils/sync-version.js +20 -0
- package/dist/utils/sync-version.js.map +1 -0
- package/package.json +49 -0
- package/skills/doc-render/SKILL.md +79 -0
- package/vendor/dev-docs-templates/templates/dev_docs/plan_template.md +104 -0
- package/vendor/dev-docs-templates/templates/dev_docs/prd_template.md +110 -0
- package/vendor/dev-docs-templates/templates/dev_docs/spec_template.md +81 -0
- package/vendor/dev-docs-templates/templates/dev_docs/tasks_template.md +122 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/checklist-clinical-evaluation.md +81 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/checklist-gspr-mdr.md +403 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/clinical-evaluation-report.md +492 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/instructions-for-use.md +132 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/literature-evaluation-table.md +15 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/mdr-declaration-of-conformity.md +75 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/post-market-clinical-follow-up-plan.md +162 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/post-market-surveillance-plan.md +175 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/risk-management-cybersecurity-checklist.md +67 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/risk-management-report.md +111 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/CA/usability-evaluation-report.md +70 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/clinical-evaluation-plan.md +154 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/list-of-hazard-related-use-scenarios.md +34 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/risk-table-fmea.md +155 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/software-architecture-description.md +307 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/software-requirements-list.md +156 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/soup-list.md +82 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/EA/usability-evaluation-plan.md +103 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/global/bug-fixes-documentation-list.md +35 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/global/change-evaluation-list.md +100 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/global/list-of-known-anomalies.md +29 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/algorithm-validation-report.md +170 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/checklist-software-release.md +52 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/checklist-software-requirements-review.md +50 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/software-architecture-checklist.md +41 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/software-detailed-design.md +321 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/software-system-test-plan.md +155 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/ER/sprint/usability-evaluation-protocol.md +63 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/intended-use.md +116 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/mdr-classification-document.md +114 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/risk-management-plan.md +198 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/software-development-maintenance-plan.md +225 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/system-requirements-spec.md +182 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/information_security/information-security-controls.md +966 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/information_security/information-security-policy-and-scope.md +99 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/quality-manual-policy-objectives.md +187 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-capa.md +112 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-change-management.md +128 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-clinical-evaluation.md +102 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-feedback-management.md +140 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-integrated-software-development.md +361 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-post-market-surveillance.md +159 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/global/qms/sop-software-problem-resolution.md +99 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export const ANNEX_II_TEMPLATE = {
|
|
2
|
+
sections: [
|
|
3
|
+
{
|
|
4
|
+
id: 'device-description',
|
|
5
|
+
title: '1. 기기 설명 및 사양',
|
|
6
|
+
required: true,
|
|
7
|
+
description: '의료기기의 식별, 의도된 사용, 환자집단, 적응증, 임상적 이득',
|
|
8
|
+
matchKeywords: ['기기 설명', 'device description', 'Intended Use', '의도된 사용', '기기 사양', 'device specification'],
|
|
9
|
+
expectedSubTypes: ['Intended Use', 'System Requirement', 'Classification'],
|
|
10
|
+
requireApproval: true,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 'manufacturer-info',
|
|
14
|
+
title: '2. 제조자 정보',
|
|
15
|
+
required: true,
|
|
16
|
+
description: '제조자 명칭, 주소, 품질관리시스템, 수탁제조자 정보',
|
|
17
|
+
matchKeywords: ['제조자 정보', 'manufacturer information', '제조사 정보', 'manufacturer'],
|
|
18
|
+
requireApproval: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'design-manufacturing',
|
|
22
|
+
title: '3. 설계 및 제조 정보',
|
|
23
|
+
required: true,
|
|
24
|
+
description: '설계 입력/출력, 아키텍처, 상세설계, 제조공정, 형상관리',
|
|
25
|
+
matchKeywords: ['설계', '제조', 'design', 'manufacturing', 'Architecture', 'Detailed Design', 'SAD', 'SDD', 'SDS', '설계 및 제조 정보'],
|
|
26
|
+
expectedSubTypes: ['Architecture', 'Detailed Design'],
|
|
27
|
+
requireApproval: true,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'gspr',
|
|
31
|
+
title: '4. GSPR 준수성',
|
|
32
|
+
required: true,
|
|
33
|
+
description: 'MDR Annex I 일반안전성유효성요구사항(GSPR) 준수 증빙',
|
|
34
|
+
matchKeywords: ['GSPR', '일반안전성유효성', 'General Safety and Performance Requirements', 'Annex I', '안전성'],
|
|
35
|
+
requireApproval: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'risk-management',
|
|
39
|
+
title: '5. 리스크 관리',
|
|
40
|
+
required: true,
|
|
41
|
+
description: '리스크 관리 보고서, Hazard 식별, 완화조치, 리스크 평가',
|
|
42
|
+
matchKeywords: ['리스크 관리', 'Risk Management', 'Hazard', 'Risk Report', '위험성', '리스크'],
|
|
43
|
+
expectedSubTypes: ['Hazard', 'Requirement'],
|
|
44
|
+
requireApproval: true,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'verification-validation',
|
|
48
|
+
title: '6. 검증 및 검증 (V&V)',
|
|
49
|
+
required: true,
|
|
50
|
+
description: '테스트 계획, 테스트 결과, 검증 보고서, 유효성 확인',
|
|
51
|
+
matchKeywords: ['검증', 'V&V', 'Verification', 'Validation', '테스트', 'Test', 'V&V', 'verification and validation'],
|
|
52
|
+
expectedSubTypes: ['Test', 'Test Execution'],
|
|
53
|
+
requireApproval: true,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'usability',
|
|
57
|
+
title: '7. 사용성 공학',
|
|
58
|
+
required: true,
|
|
59
|
+
description: 'IEC 62366-1 준수 사용성 공학 보고서, Use Specification, 시나리오, 검증',
|
|
60
|
+
matchKeywords: ['사용성', 'Usability', 'Use Specification', 'IEC 62366', '사용자 인터페이스', '사용 시나리오', 'usability engineering'],
|
|
61
|
+
expectedSubTypes: ['Use Scenario', 'Use Specification', 'Usability Validation'],
|
|
62
|
+
requireApproval: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'pms',
|
|
66
|
+
title: '8. 시판후 감시 (PMS)',
|
|
67
|
+
required: true,
|
|
68
|
+
description: '시판후 감시 계획, 불만사항 처리, 현장안전정보시정조치(FSCA)',
|
|
69
|
+
matchKeywords: ['PMS', 'Post-Market Surveillance', '시판후 감시', 'post-market', '불만사항', 'FSCA'],
|
|
70
|
+
requireApproval: false,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'ce',
|
|
74
|
+
title: '9. CE 마킹 및 준수 선언',
|
|
75
|
+
required: true,
|
|
76
|
+
description: 'CE 마킹 적용, EU 준수 선언서(EC DoC), NB 심사 보고서',
|
|
77
|
+
matchKeywords: ['CE 마킹', 'CE marking', '준수 선언', 'Declaration of Conformity', 'EC DoC', 'NB', 'Notified Body', '인증'],
|
|
78
|
+
requireApproval: true,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
export function matchSection(summary) {
|
|
83
|
+
const lowerSummary = summary.toLowerCase();
|
|
84
|
+
for (const section of ANNEX_II_TEMPLATE.sections) {
|
|
85
|
+
for (const keyword of section.matchKeywords) {
|
|
86
|
+
if (lowerSummary.includes(keyword.toLowerCase())) {
|
|
87
|
+
return section;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
export function checkCompleteness(sections, tickets) {
|
|
94
|
+
const results = [];
|
|
95
|
+
for (const section of sections) {
|
|
96
|
+
const matchedTickets = tickets.filter(t => matchSection(t.summary)?.id === section.id);
|
|
97
|
+
if (matchedTickets.length === 0) {
|
|
98
|
+
results.push({
|
|
99
|
+
section,
|
|
100
|
+
status: 'missing',
|
|
101
|
+
tickets: [],
|
|
102
|
+
issues: [`필수 문서 누락: ${section.title}`],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const issues = [];
|
|
107
|
+
const completedTickets = matchedTickets.filter(t => t.status === 'Done' || t.status === 'Closed' || t.status === 'Approved');
|
|
108
|
+
if (section.requireApproval && completedTickets.length === 0) {
|
|
109
|
+
issues.push('승인 상태가 아님 (Done/Closed/Approved 필요)');
|
|
110
|
+
}
|
|
111
|
+
if (section.expectedSubTypes && section.expectedSubTypes.length > 0) {
|
|
112
|
+
const foundSubTypes = new Set(matchedTickets.map(t => t.issuetype));
|
|
113
|
+
for (const expected of section.expectedSubTypes) {
|
|
114
|
+
if (!foundSubTypes.has(expected)) {
|
|
115
|
+
issues.push(`예상된 하위 타입 누락: ${expected}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
results.push({
|
|
120
|
+
section,
|
|
121
|
+
status: issues.length > 0 ? 'incomplete' : 'found',
|
|
122
|
+
tickets: matchedTickets,
|
|
123
|
+
issues,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return results;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=annex-ii-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"annex-ii-template.js","sourceRoot":"","sources":["../../src/tools/annex-ii-template.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const registerConfluenceTools = (ctx) => {
|
|
3
|
+
const { server, confluence } = ctx;
|
|
4
|
+
server.tool('confluence_get_page', 'Get a Confluence page by ID', {
|
|
5
|
+
page_id: z.string().describe('Page ID'),
|
|
6
|
+
expand: z.array(z.string()).optional().describe('Fields to expand (e.g. body.storage, version)'),
|
|
7
|
+
}, async ({ page_id, expand }) => {
|
|
8
|
+
const data = await confluence.getPage(page_id, expand);
|
|
9
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
10
|
+
});
|
|
11
|
+
server.tool('confluence_search', 'Search Confluence pages with CQL', {
|
|
12
|
+
cql: z.string().describe('CQL query string'),
|
|
13
|
+
limit: z.number().optional().default(25).describe('Maximum results'),
|
|
14
|
+
}, async ({ cql, limit }) => {
|
|
15
|
+
const data = await confluence.search(cql, limit);
|
|
16
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
17
|
+
});
|
|
18
|
+
server.tool('confluence_create_page', 'Create a new Confluence page', {
|
|
19
|
+
space_key: z.string().describe('Space key (e.g. PROJ)'),
|
|
20
|
+
title: z.string().describe('Page title'),
|
|
21
|
+
body: z.string().describe('Page content in Confluence storage format (HTML)'),
|
|
22
|
+
parent_id: z.string().optional().describe('Parent page ID'),
|
|
23
|
+
}, async ({ space_key, title, body, parent_id }) => {
|
|
24
|
+
const data = await confluence.createPage(space_key, title, body, parent_id);
|
|
25
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
26
|
+
});
|
|
27
|
+
server.tool('confluence_update_page', 'Update an existing Confluence page', {
|
|
28
|
+
page_id: z.string().describe('Page ID'),
|
|
29
|
+
title: z.string().describe('Page title'),
|
|
30
|
+
body: z.string().describe('Page content in Confluence storage format (HTML)'),
|
|
31
|
+
version: z.number().describe('Current version number of the page'),
|
|
32
|
+
}, async ({ page_id, title, body, version }) => {
|
|
33
|
+
const data = await confluence.updatePage(page_id, title, body, version);
|
|
34
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
35
|
+
});
|
|
36
|
+
server.tool('confluence_delete_page', 'Delete a Confluence page', {
|
|
37
|
+
page_id: z.string().describe('Page ID'),
|
|
38
|
+
}, async ({ page_id }) => {
|
|
39
|
+
await confluence.deletePage(page_id);
|
|
40
|
+
return { content: [{ type: 'text', text: `Page ${page_id} deleted` }] };
|
|
41
|
+
});
|
|
42
|
+
server.tool('confluence_get_spaces', 'List available Confluence spaces', {}, async () => {
|
|
43
|
+
const data = await confluence.getSpaces();
|
|
44
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
45
|
+
});
|
|
46
|
+
server.tool('confluence_get_page_children', 'Get child pages of a Confluence page', {
|
|
47
|
+
page_id: z.string().describe('Parent page ID'),
|
|
48
|
+
limit: z.number().optional().default(25).describe('Maximum results'),
|
|
49
|
+
}, async ({ page_id, limit }) => {
|
|
50
|
+
const data = await confluence.getPageChildren(page_id, limit);
|
|
51
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=confluence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confluence.js","sourceRoot":"","sources":["../../src/tools/confluence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { calculateCvssScore, buildCvssVector, parseCvssVector, validateMetrics, METRIC_LABELS } from '../utils/cvss.js';
|
|
3
|
+
export const registerCvssTools = (ctx) => {
|
|
4
|
+
const { server, jira } = ctx;
|
|
5
|
+
server.tool('cvss_calculate', 'Calculate CVSS v4.0 score and severity from metric values', {
|
|
6
|
+
metrics: z.record(z.string()).describe('CVSS v4.0 metrics as key-value pairs (e.g. {"AV":"N","AC":"L","PR":"N","UI":"N","VC":"H","VI":"L","VA":"N","SC":"N","SI":"N","SA":"N"})'),
|
|
7
|
+
}, async ({ metrics }) => {
|
|
8
|
+
const errors = validateMetrics(metrics);
|
|
9
|
+
if (errors.length > 0) {
|
|
10
|
+
return { content: [{ type: 'text', text: `Validation errors:\n${errors.join('\n')}` }] };
|
|
11
|
+
}
|
|
12
|
+
const vector = buildCvssVector(metrics);
|
|
13
|
+
const { score, severity } = calculateCvssScore(metrics);
|
|
14
|
+
const details = Object.entries(metrics).map(([k, v]) => ` ${k} = ${v} (${METRIC_LABELS[k] || k})`).join('\n');
|
|
15
|
+
return { content: [{ type: 'text', text: `CVSS Vector: ${vector}\nScore: ${score} (${severity})\n\nMetrics:\n${details}` }] };
|
|
16
|
+
});
|
|
17
|
+
server.tool('cvss_set_vector', 'Set CVSS v4.0 vector and score on a Vulnerability ticket', {
|
|
18
|
+
issue_key: z.string().describe('Vulnerability issue key'),
|
|
19
|
+
metrics: z.record(z.string()).optional().describe('CVSS v4.0 metrics as key-value pairs'),
|
|
20
|
+
vector: z.string().optional().describe('Full CVSS vector string (e.g. CVSS:4.0/AV:N/AC:L/...)'),
|
|
21
|
+
}, async ({ issue_key, metrics, vector: vectorStr }) => {
|
|
22
|
+
let finalMetrics;
|
|
23
|
+
if (vectorStr) {
|
|
24
|
+
finalMetrics = parseCvssVector(vectorStr);
|
|
25
|
+
}
|
|
26
|
+
else if (metrics) {
|
|
27
|
+
const errors = validateMetrics(metrics);
|
|
28
|
+
if (errors.length > 0)
|
|
29
|
+
return { content: [{ type: 'text', text: `Validation errors:\n${errors.join('\n')}` }] };
|
|
30
|
+
finalMetrics = metrics;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return { content: [{ type: 'text', text: 'Provide either metrics or vector parameter' }] };
|
|
34
|
+
}
|
|
35
|
+
const vector = buildCvssVector(finalMetrics);
|
|
36
|
+
const { score, severity } = calculateCvssScore(finalMetrics);
|
|
37
|
+
const fields = {
|
|
38
|
+
customfield_10166: vector,
|
|
39
|
+
customfield_10167: `${score} / ${severity}`,
|
|
40
|
+
};
|
|
41
|
+
await jira.updateIssue(issue_key, fields);
|
|
42
|
+
return { content: [{ type: 'text', text: `Updated ${issue_key}\n Vector: ${vector}\n Score: ${score} (${severity})` }] };
|
|
43
|
+
});
|
|
44
|
+
server.tool('cvss_get_vector', 'Get CVSS vector and score from a Vulnerability ticket', {
|
|
45
|
+
issue_key: z.string().describe('Vulnerability issue key'),
|
|
46
|
+
}, async ({ issue_key }) => {
|
|
47
|
+
const data = await jira.getIssue(issue_key, ['summary', 'customfield_10166', 'customfield_10167']);
|
|
48
|
+
const f = data.fields;
|
|
49
|
+
const vector = f?.customfield_10166 || '';
|
|
50
|
+
const score = f?.customfield_10167 || '';
|
|
51
|
+
let details = '';
|
|
52
|
+
if (vector) {
|
|
53
|
+
const metrics = parseCvssVector(vector);
|
|
54
|
+
details = '\n\nMetrics:\n' + Object.entries(metrics).map(([k, v]) => ` ${k} = ${v} (${METRIC_LABELS[k] || k})`).join('\n');
|
|
55
|
+
}
|
|
56
|
+
return { content: [{ type: 'text', text: `${issue_key}: ${f?.summary}\nCVSS Vector: ${vector}\nCVSS Score: ${score}${details}` }] };
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=cvss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cvss.js","sourceRoot":"","sources":["../../src/tools/cvss.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { renderTemplate, TEMPLATE_PATHS, TEMPLATE_NAMES, TEMPLATE_VERSION } from '../utils/doc-render.js';
|
|
6
|
+
import { adfToMarkdown } from '../utils/adf.js';
|
|
7
|
+
// ESM에선 __dirname이 없음 — import.meta.url로 빌드 산출물 위치를 기준으로 경로 해석.
|
|
8
|
+
// dist/tools/doc-render.js → ../../vendor = repo 루트의 vendor/
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const TEMPLATE_DIR = path.resolve(__dirname, '../../vendor/dev-docs-templates/templates');
|
|
11
|
+
// TEMPLATE_NAMES / TEMPLATE_PATHS 는 ../utils/doc-render.js 에서 (모드 기반 매핑)
|
|
12
|
+
export const registerDocRenderTools = (ctx) => {
|
|
13
|
+
const { server, jira } = ctx;
|
|
14
|
+
server.tool('doc_render', 'dev_docs(PRD/Spec/Plan/Tasks)·mdr_docs(intended-use 등) 템플릿을 모드 기반 결정적 렌더(freeform). 티켓 메타({TICKET_ID}/{DATE} 등)만 치환하고, 자유 텍스트/꺾쇠 placeholder/AI 지침은 consumer가 채우도록 반환. (레이어 ② — LLM 호출 없음)', {
|
|
15
|
+
template: z.enum(TEMPLATE_NAMES).describe('렌더할 템플릿: prd | spec | plan | tasks | intended_use'),
|
|
16
|
+
ticket_key: z.string().describe('Jira 티켓 키 (예: ER-123). description/메타 fetch에 사용'),
|
|
17
|
+
feature_slug: z.string().optional().describe('{FEATURE_SLUG} 치환용 (예: add-login). 미제공 시 placeholder로 남음'),
|
|
18
|
+
}, async ({ template, ticket_key, feature_slug }) => {
|
|
19
|
+
// 1. 티켓 fetch — 메타 + consumer 채우기용 본문 데이터
|
|
20
|
+
const data = await jira.getIssue(ticket_key, [
|
|
21
|
+
'summary', 'description', 'issuetype', 'status', 'project', 'reporter', 'comment',
|
|
22
|
+
]);
|
|
23
|
+
const reporter = data.fields?.reporter;
|
|
24
|
+
const ticket = {
|
|
25
|
+
key: data.key,
|
|
26
|
+
issuetype: data.fields?.issuetype?.name,
|
|
27
|
+
projectName: data.fields?.project?.name,
|
|
28
|
+
reporter: reporter?.displayName || reporter?.emailAddress,
|
|
29
|
+
};
|
|
30
|
+
// 2. 템플릿 로드 — 매핑 테이블에서 {path, mode}. 모드별 분기.
|
|
31
|
+
const entry = TEMPLATE_PATHS[template];
|
|
32
|
+
if (!entry) {
|
|
33
|
+
throw new Error(`알 수 없는 template: ${template}`);
|
|
34
|
+
}
|
|
35
|
+
if (entry.mode !== 'freeform') {
|
|
36
|
+
// table-map 등은 아직 미구현 — 도달 시 명시적 에러로 방어.
|
|
37
|
+
throw new Error(`template '${template}' (mode=${entry.mode}) 렌더는 아직 지원되지 않습니다. 현재 freeform만 구현됨.`);
|
|
38
|
+
}
|
|
39
|
+
const templatePath = path.join(TEMPLATE_DIR, entry.path);
|
|
40
|
+
const templateBody = readFileSync(templatePath, 'utf8');
|
|
41
|
+
// 3. 결정적 치환 (date는 주입 — 로직은 순수 유지)
|
|
42
|
+
const date = new Date().toISOString().split('T')[0];
|
|
43
|
+
const { rendered, unresolved } = renderTemplate({
|
|
44
|
+
template: templateBody,
|
|
45
|
+
ticket,
|
|
46
|
+
featureSlug: feature_slug,
|
|
47
|
+
date,
|
|
48
|
+
});
|
|
49
|
+
// 4. consumer용 데이터 패키징
|
|
50
|
+
const comments = (data.fields?.comment?.comments || [])
|
|
51
|
+
.slice(-5)
|
|
52
|
+
.map((c) => adfToMarkdown(c.body))
|
|
53
|
+
.filter((s) => s !== '');
|
|
54
|
+
const ticketData = {
|
|
55
|
+
key: data.key,
|
|
56
|
+
summary: data.fields?.summary,
|
|
57
|
+
status: data.fields?.status?.name,
|
|
58
|
+
issuetype: ticket.issuetype,
|
|
59
|
+
project: ticket.projectName,
|
|
60
|
+
reporter: ticket.reporter,
|
|
61
|
+
description: adfToMarkdown(data.fields?.description),
|
|
62
|
+
comments,
|
|
63
|
+
};
|
|
64
|
+
const text = [
|
|
65
|
+
`# doc_render — ${template} (티켓 ${ticket_key}, ${date})`,
|
|
66
|
+
'',
|
|
67
|
+
'## 렌더 메타 (consumer repo 저장 frontmatter용)',
|
|
68
|
+
'```yaml',
|
|
69
|
+
[
|
|
70
|
+
`doc: ${template}`,
|
|
71
|
+
`domain: ${entry.domain}`,
|
|
72
|
+
...(entry.gate ? [`gate: ${entry.gate}`] : []),
|
|
73
|
+
`template_version: ${TEMPLATE_VERSION}`,
|
|
74
|
+
].join('\n'),
|
|
75
|
+
'```',
|
|
76
|
+
'',
|
|
77
|
+
'## 렌더된 템플릿 (메타 변수 치환 완료 / 자유 텍스트는 placeholder 보존)',
|
|
78
|
+
'아래를 consumer가 채운 뒤 Write 도구로 docs/*.md 로 저장하세요.',
|
|
79
|
+
'```markdown',
|
|
80
|
+
rendered,
|
|
81
|
+
'```',
|
|
82
|
+
'',
|
|
83
|
+
'## 채워야 할 placeholder 변수 (티켓 데이터를 근거로 작성)',
|
|
84
|
+
unresolved.length > 0
|
|
85
|
+
? unresolved.map((v) => `- {${v}}`).join('\n')
|
|
86
|
+
: '(없음 — 모든 변수가 치환됨)',
|
|
87
|
+
'',
|
|
88
|
+
'## 티켓 데이터 (빈칸 작성용 재료)',
|
|
89
|
+
'```json',
|
|
90
|
+
JSON.stringify(ticketData, null, 2),
|
|
91
|
+
'```',
|
|
92
|
+
].join('\n');
|
|
93
|
+
return { content: [{ type: 'text', text }] };
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=doc-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-render.js","sourceRoot":"","sources":["../../src/tools/doc-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { textToAdf } from '../jira-client.js';
|
|
3
|
+
import { ANNEX_II_TEMPLATE, matchSection, checkCompleteness } from './annex-ii-template.js';
|
|
4
|
+
export const registerDocValidationTools = (ctx) => {
|
|
5
|
+
const { server, jira } = ctx;
|
|
6
|
+
server.tool('doc_create_from_template', 'Search existing Documents under a Gate, create missing ones per MDR Annex II template.', {
|
|
7
|
+
project_key: z.string().describe('Project key'),
|
|
8
|
+
gate_key: z.string().describe('Gate ticket key (PA or EA)'),
|
|
9
|
+
}, async ({ project_key, gate_key }) => {
|
|
10
|
+
// Get existing documents linked to the gate
|
|
11
|
+
const gateData = await jira.getIssue(gate_key, ['issuelinks', 'key', 'summary']);
|
|
12
|
+
const linkedIssues = [];
|
|
13
|
+
const links = gateData.fields?.issuelinks || [];
|
|
14
|
+
for (const link of links) {
|
|
15
|
+
if (link.outwardIssue) {
|
|
16
|
+
linkedIssues.push(link.outwardIssue.key);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Get details of linked issues
|
|
20
|
+
const existingTickets = [];
|
|
21
|
+
for (const key of linkedIssues) {
|
|
22
|
+
try {
|
|
23
|
+
const data = await jira.getIssue(key, ['summary', 'issuetype']);
|
|
24
|
+
existingTickets.push({
|
|
25
|
+
key: data.key,
|
|
26
|
+
summary: data.fields.summary,
|
|
27
|
+
issuetype: data.fields.issuetype.name,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
// Ignore errors for deleted issues
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Find missing sections
|
|
35
|
+
const missingSections = [];
|
|
36
|
+
for (const section of ANNEX_II_TEMPLATE.sections) {
|
|
37
|
+
const exists = existingTickets.some(t => matchSection(t.summary)?.id === section.id);
|
|
38
|
+
if (!exists) {
|
|
39
|
+
missingSections.push(section);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Create missing documents
|
|
43
|
+
const created = [];
|
|
44
|
+
for (const section of missingSections) {
|
|
45
|
+
const content = [
|
|
46
|
+
`# ${section.title}`,
|
|
47
|
+
'',
|
|
48
|
+
section.description,
|
|
49
|
+
'',
|
|
50
|
+
'## Content',
|
|
51
|
+
'[Document content to be filled]',
|
|
52
|
+
].join('\n');
|
|
53
|
+
const issue = await jira.createIssue({
|
|
54
|
+
project: { key: project_key },
|
|
55
|
+
summary: `[${section.title}]`,
|
|
56
|
+
issuetype: { name: 'Document' },
|
|
57
|
+
description: textToAdf(content),
|
|
58
|
+
});
|
|
59
|
+
const issueKey = issue.key;
|
|
60
|
+
// Document blocks Gate
|
|
61
|
+
await jira.createLink('Blocks', gate_key, issueKey);
|
|
62
|
+
created.push({
|
|
63
|
+
key: issueKey,
|
|
64
|
+
sectionId: section.id,
|
|
65
|
+
title: section.title,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
69
|
+
gate: gate_key,
|
|
70
|
+
existing_documents: existingTickets.length,
|
|
71
|
+
missing_sections: missingSections.map(s => s.id),
|
|
72
|
+
created_documents: created,
|
|
73
|
+
message: `${created.length} missing documents created from Annex II template.`,
|
|
74
|
+
}, null, 2) }] };
|
|
75
|
+
});
|
|
76
|
+
server.tool('doc_check_completeness', 'Query all Document tickets in project, run checkCompleteness against template, format report with ✅⚠️❌ icons.', {
|
|
77
|
+
project_key: z.string().describe('Project key'),
|
|
78
|
+
}, async ({ project_key }) => {
|
|
79
|
+
// Search all Document tickets in project
|
|
80
|
+
const searchResult = await jira.search(`project = ${project_key} AND issuetype = "Document"`, 100, ['summary', 'status', 'issuetype', 'key']);
|
|
81
|
+
const issues = searchResult.issues || [];
|
|
82
|
+
const tickets = issues.map((i) => ({
|
|
83
|
+
key: i.key,
|
|
84
|
+
summary: i.fields.summary,
|
|
85
|
+
status: i.fields.status.name,
|
|
86
|
+
issuetype: i.fields.issuetype.name,
|
|
87
|
+
}));
|
|
88
|
+
const results = checkCompleteness(ANNEX_II_TEMPLATE.sections, tickets);
|
|
89
|
+
// Format report
|
|
90
|
+
const lines = ['=== MDR Annex II 문서 완전성 검사 ===', ''];
|
|
91
|
+
for (const result of results) {
|
|
92
|
+
const icon = result.status === 'found' ? '✅' : result.status === 'missing' ? '❌' : '⚠️';
|
|
93
|
+
lines.push(`${icon} ${result.section.title} (${result.section.id})`);
|
|
94
|
+
if (result.tickets.length > 0) {
|
|
95
|
+
lines.push(` 티켓: ${result.tickets.map(t => `${t.key} (${t.status})`).join(', ')}`);
|
|
96
|
+
}
|
|
97
|
+
if (result.issues.length > 0) {
|
|
98
|
+
for (const issue of result.issues) {
|
|
99
|
+
lines.push(` - ${issue}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
lines.push('');
|
|
103
|
+
}
|
|
104
|
+
const summary = {
|
|
105
|
+
total_sections: results.length,
|
|
106
|
+
found: results.filter((r) => r.status === 'found').length,
|
|
107
|
+
incomplete: results.filter((r) => r.status === 'incomplete').length,
|
|
108
|
+
missing: results.filter((r) => r.status === 'missing').length,
|
|
109
|
+
};
|
|
110
|
+
lines.push('=== 요약 ===');
|
|
111
|
+
lines.push(`총 섹션: ${summary.total_sections}`);
|
|
112
|
+
lines.push(`✅ 완료: ${summary.found}`);
|
|
113
|
+
lines.push(`⚠️ 불완전: ${summary.incomplete}`);
|
|
114
|
+
lines.push(`❌ 누락: ${summary.missing}`);
|
|
115
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
116
|
+
});
|
|
117
|
+
server.tool('doc_generate_evidence', 'Generate evidence package for NB review: traceability matrix, risk matrix, V&V summary.', {
|
|
118
|
+
project_key: z.string().describe('Project key'),
|
|
119
|
+
}, async ({ project_key }) => {
|
|
120
|
+
// Get all issues with links for traceability
|
|
121
|
+
const issuesResult = await jira.search(`project = ${project_key}`, 500, ['key', 'summary', 'issuetype', 'status', 'issuelinks']);
|
|
122
|
+
const issues = issuesResult.issues || [];
|
|
123
|
+
// Build traceability map
|
|
124
|
+
const traceabilityMap = new Map();
|
|
125
|
+
for (const issue of issues) {
|
|
126
|
+
const links = [];
|
|
127
|
+
const issueLinks = issue.fields?.issuelinks || [];
|
|
128
|
+
for (const link of issueLinks) {
|
|
129
|
+
if (link.outwardIssue) {
|
|
130
|
+
links.push(`${link.type?.name || 'Relates'} → ${link.outwardIssue.key}`);
|
|
131
|
+
}
|
|
132
|
+
if (link.inwardIssue) {
|
|
133
|
+
links.push(`${link.type?.name || 'Relates'} ← ${link.inwardIssue.key}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
traceabilityMap.set(issue.key, {
|
|
137
|
+
summary: issue.fields.summary,
|
|
138
|
+
type: issue.fields.issuetype.name,
|
|
139
|
+
links,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Get Hazard tickets for risk matrix
|
|
143
|
+
const hazardResult = await jira.search(`project = ${project_key} AND issuetype = "Hazard"`, 100, ['key', 'summary', 'customfield_10375', 'customfield_10376', 'customfield_10377']);
|
|
144
|
+
const hazards = hazardResult.issues || [];
|
|
145
|
+
// Get Test tickets for V&V summary
|
|
146
|
+
const testResult = await jira.search(`project = ${project_key} AND issuetype = "Test"`, 100, ['key', 'summary', 'status']);
|
|
147
|
+
const tests = testResult.issues || [];
|
|
148
|
+
// Get Test Execution tickets for more V&V data
|
|
149
|
+
const testExecutionResult = await jira.search(`project = ${project_key} AND issuetype = "Test Execution"`, 100, ['key', 'summary', 'status']);
|
|
150
|
+
const testExecutions = testExecutionResult.issues || [];
|
|
151
|
+
// Format evidence package
|
|
152
|
+
const lines = [
|
|
153
|
+
'=== NB 심사용 증거 패키지 ===',
|
|
154
|
+
`생성일: ${new Date().toISOString().split('T')[0]}`,
|
|
155
|
+
`프로젝트: ${project_key}`,
|
|
156
|
+
'',
|
|
157
|
+
'## 1. 추적성 매트릭스 (Traceability Matrix)',
|
|
158
|
+
'',
|
|
159
|
+
'### Issue 추적성 (샘플 - 상위 20개)',
|
|
160
|
+
];
|
|
161
|
+
let count = 0;
|
|
162
|
+
for (const [key, info] of traceabilityMap.entries()) {
|
|
163
|
+
if (count >= 20) {
|
|
164
|
+
lines.push(` ... (총 ${traceabilityMap.size}개 issue 중 ${count}개 표시)`);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
lines.push(`**${key}** [${info.type}]: ${info.summary.substring(0, 50)}...`);
|
|
168
|
+
if (info.links.length > 0) {
|
|
169
|
+
lines.push(` 링크: ${info.links.slice(0, 3).join(', ')}${info.links.length > 3 ? '...' : ''}`);
|
|
170
|
+
}
|
|
171
|
+
lines.push('');
|
|
172
|
+
count++;
|
|
173
|
+
}
|
|
174
|
+
lines.push('## 2. 리스크 매트릭스 (Risk Matrix)');
|
|
175
|
+
lines.push('');
|
|
176
|
+
if (hazards.length === 0) {
|
|
177
|
+
lines.push('(등록된 Hazard 없음)');
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
for (const hazard of hazards.slice(0, 10)) {
|
|
181
|
+
const severity = hazard.fields?.customfield_10375?.value || 'N/A';
|
|
182
|
+
const p1 = hazard.fields?.customfield_10376?.value || 'N/A';
|
|
183
|
+
const p2 = hazard.fields?.customfield_10377?.value || 'N/A';
|
|
184
|
+
lines.push(`- ${hazard.key}: ${hazard.fields.summary.substring(0, 60)}...`);
|
|
185
|
+
lines.push(` Severity: ${severity}, P1: ${p1}, P2: ${p2}`);
|
|
186
|
+
lines.push('');
|
|
187
|
+
}
|
|
188
|
+
if (hazards.length > 10) {
|
|
189
|
+
lines.push(`... (총 ${hazards.length}개 Hazard 중 10개 표시)`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
lines.push('');
|
|
193
|
+
lines.push('## 3. V&V 요약 (Verification & Validation)');
|
|
194
|
+
lines.push('');
|
|
195
|
+
const allTests = [...tests, ...testExecutions];
|
|
196
|
+
if (allTests.length === 0) {
|
|
197
|
+
lines.push('(등록된 Test 없음)');
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
const passed = allTests.filter((t) => t.fields.status.name === 'Passed' || t.fields.status.name === 'Done').length;
|
|
201
|
+
const failed = allTests.filter((t) => t.fields.status.name === 'Failed').length;
|
|
202
|
+
const pending = allTests.filter((t) => !['Passed', 'Done', 'Failed'].includes(t.fields.status.name)).length;
|
|
203
|
+
lines.push(`- 총 테스트: ${allTests.length}`);
|
|
204
|
+
lines.push(`- 통과: ${passed} (${Math.round(passed / allTests.length * 100)}%)`);
|
|
205
|
+
lines.push(`- 실패: ${failed}`);
|
|
206
|
+
lines.push(`- 대기: ${pending}`);
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push('### 테스트 목록 (상위 10개)');
|
|
209
|
+
for (const test of allTests.slice(0, 10)) {
|
|
210
|
+
lines.push(`- ${test.key} [${test.fields.status.name}]: ${test.fields.summary.substring(0, 60)}...`);
|
|
211
|
+
}
|
|
212
|
+
if (allTests.length > 10) {
|
|
213
|
+
lines.push(`... (총 ${allTests.length}개 테스트 중 10개 표시)`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
lines.push('');
|
|
217
|
+
lines.push('=== 증거 패키지 생성 완료 ===');
|
|
218
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=doc-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc-validation.js","sourceRoot":"","sources":["../../src/tools/doc-validation.ts"],"names":[],"mappings":"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"}
|