@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,142 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { textToAdf } from '../jira-client.js';
|
|
3
|
+
import { inferAdfFields, applyAdfToFields } from '../utils/jira-fields.js';
|
|
4
|
+
export const registerJiraCrudTools = (ctx) => {
|
|
5
|
+
const { server, jira } = ctx;
|
|
6
|
+
server.tool('jira_get_issue', 'Get a Jira issue by key', {
|
|
7
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
8
|
+
fields: z.string().optional().describe('Comma-separated list of fields to return'),
|
|
9
|
+
}, async ({ issue_key, fields }) => {
|
|
10
|
+
const fieldList = fields ? fields.split(',').map(f => f.trim()) : undefined;
|
|
11
|
+
const data = await jira.getIssue(issue_key, fieldList);
|
|
12
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
13
|
+
});
|
|
14
|
+
server.tool('jira_search', 'Search Jira issues with JQL', {
|
|
15
|
+
jql: z.string().describe('JQL query string'),
|
|
16
|
+
max_results: z.number().optional().default(50).describe('Maximum results to return'),
|
|
17
|
+
}, async ({ jql, max_results }) => {
|
|
18
|
+
const data = await jira.search(jql, max_results);
|
|
19
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
20
|
+
});
|
|
21
|
+
server.tool('jira_create_issue', 'Create a new Jira issue. Rich-text customfields: pass their keys in rich_text_custom_fields (string values auto-converted to ADF), or set auto_detect_rich_text to infer them from the field schema (jira_get_issue_type_schema).', {
|
|
22
|
+
project: z.string().describe('Project key (e.g. PROJ)'),
|
|
23
|
+
summary: z.string().describe('Issue summary/title'),
|
|
24
|
+
issuetype: z.string().describe('Issue type name (e.g. Task, Story, Bug, Requirement)'),
|
|
25
|
+
description: z.string().optional().describe('Issue description (plain text, auto-converted to ADF)'),
|
|
26
|
+
assignee: z.string().optional().describe('Assignee email or accountId'),
|
|
27
|
+
labels: z.array(z.string()).optional().describe('Labels to apply'),
|
|
28
|
+
priority: z.string().optional().describe('Priority name (e.g. High, Medium, Low)'),
|
|
29
|
+
parent: z.string().optional().describe('Parent issue key for sub-tasks'),
|
|
30
|
+
extra_fields: z.record(z.unknown()).optional().describe('Additional fields to set (customfield_*). Rich-text fields should be listed in rich_text_custom_fields.'),
|
|
31
|
+
rich_text_custom_fields: z.array(z.string()).optional().describe('customfield keys whose plain-text values should be auto-converted to ADF. Discover ADF candidates via jira_get_issue_type_schema (inferredFormat: adf/adf-suspect).'),
|
|
32
|
+
auto_detect_rich_text: z.boolean().optional().describe('If true, query the field schema for this project/issuetype and auto-convert detected ADF fields (merged with rich_text_custom_fields). Adds extra API calls.'),
|
|
33
|
+
}, async ({ project, summary, issuetype, description, assignee, labels, priority, parent, extra_fields, rich_text_custom_fields, auto_detect_rich_text }) => {
|
|
34
|
+
const fields = {
|
|
35
|
+
project: { key: project },
|
|
36
|
+
summary,
|
|
37
|
+
issuetype: { name: issuetype },
|
|
38
|
+
};
|
|
39
|
+
if (description)
|
|
40
|
+
fields.description = textToAdf(description);
|
|
41
|
+
if (assignee)
|
|
42
|
+
fields.assignee = { emailAddress: assignee };
|
|
43
|
+
if (labels?.length)
|
|
44
|
+
fields.labels = labels;
|
|
45
|
+
if (priority)
|
|
46
|
+
fields.priority = { name: priority };
|
|
47
|
+
if (parent)
|
|
48
|
+
fields.parent = { key: parent };
|
|
49
|
+
if (extra_fields)
|
|
50
|
+
Object.assign(fields, extra_fields);
|
|
51
|
+
// 하이브리드 ADF 변환: 명시 키 + (선택) schema 자동 감지 병합
|
|
52
|
+
let adfKeys = rich_text_custom_fields || [];
|
|
53
|
+
if (auto_detect_rich_text) {
|
|
54
|
+
const schema = await jira.getIssueTypeSchema(project);
|
|
55
|
+
const it = schema.issueTypes?.find(t => t.name === issuetype);
|
|
56
|
+
adfKeys = inferAdfFields(it?.fields || [], rich_text_custom_fields);
|
|
57
|
+
}
|
|
58
|
+
const finalFields = applyAdfToFields(fields, adfKeys);
|
|
59
|
+
const data = await jira.createIssue(finalFields);
|
|
60
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
61
|
+
});
|
|
62
|
+
server.tool('jira_update_issue', 'Update fields on a Jira issue. Rich-text customfields: pass their keys in rich_text_custom_fields (string values auto-converted to ADF), or set auto_detect_rich_text to infer them from the issue\'s field schema. description is accepted as plain text and auto-converted to ADF.', {
|
|
63
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
64
|
+
fields: z.record(z.unknown()).describe('Fields to update as key-value pairs. Rich-text (ADF) fields should be listed in rich_text_custom_fields; otherwise pass a pre-built ADF object.'),
|
|
65
|
+
description: z.string().optional().describe('New description (plain text, auto-converted to ADF). Overrides fields.description if present.'),
|
|
66
|
+
rich_text_custom_fields: z.array(z.string()).optional().describe('customfield keys whose plain-text values should be auto-converted to ADF. Discover ADF candidates via jira_get_issue_type_schema (inferredFormat: adf/adf-suspect).'),
|
|
67
|
+
auto_detect_rich_text: z.boolean().optional().describe('If true, detect ADF fields from the issue\'s issuetype schema and auto-convert (merged with rich_text_custom_fields). Adds extra API calls.'),
|
|
68
|
+
}, async ({ issue_key, fields, description, rich_text_custom_fields, auto_detect_rich_text }) => {
|
|
69
|
+
const merged = { ...fields };
|
|
70
|
+
if (description !== undefined)
|
|
71
|
+
merged.description = textToAdf(description);
|
|
72
|
+
// 하이브리드 ADF 변환: 명시 키 + (선택) issue의 issuetype schema 자동 감지 병합
|
|
73
|
+
let adfKeys = rich_text_custom_fields || [];
|
|
74
|
+
if (auto_detect_rich_text) {
|
|
75
|
+
const issue = await jira.getIssue(issue_key, ['issuetype', 'project']);
|
|
76
|
+
const projectKey = issue.fields?.project?.key;
|
|
77
|
+
const itName = issue.fields?.issuetype?.name;
|
|
78
|
+
if (projectKey && itName) {
|
|
79
|
+
const schema = await jira.getIssueTypeSchema(projectKey);
|
|
80
|
+
const it = schema.issueTypes?.find(t => t.name === itName);
|
|
81
|
+
adfKeys = inferAdfFields(it?.fields || [], rich_text_custom_fields);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const finalFields = applyAdfToFields(merged, adfKeys);
|
|
85
|
+
await jira.updateIssue(issue_key, finalFields);
|
|
86
|
+
return { content: [{ type: 'text', text: `Issue ${issue_key} updated successfully${adfKeys.length ? ` (ADF-converted: ${adfKeys.join(', ')})` : ''}` }] };
|
|
87
|
+
});
|
|
88
|
+
server.tool('jira_add_comment', 'Add a comment to a Jira issue', {
|
|
89
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
90
|
+
body: z.string().describe('Comment text'),
|
|
91
|
+
}, async ({ issue_key, body }) => {
|
|
92
|
+
const data = await jira.addComment(issue_key, body);
|
|
93
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
94
|
+
});
|
|
95
|
+
server.tool('jira_create_link', 'Create a link between two issues. IMPORTANT direction rules: For "Blocks", outward_key blocks inward_key (e.g. outward=Document, inward=Gate means Document blocks Gate). For "Implements", outward_key implements inward_key (e.g. outward=Task, inward=DetailedDesign). For "Relates", direction does not matter. For "Risk Source", outward_key gives rise to inward_key (e.g. outward=SyRS, inward=Hazard means SyRS gives rise to Hazard). For "Mitigates", outward_key mitigates inward_key (e.g. outward=Requirement, inward=Hazard).', {
|
|
96
|
+
link_type: z.string().describe('Link type (Blocks, Implements, Relates, Risk Source, Mitigates)'),
|
|
97
|
+
inward_key: z.string().describe('The TARGET issue key (the one being blocked/implemented/mitigated/arising from)'),
|
|
98
|
+
outward_key: z.string().describe('The SOURCE issue key (the one doing the blocking/implementing/mitigating/giving rise to)'),
|
|
99
|
+
}, async ({ link_type, inward_key, outward_key }) => {
|
|
100
|
+
await jira.createLink(link_type, inward_key, outward_key);
|
|
101
|
+
return { content: [{ type: 'text', text: `Link created: ${inward_key} ←[${link_type}]→ ${outward_key}` }] };
|
|
102
|
+
});
|
|
103
|
+
server.tool('jira_delete_link', 'Delete an issue link by link ID', {
|
|
104
|
+
link_id: z.string().describe('The issue link ID to delete'),
|
|
105
|
+
}, async ({ link_id }) => {
|
|
106
|
+
await jira.deleteLink(link_id);
|
|
107
|
+
return { content: [{ type: 'text', text: `Link ${link_id} deleted` }] };
|
|
108
|
+
});
|
|
109
|
+
server.tool('jira_get_links', 'Get all issue links for a Jira issue', {
|
|
110
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
111
|
+
}, async ({ issue_key }) => {
|
|
112
|
+
const links = await jira.getLinks(issue_key);
|
|
113
|
+
return { content: [{ type: 'text', text: JSON.stringify(links, null, 2) }] };
|
|
114
|
+
});
|
|
115
|
+
server.tool('jira_get_transitions', 'Get available status transitions for an issue', {
|
|
116
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
117
|
+
}, async ({ issue_key }) => {
|
|
118
|
+
const data = await jira.getTransitions(issue_key);
|
|
119
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
120
|
+
});
|
|
121
|
+
server.tool('jira_transition', 'Transition an issue to a new status', {
|
|
122
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
123
|
+
transition_id: z.string().describe('Transition ID from jira_get_transitions'),
|
|
124
|
+
}, async ({ issue_key, transition_id }) => {
|
|
125
|
+
await jira.transition(issue_key, transition_id);
|
|
126
|
+
return { content: [{ type: 'text', text: `Issue ${issue_key} transitioned` }] };
|
|
127
|
+
});
|
|
128
|
+
server.tool('jira_delete_issue', 'Delete a Jira issue', {
|
|
129
|
+
issue_key: z.string().describe('Issue key (e.g. PROJ-123)'),
|
|
130
|
+
}, async ({ issue_key }) => {
|
|
131
|
+
await jira.deleteIssue(issue_key);
|
|
132
|
+
return { content: [{ type: 'text', text: `Issue ${issue_key} deleted` }] };
|
|
133
|
+
});
|
|
134
|
+
server.tool('jira_get_issue_type_schema', 'Get the field schema for issue types in a project. Use this to discover available fields for Vulnerability, SW Failure, Hazard, etc.', {
|
|
135
|
+
project_key: z.string().describe('Project key (e.g. PLAYG)'),
|
|
136
|
+
issue_type_id: z.string().optional().describe('Specific issue type ID. Omit to get all issue types.'),
|
|
137
|
+
}, async ({ project_key, issue_type_id }) => {
|
|
138
|
+
const data = await jira.getIssueTypeSchema(project_key, issue_type_id);
|
|
139
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=jira-crud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-crud.js","sourceRoot":"","sources":["../../src/tools/jira-crud.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getRiskConfig } from '../config/project-config.js';
|
|
3
|
+
export const registerRiskTools = (ctx) => {
|
|
4
|
+
const { server, risk, jira } = ctx;
|
|
5
|
+
server.tool('risk_activate_panel', 'Activate Risk Management Plugin panel on an issue', {
|
|
6
|
+
issue_key: z.string().describe('Issue key to activate risk panel on'),
|
|
7
|
+
}, async ({ issue_key }) => {
|
|
8
|
+
const ok = await risk.activateRiskPanel(issue_key);
|
|
9
|
+
return { content: [{ type: 'text', text: ok ? `Risk panel activated on ${issue_key}` : `Failed to activate risk panel on ${issue_key}` }] };
|
|
10
|
+
});
|
|
11
|
+
server.tool('risk_set_values', 'Set risk values (severity, p1, p2) on an issue via Risk Management Plugin', {
|
|
12
|
+
issue_key: z.string().describe('Issue key'),
|
|
13
|
+
project_key: z.string().describe('Project key (for config lookup)'),
|
|
14
|
+
severity: z.enum(['negligible', 'minor', 'serious', 'critical', 'catastrophic']).optional(),
|
|
15
|
+
p1: z.enum(['improvable', 'remote', 'occasional', 'probable', 'frequent']).optional(),
|
|
16
|
+
p2: z.enum(['improvable', 'remote', 'occasional', 'probable', 'frequent']).optional(),
|
|
17
|
+
risk_set: z.enum(['initial', 'current']).default('current').describe('Which risk set to update'),
|
|
18
|
+
}, async ({ issue_key, project_key, severity, p1, p2, risk_set }) => {
|
|
19
|
+
const riskConfig = getRiskConfig(project_key);
|
|
20
|
+
if (!riskConfig)
|
|
21
|
+
return { content: [{ type: 'text', text: `No risk management config for project ${project_key}. Check PROJECT_CONFIG_PATH.` }] };
|
|
22
|
+
const riskSetId = riskConfig.risk_sets[risk_set];
|
|
23
|
+
const configForSet = {
|
|
24
|
+
endpoint: riskConfig.endpoint,
|
|
25
|
+
author: riskConfig.author,
|
|
26
|
+
riskModelKey: riskConfig.risk_model_key,
|
|
27
|
+
riskSetId,
|
|
28
|
+
classifiers: riskConfig.classifiers,
|
|
29
|
+
};
|
|
30
|
+
const results = [];
|
|
31
|
+
for (const [name, value] of [['severity', severity], ['p1', p1], ['p2', p2]]) {
|
|
32
|
+
if (value) {
|
|
33
|
+
const ok = await risk.setRiskValue(issue_key, configForSet, name, value);
|
|
34
|
+
results.push(`${name}=${value}: ${ok ? 'OK' : 'FAILED'}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { content: [{ type: 'text', text: `Risk values for ${issue_key} (${risk_set} set):\n${results.join('\n')}` }] };
|
|
38
|
+
});
|
|
39
|
+
server.tool('risk_get_config', 'Get risk management configuration for a project', {
|
|
40
|
+
project_key: z.string().describe('Project key'),
|
|
41
|
+
}, async ({ project_key }) => {
|
|
42
|
+
const config = getRiskConfig(project_key);
|
|
43
|
+
if (!config)
|
|
44
|
+
return { content: [{ type: 'text', text: `No risk config for ${project_key}` }] };
|
|
45
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
46
|
+
risk_model_key: config.risk_model_key,
|
|
47
|
+
risk_sets: config.risk_sets,
|
|
48
|
+
classifiers: Object.fromEntries(Object.entries(config.classifiers).map(([k, v]) => [k, { id: v.id, options: Object.keys(v.options) }])),
|
|
49
|
+
}, null, 2) }] };
|
|
50
|
+
});
|
|
51
|
+
server.tool('risk_create_hazards', 'Batch create Hazard tickets with Risk panel activation, risk values, and Risk Source links. Migrated from rmr_create_hazards.py.', {
|
|
52
|
+
project_key: z.string().describe('Project key'),
|
|
53
|
+
rmr_key: z.string().describe('RMR Document ticket key'),
|
|
54
|
+
hazards: z.array(z.object({
|
|
55
|
+
summary: z.string(),
|
|
56
|
+
description: z.string(),
|
|
57
|
+
harm: z.string(),
|
|
58
|
+
severity: z.enum(['negligible', 'minor', 'serious', 'critical', 'catastrophic']),
|
|
59
|
+
p1: z.enum(['improvable', 'remote', 'occasional', 'probable', 'frequent']),
|
|
60
|
+
p2: z.enum(['improvable', 'remote', 'occasional', 'probable', 'frequent']),
|
|
61
|
+
source_keys: z.array(z.string()).describe('Related IU/SyRS ticket keys'),
|
|
62
|
+
})).describe('Array of hazard definitions'),
|
|
63
|
+
}, async ({ project_key, rmr_key, hazards }) => {
|
|
64
|
+
const riskConfig = getRiskConfig(project_key);
|
|
65
|
+
const { textToAdf } = await import('../jira-client.js');
|
|
66
|
+
const results = [];
|
|
67
|
+
const errors = [];
|
|
68
|
+
for (const h of hazards) {
|
|
69
|
+
try {
|
|
70
|
+
// 1. Create Hazard ticket
|
|
71
|
+
const issue = await jira.createIssue({
|
|
72
|
+
project: { key: project_key },
|
|
73
|
+
summary: h.summary,
|
|
74
|
+
issuetype: { name: 'Hazard' },
|
|
75
|
+
description: textToAdf(h.description),
|
|
76
|
+
customfield_10148: h.harm,
|
|
77
|
+
});
|
|
78
|
+
const issueKey = issue.key;
|
|
79
|
+
if (!issueKey) {
|
|
80
|
+
errors.push(`${h.summary}: creation failed`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// 2. Activate Risk Panel
|
|
84
|
+
await risk.activateRiskPanel(issueKey);
|
|
85
|
+
// 3. Set Risk values (both initial and current sets)
|
|
86
|
+
if (riskConfig) {
|
|
87
|
+
for (const setName of ['initial', 'current']) {
|
|
88
|
+
const setConfig = {
|
|
89
|
+
endpoint: riskConfig.endpoint, author: riskConfig.author,
|
|
90
|
+
riskModelKey: riskConfig.risk_model_key, riskSetId: riskConfig.risk_sets[setName],
|
|
91
|
+
classifiers: riskConfig.classifiers,
|
|
92
|
+
};
|
|
93
|
+
for (const [name, value] of [['severity', h.severity], ['p1', h.p1], ['p2', h.p2]]) {
|
|
94
|
+
await risk.setRiskValue(issueKey, setConfig, name, value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 4. Risk Source links (SyRS/IU → Hazard)
|
|
99
|
+
for (const srcKey of h.source_keys) {
|
|
100
|
+
await jira.createLink('Risk Source', issueKey, srcKey);
|
|
101
|
+
}
|
|
102
|
+
// 5. Relates link (Hazard → RMR)
|
|
103
|
+
await jira.createLink('Relates', issueKey, rmr_key);
|
|
104
|
+
results.push({ key: issueKey, summary: h.summary, status: 'created' });
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
errors.push(`${h.summary}: ${e.message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { content: [{ type: 'text', text: JSON.stringify({ created: results.length, failed: errors.length, results, errors }, null, 2) }] };
|
|
111
|
+
});
|
|
112
|
+
server.tool('risk_create_mitigation', 'Create mitigation Requirements, link to Hazards, and update Hazard Current P2. Migrated from srs_create_requirements.py.', {
|
|
113
|
+
project_key: z.string().describe('Project key'),
|
|
114
|
+
srs_key: z.string().describe('SRS Document ticket key'),
|
|
115
|
+
requirements: z.array(z.object({
|
|
116
|
+
summary: z.string(),
|
|
117
|
+
description: z.string(),
|
|
118
|
+
mitigates: z.array(z.string()).describe('Hazard keys this requirement mitigates'),
|
|
119
|
+
implements: z.array(z.string()).describe('System Requirement keys this implements'),
|
|
120
|
+
})),
|
|
121
|
+
hazard_risk_updates: z.record(z.object({ p2: z.string() })).describe('Hazard key → new P2 value mapping'),
|
|
122
|
+
}, async ({ project_key, srs_key, requirements, hazard_risk_updates }) => {
|
|
123
|
+
const riskConfig = getRiskConfig(project_key);
|
|
124
|
+
const { textToAdf } = await import('../jira-client.js');
|
|
125
|
+
const results = [];
|
|
126
|
+
const errors = [];
|
|
127
|
+
for (const req of requirements) {
|
|
128
|
+
try {
|
|
129
|
+
const issue = await jira.createIssue({
|
|
130
|
+
project: { key: project_key },
|
|
131
|
+
summary: req.summary,
|
|
132
|
+
issuetype: { name: 'Requirement' },
|
|
133
|
+
description: textToAdf(req.description),
|
|
134
|
+
});
|
|
135
|
+
const issueKey = issue.key;
|
|
136
|
+
if (!issueKey) {
|
|
137
|
+
errors.push(`${req.summary}: creation failed`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Mitigates links
|
|
141
|
+
for (const hazKey of req.mitigates) {
|
|
142
|
+
await jira.createLink('Mitigates', issueKey, hazKey);
|
|
143
|
+
}
|
|
144
|
+
// Implements links
|
|
145
|
+
for (const syrsKey of req.implements) {
|
|
146
|
+
await jira.createLink('Implements', issueKey, syrsKey);
|
|
147
|
+
}
|
|
148
|
+
// Relates link → SRS
|
|
149
|
+
await jira.createLink('Relates', issueKey, srs_key);
|
|
150
|
+
results.push({ key: issueKey, summary: req.summary, mitigates: req.mitigates });
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
errors.push(`${req.summary}: ${e.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Update Hazard Current P2
|
|
157
|
+
const riskUpdates = [];
|
|
158
|
+
if (riskConfig) {
|
|
159
|
+
const currentConfig = {
|
|
160
|
+
endpoint: riskConfig.endpoint, author: riskConfig.author,
|
|
161
|
+
riskModelKey: riskConfig.risk_model_key, riskSetId: riskConfig.risk_sets.current,
|
|
162
|
+
classifiers: riskConfig.classifiers,
|
|
163
|
+
};
|
|
164
|
+
for (const [hazKey, update] of Object.entries(hazard_risk_updates)) {
|
|
165
|
+
const ok = await risk.setRiskValue(hazKey, currentConfig, 'p2', update.p2);
|
|
166
|
+
riskUpdates.push(`${hazKey} P2→${update.p2}: ${ok ? 'OK' : 'FAILED'}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { content: [{ type: 'text', text: JSON.stringify({ requirements_created: results.length, results, risk_updates: riskUpdates, errors }, null, 2) }] };
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=risk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/tools/risk.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
function extractLinks(issueData) {
|
|
3
|
+
const links = [];
|
|
4
|
+
for (const link of issueData?.fields?.issuelinks || []) {
|
|
5
|
+
if (link.outwardIssue) {
|
|
6
|
+
// We're the inward side — show our perspective (inward label, incoming arrow)
|
|
7
|
+
links.push({ key: link.outwardIssue.key, summary: link.outwardIssue.fields?.summary || '', link_type: link.type.inward, direction: 'inward' });
|
|
8
|
+
}
|
|
9
|
+
if (link.inwardIssue) {
|
|
10
|
+
// We're the outward side — show our perspective (outward label, outgoing arrow)
|
|
11
|
+
links.push({ key: link.inwardIssue.key, summary: link.inwardIssue.fields?.summary || '', link_type: link.type.outward, direction: 'outward' });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return links;
|
|
15
|
+
}
|
|
16
|
+
export const registerTraceabilityTools = (ctx) => {
|
|
17
|
+
const { server, jira } = ctx;
|
|
18
|
+
server.tool('traceability_check', 'Check traceability status of a ticket - show all links and their types', {
|
|
19
|
+
issue_key: z.string().describe('Issue key to check'),
|
|
20
|
+
}, async ({ issue_key }) => {
|
|
21
|
+
const data = await jira.getIssue(issue_key, ['summary', 'issuetype', 'status', 'issuelinks', 'subtasks', 'parent']);
|
|
22
|
+
const f = data.fields;
|
|
23
|
+
const links = extractLinks(data);
|
|
24
|
+
const report = [
|
|
25
|
+
`=== ${issue_key}: ${f.summary} ===`,
|
|
26
|
+
`Type: ${f.issuetype?.name} | Status: ${f.status?.name}`,
|
|
27
|
+
'',
|
|
28
|
+
`Parent: ${f.parent?.key || '(none)'}`,
|
|
29
|
+
`Subtasks: ${(f.subtasks || []).map((s) => s.key).join(', ') || '(none)'}`,
|
|
30
|
+
'',
|
|
31
|
+
`Links (${links.length}):`,
|
|
32
|
+
...links.map(l => ` ${l.direction === 'inward' ? '←' : '→'} [${l.link_type}] ${l.key}: ${l.summary}`),
|
|
33
|
+
];
|
|
34
|
+
return { content: [{ type: 'text', text: report.join('\n') }] };
|
|
35
|
+
});
|
|
36
|
+
server.tool('traceability_find_missing', 'Find missing traceability links within a Gate. Checks expected link patterns based on IEC 62304 traceability map.', {
|
|
37
|
+
issue_key: z.string().describe('Any ticket key within the Gate to check'),
|
|
38
|
+
}, async ({ issue_key }) => {
|
|
39
|
+
// Search for Gate issues in the project
|
|
40
|
+
const projectKey = issue_key.split('-')[0];
|
|
41
|
+
const gates = await jira.search(`project=${projectKey} AND issuetype=Gate`, 50, ['summary', 'issuelinks']);
|
|
42
|
+
const missing = [];
|
|
43
|
+
for (const gate of gates.issues || []) {
|
|
44
|
+
const gateLinks = extractLinks(gate);
|
|
45
|
+
const documentKeys = gateLinks.filter(l => l.link_type === 'is blocked by').map(l => l.key);
|
|
46
|
+
for (const docKey of documentKeys) {
|
|
47
|
+
const docData = await jira.getIssue(docKey, ['summary', 'issuetype', 'issuelinks']);
|
|
48
|
+
const docLinks = extractLinks(docData);
|
|
49
|
+
const docType = docData.fields?.issuetype?.name;
|
|
50
|
+
const docSummary = docData.fields?.summary || '';
|
|
51
|
+
// Check: Document should link to its sub-tickets
|
|
52
|
+
if (docType === 'Document' && docSummary.includes('Risk Management Report')) {
|
|
53
|
+
// Should have Hazard links
|
|
54
|
+
const hasHazardLinks = docLinks.some(l => l.link_type === 'Relates');
|
|
55
|
+
if (!hasHazardLinks && documentKeys.length > 0) {
|
|
56
|
+
missing.push({ source: docKey, target: '(any Hazard)', expected_link: 'Relates' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { content: [{ type: 'text', text: missing.length > 0
|
|
62
|
+
? `Missing links found:\n${missing.map(m => ` ${m.source} → ${m.target} [${m.expected_link}]`).join('\n')}`
|
|
63
|
+
: `No missing links found for Gate issues in ${projectKey}` }] };
|
|
64
|
+
});
|
|
65
|
+
server.tool('traceability_fix', 'Automatically create missing traceability links', {
|
|
66
|
+
links: z.array(z.object({
|
|
67
|
+
link_type: z.string().describe('Link type name (e.g. Relates, Blocks, Implements, Risk Source, Mitigates)'),
|
|
68
|
+
inward_key: z.string().describe('Inward issue key'),
|
|
69
|
+
outward_key: z.string().describe('Outward issue key'),
|
|
70
|
+
})).describe('Array of links to create'),
|
|
71
|
+
}, async ({ links: linksToCreate }) => {
|
|
72
|
+
const results = [];
|
|
73
|
+
for (const l of linksToCreate) {
|
|
74
|
+
try {
|
|
75
|
+
await jira.createLink(l.link_type, l.inward_key, l.outward_key);
|
|
76
|
+
results.push({ link: `${l.inward_key} ←[${l.link_type}]→ ${l.outward_key}`, status: 'created' });
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
results.push({ link: `${l.inward_key} ←[${l.link_type}]→ ${l.outward_key}`, status: `failed: ${e.message}` });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { content: [{ type: 'text', text: results.map(r => `${r.status}: ${r.link}`).join('\n') }] };
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=traceability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceability.js","sourceRoot":"","sources":["../../src/tools/traceability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { JiraClient } from '../jira-client.js';
|
|
3
|
+
import { ConfluenceClient } from '../confluence-client.js';
|
|
4
|
+
import { RiskClient } from '../clients/risk-client.js';
|
|
5
|
+
import { XrayClient } from '../clients/xray-client.js';
|
|
6
|
+
export interface ToolContext {
|
|
7
|
+
server: McpServer;
|
|
8
|
+
jira: JiraClient;
|
|
9
|
+
confluence: ConfluenceClient;
|
|
10
|
+
risk: RiskClient;
|
|
11
|
+
xray: XrayClient | null;
|
|
12
|
+
}
|
|
13
|
+
export type ToolRegistrar = (ctx: ToolContext) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { textToAdf } from '../jira-client.js';
|
|
3
|
+
export const registerUsabilityTools = (ctx) => {
|
|
4
|
+
const { server, jira } = ctx;
|
|
5
|
+
server.tool('usability_create_use_spec', 'Create Document ticket with Use Specification content (IEC 62366-1), linked to PA Gate with Blocks link.', {
|
|
6
|
+
project_key: z.string().describe('Project key'),
|
|
7
|
+
pa_gate_key: z.string().describe('PA Gate ticket key'),
|
|
8
|
+
summary: z.string().optional().describe('Document summary (default: "[Use Specification]")'),
|
|
9
|
+
user_profile: z.string().describe('User profile description'),
|
|
10
|
+
use_environment: z.string().describe('Use environment description'),
|
|
11
|
+
intended_use: z.string().describe('Intended use description'),
|
|
12
|
+
}, async ({ project_key, pa_gate_key, summary, user_profile, use_environment, intended_use }) => {
|
|
13
|
+
const docSummary = summary || '[Use Specification]';
|
|
14
|
+
const content = [
|
|
15
|
+
'# Use Specification (IEC 62366-1)',
|
|
16
|
+
'',
|
|
17
|
+
'## User Profile',
|
|
18
|
+
user_profile,
|
|
19
|
+
'',
|
|
20
|
+
'## Use Environment',
|
|
21
|
+
use_environment,
|
|
22
|
+
'',
|
|
23
|
+
'## Intended Use',
|
|
24
|
+
intended_use,
|
|
25
|
+
].join('\n');
|
|
26
|
+
const issue = await jira.createIssue({
|
|
27
|
+
project: { key: project_key },
|
|
28
|
+
summary: docSummary,
|
|
29
|
+
issuetype: { name: 'Document' },
|
|
30
|
+
description: textToAdf(content),
|
|
31
|
+
});
|
|
32
|
+
const issueKey = issue.key;
|
|
33
|
+
// Document blocks Gate
|
|
34
|
+
await jira.createLink('Blocks', pa_gate_key, issueKey);
|
|
35
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
36
|
+
key: issueKey,
|
|
37
|
+
summary: docSummary,
|
|
38
|
+
linked_to_gate: pa_gate_key,
|
|
39
|
+
message: 'Use Specification Document created and linked to PA Gate with Blocks.',
|
|
40
|
+
}, null, 2) }] };
|
|
41
|
+
});
|
|
42
|
+
server.tool('usability_create_scenarios', 'Batch create Task tickets for Normal/Abnormal Use scenarios, linked to use_spec with Relates.', {
|
|
43
|
+
project_key: z.string().describe('Project key'),
|
|
44
|
+
use_spec_key: z.string().describe('Use Specification Document ticket key'),
|
|
45
|
+
scenarios: z.array(z.object({
|
|
46
|
+
summary: z.string().describe('Scenario summary'),
|
|
47
|
+
description: z.string().describe('Scenario description'),
|
|
48
|
+
type: z.enum(['normal', 'abnormal']).describe('Scenario type: normal or abnormal'),
|
|
49
|
+
frequency: z.enum(['rare', 'occasional', 'frequent']).describe('Usage frequency'),
|
|
50
|
+
})).describe('Scenarios to create'),
|
|
51
|
+
}, async ({ project_key, use_spec_key, scenarios }) => {
|
|
52
|
+
const results = [];
|
|
53
|
+
for (const scenario of scenarios) {
|
|
54
|
+
const content = [
|
|
55
|
+
`# Use Scenario: ${scenario.summary}`,
|
|
56
|
+
'',
|
|
57
|
+
`**Type:** ${scenario.type}`,
|
|
58
|
+
`**Frequency:** ${scenario.frequency}`,
|
|
59
|
+
'',
|
|
60
|
+
'## Description',
|
|
61
|
+
scenario.description,
|
|
62
|
+
'',
|
|
63
|
+
'## Steps',
|
|
64
|
+
'1. [Step 1]',
|
|
65
|
+
'2. [Step 2]',
|
|
66
|
+
'...',
|
|
67
|
+
].join('\n');
|
|
68
|
+
const issue = await jira.createIssue({
|
|
69
|
+
project: { key: project_key },
|
|
70
|
+
summary: scenario.summary,
|
|
71
|
+
issuetype: { name: 'Task' },
|
|
72
|
+
description: textToAdf(content),
|
|
73
|
+
labels: ['use-scenario', scenario.type],
|
|
74
|
+
});
|
|
75
|
+
const issueKey = issue.key;
|
|
76
|
+
// Relates link to Use Specification
|
|
77
|
+
await jira.createLink('Relates', issueKey, use_spec_key);
|
|
78
|
+
results.push({
|
|
79
|
+
key: issueKey,
|
|
80
|
+
summary: scenario.summary,
|
|
81
|
+
type: scenario.type,
|
|
82
|
+
frequency: scenario.frequency,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
86
|
+
total_created: results.length,
|
|
87
|
+
linked_to: use_spec_key,
|
|
88
|
+
scenarios: results,
|
|
89
|
+
message: `${results.length} use scenarios created and linked to Use Specification.`,
|
|
90
|
+
}, null, 2) }] };
|
|
91
|
+
});
|
|
92
|
+
server.tool('usability_link_to_hazard', 'Link scenario to hazards with Risk Source link (scenario gives rise to hazard).', {
|
|
93
|
+
scenario_key: z.string().describe('Use scenario Task ticket key'),
|
|
94
|
+
hazard_keys: z.array(z.string()).describe('Hazard ticket keys to link'),
|
|
95
|
+
}, async ({ scenario_key, hazard_keys }) => {
|
|
96
|
+
const results = [];
|
|
97
|
+
for (const hazardKey of hazard_keys) {
|
|
98
|
+
await jira.createLink('Risk Source', hazardKey, scenario_key);
|
|
99
|
+
results.push(`${scenario_key} → ${hazardKey} (Risk Source)`);
|
|
100
|
+
}
|
|
101
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
102
|
+
scenario: scenario_key,
|
|
103
|
+
linked_hazards: hazard_keys,
|
|
104
|
+
links_created: results,
|
|
105
|
+
message: `${results.length} Risk Source links created (scenario → hazards).`,
|
|
106
|
+
}, null, 2) }] };
|
|
107
|
+
});
|
|
108
|
+
server.tool('usability_create_validation', 'Create Task ticket with usability validation evidence, linked to scenario with Relates.', {
|
|
109
|
+
project_key: z.string().describe('Project key'),
|
|
110
|
+
scenario_key: z.string().describe('Use scenario Task ticket key'),
|
|
111
|
+
summary: z.string().describe('Validation summary'),
|
|
112
|
+
method: z.string().describe('Validation method'),
|
|
113
|
+
result: z.enum(['pass', 'fail', 'partial']).describe('Validation result'),
|
|
114
|
+
evidence: z.string().describe('Evidence description'),
|
|
115
|
+
participants: z.string().optional().describe('Participant information'),
|
|
116
|
+
}, async ({ project_key, scenario_key, summary, method, result, evidence, participants }) => {
|
|
117
|
+
const content = [
|
|
118
|
+
'# Usability Validation',
|
|
119
|
+
'',
|
|
120
|
+
`**Method:** ${method}`,
|
|
121
|
+
`**Result:** ${result}`,
|
|
122
|
+
'',
|
|
123
|
+
participants ? `**Participants:** ${participants}\n` : '',
|
|
124
|
+
'## Evidence',
|
|
125
|
+
evidence,
|
|
126
|
+
'',
|
|
127
|
+
'## Conclusion',
|
|
128
|
+
result === 'pass' ? 'Usability validation PASSED.' : result === 'fail' ? 'Usability validation FAILED.' : 'Usability validation PARTIALLY PASSED.',
|
|
129
|
+
].join('\n');
|
|
130
|
+
const issue = await jira.createIssue({
|
|
131
|
+
project: { key: project_key },
|
|
132
|
+
summary,
|
|
133
|
+
issuetype: { name: 'Task' },
|
|
134
|
+
description: textToAdf(content),
|
|
135
|
+
labels: ['usability-validation'],
|
|
136
|
+
});
|
|
137
|
+
const issueKey = issue.key;
|
|
138
|
+
// Relates link to scenario
|
|
139
|
+
await jira.createLink('Relates', issueKey, scenario_key);
|
|
140
|
+
return { content: [{ type: 'text', text: JSON.stringify({
|
|
141
|
+
key: issueKey,
|
|
142
|
+
summary,
|
|
143
|
+
result,
|
|
144
|
+
linked_to_scenario: scenario_key,
|
|
145
|
+
message: 'Usability validation Task created and linked to scenario.',
|
|
146
|
+
}, null, 2) }] };
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=usability.js.map
|