@neobiotechlabs/neobiotech-dev-agent-codex 0.1.39
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/.codex-plugin/plugin.json +36 -0
- package/.mcp.json +20 -0
- package/data/cyber_sec.png +0 -0
- package/data/hazard_panel.png +0 -0
- package/data/review-criteria.md +185 -0
- package/data/risk_score.png +0 -0
- package/dist/build/plantuml-1.2026.1.jar +0 -0
- package/dist/data/Courier-Bold.afm +342 -0
- package/dist/data/Courier-BoldOblique.afm +342 -0
- package/dist/data/Courier-Oblique.afm +342 -0
- package/dist/data/Courier.afm +342 -0
- package/dist/data/Helvetica-Bold.afm +2827 -0
- package/dist/data/Helvetica-BoldOblique.afm +2827 -0
- package/dist/data/Helvetica-Oblique.afm +3051 -0
- package/dist/data/Helvetica.afm +3051 -0
- package/dist/data/Symbol.afm +213 -0
- package/dist/data/Times-Bold.afm +2588 -0
- package/dist/data/Times-BoldItalic.afm +2384 -0
- package/dist/data/Times-Italic.afm +2667 -0
- package/dist/data/Times-Roman.afm +2419 -0
- package/dist/data/ZapfDingbats.afm +225 -0
- package/dist/data/sRGB_IEC61966_2_1.icc +0 -0
- package/dist/doctor.js +15106 -0
- package/dist/doctor.js.map +1 -0
- package/dist/fonts/LICENSE.txt +94 -0
- package/dist/fonts/Pretendard-Bold.ttf +0 -0
- package/dist/fonts/Pretendard-Regular.ttf +0 -0
- package/dist/index.js +185999 -0
- package/dist/index.js.map +1 -0
- package/dist/setup-codex.js +164 -0
- package/dist/setup-codex.js.map +1 -0
- package/package.json +34 -0
- package/skills/doc-render/SKILL.md +84 -0
- package/skills/role-document-content-reviewer/SKILL.md +68 -0
- package/skills/role-mdr-cybersecurity-reviewer/SKILL.md +47 -0
- package/skills/role-mdr-regulatory-architect/SKILL.md +48 -0
- package/skills/role-requirement-coverage-tracker/SKILL.md +108 -0
- package/skills/role-sw-architect/SKILL.md +61 -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-detailed-design.md +321 -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-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/configuration-management-plan.md +112 -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/security-management-plan.md +101 -0
- package/vendor/dev-docs-templates/templates/mdr_docs/PA/software-development-maintenance-plan.md +213 -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,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { fileURLToPath as __f2p } from "node:url";
|
|
4
|
+
import { dirname as __dn } from "node:path";
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const __filename = __f2p(import.meta.url);
|
|
7
|
+
const __dirname = __dn(__filename);
|
|
8
|
+
|
|
9
|
+
// src/cli/setup-codex.ts
|
|
10
|
+
import path2 from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
|
|
13
|
+
// src/cli/codex-project-config.ts
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
15
|
+
import path from "path";
|
|
16
|
+
var FALLBACK_KEY = "project_doc_fallback_filenames";
|
|
17
|
+
var MAX_BYTES_KEY = "project_doc_max_bytes";
|
|
18
|
+
var FALLBACK_LINE = `${FALLBACK_KEY} = ["CLAUDE.md"]`;
|
|
19
|
+
var MAX_BYTES_LINE = `${MAX_BYTES_KEY} = 65536`;
|
|
20
|
+
function parseStringArray(value) {
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(value);
|
|
23
|
+
return Array.isArray(parsed) && parsed.every((item) => typeof item === "string") ? parsed : null;
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function formatStringArray(values) {
|
|
29
|
+
return `[${values.map((value) => JSON.stringify(value)).join(", ")}]`;
|
|
30
|
+
}
|
|
31
|
+
function mergeCodexConfig(configText) {
|
|
32
|
+
const newline = configText.includes("\r\n") ? "\r\n" : "\n";
|
|
33
|
+
const hadTrailingNewline = configText.endsWith("\n");
|
|
34
|
+
const lines = configText ? configText.replace(/\r\n/g, "\n").split("\n") : [];
|
|
35
|
+
if (hadTrailingNewline) lines.pop();
|
|
36
|
+
let inSection = false;
|
|
37
|
+
let fallbackIndex = -1;
|
|
38
|
+
let maxBytesIndex = -1;
|
|
39
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
40
|
+
const line = lines[index];
|
|
41
|
+
if (/^\s*\[/.test(line)) inSection = true;
|
|
42
|
+
if (inSection) continue;
|
|
43
|
+
if (new RegExp(`^\\s*${FALLBACK_KEY}\\s*=`).test(line)) {
|
|
44
|
+
if (fallbackIndex !== -1) throw new Error(`Duplicate ${FALLBACK_KEY}`);
|
|
45
|
+
fallbackIndex = index;
|
|
46
|
+
}
|
|
47
|
+
if (new RegExp(`^\\s*${MAX_BYTES_KEY}\\s*=`).test(line)) {
|
|
48
|
+
if (maxBytesIndex !== -1) throw new Error(`Duplicate ${MAX_BYTES_KEY}`);
|
|
49
|
+
maxBytesIndex = index;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (fallbackIndex !== -1) {
|
|
53
|
+
const match = lines[fallbackIndex].match(
|
|
54
|
+
new RegExp(`^(\\s*)${FALLBACK_KEY}\\s*=\\s*(\\[[^#]*\\])(\\s+#.*)?$`)
|
|
55
|
+
);
|
|
56
|
+
if (!match) throw new Error(`Cannot safely parse ${FALLBACK_KEY}`);
|
|
57
|
+
const values = parseStringArray(match[2]);
|
|
58
|
+
if (!values) throw new Error(`Cannot safely parse ${FALLBACK_KEY}`);
|
|
59
|
+
if (!values.includes("CLAUDE.md")) {
|
|
60
|
+
lines[fallbackIndex] = `${match[1]}${FALLBACK_KEY} = ${formatStringArray([
|
|
61
|
+
...values,
|
|
62
|
+
"CLAUDE.md"
|
|
63
|
+
])}${match[3] ?? ""}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (maxBytesIndex !== -1) {
|
|
67
|
+
const match = lines[maxBytesIndex].match(
|
|
68
|
+
new RegExp(`^(\\s*)${MAX_BYTES_KEY}\\s*=\\s*(\\d+)(\\s+#.*)?$`)
|
|
69
|
+
);
|
|
70
|
+
if (!match) throw new Error(`Cannot safely parse ${MAX_BYTES_KEY}`);
|
|
71
|
+
if (Number(match[2]) < 65536) {
|
|
72
|
+
lines[maxBytesIndex] = `${match[1]}${MAX_BYTES_LINE}${match[3] ?? ""}`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const additions = [];
|
|
76
|
+
if (fallbackIndex === -1) additions.push(FALLBACK_LINE);
|
|
77
|
+
if (maxBytesIndex === -1) additions.push(MAX_BYTES_LINE);
|
|
78
|
+
if (additions.length > 0) {
|
|
79
|
+
if (lines.length > 0 && lines[0] !== "") additions.push("");
|
|
80
|
+
lines.unshift(...additions);
|
|
81
|
+
}
|
|
82
|
+
const content = `${lines.join(newline)}${newline}`;
|
|
83
|
+
const normalizedOriginal = configText ? `${configText.replace(/\r\n|\r|\n/g, "\n").replace(/\n$/, "").replace(/\n/g, newline)}${newline}` : "";
|
|
84
|
+
return { changed: content !== normalizedOriginal, content };
|
|
85
|
+
}
|
|
86
|
+
function planCodexProjectSetup({
|
|
87
|
+
hasClaude,
|
|
88
|
+
hasAgents,
|
|
89
|
+
configText
|
|
90
|
+
}) {
|
|
91
|
+
if (hasClaude && hasAgents) {
|
|
92
|
+
return {
|
|
93
|
+
status: "conflict",
|
|
94
|
+
messages: ["CLAUDE.md\uC640 AGENTS.md\uAC00 \uB3D9\uC2DC\uC5D0 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uC790\uB3D9 \uBCC0\uACBD\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."]
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (hasAgents) return { status: "skip", messages: ["\uAE30\uC874 AGENTS.md\uB97C \uC720\uC9C0\uD569\uB2C8\uB2E4."] };
|
|
98
|
+
if (!hasClaude) {
|
|
99
|
+
return { status: "skip", messages: ["CLAUDE.md\uAC00 \uC5C6\uC5B4 fallback\uC744 \uC0DD\uC131\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."] };
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const merged = mergeCodexConfig(configText);
|
|
103
|
+
return {
|
|
104
|
+
status: configText ? merged.changed ? "update" : "noop" : "create",
|
|
105
|
+
messages: [
|
|
106
|
+
merged.changed ? "Codex fallback \uC124\uC815\uC744 \uC900\uBE44\uD588\uC2B5\uB2C8\uB2E4." : "Codex fallback \uC124\uC815\uC774 \uC774\uBBF8 \uCD5C\uC2E0\uC785\uB2C8\uB2E4."
|
|
107
|
+
],
|
|
108
|
+
configText: merged.content
|
|
109
|
+
};
|
|
110
|
+
} catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
status: "conflict",
|
|
113
|
+
messages: [
|
|
114
|
+
`\uAE30\uC874 Codex \uC124\uC815\uC744 \uC548\uC804\uD558\uAC8C \uBCD1\uD569\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${error instanceof Error ? error.message : String(error)}`
|
|
115
|
+
]
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function setupCodexProject({ projectDir }) {
|
|
120
|
+
const claudePath = path.join(projectDir, "CLAUDE.md");
|
|
121
|
+
const agentsPath = path.join(projectDir, "AGENTS.md");
|
|
122
|
+
const configPath = path.join(projectDir, ".codex", "config.toml");
|
|
123
|
+
const plan = planCodexProjectSetup({
|
|
124
|
+
hasClaude: existsSync(claudePath),
|
|
125
|
+
hasAgents: existsSync(agentsPath),
|
|
126
|
+
configText: existsSync(configPath) ? readFileSync(configPath, "utf8") : ""
|
|
127
|
+
});
|
|
128
|
+
if ((plan.status === "create" || plan.status === "update") && plan.configText) {
|
|
129
|
+
mkdirSync(path.dirname(configPath), { recursive: true });
|
|
130
|
+
writeFileSync(configPath, plan.configText);
|
|
131
|
+
}
|
|
132
|
+
return plan;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/cli/setup-codex.ts
|
|
136
|
+
function parseProjectPath(args) {
|
|
137
|
+
const index = args.indexOf("--project");
|
|
138
|
+
if (index === -1) return process.cwd();
|
|
139
|
+
if (!args[index + 1]) throw new Error("--project requires a path");
|
|
140
|
+
return path2.resolve(args[index + 1]);
|
|
141
|
+
}
|
|
142
|
+
function runSetupCodexCli(args) {
|
|
143
|
+
const projectDir = parseProjectPath(args);
|
|
144
|
+
const result = setupCodexProject({ projectDir });
|
|
145
|
+
const output = [
|
|
146
|
+
`project instruction status: ${result.status}`,
|
|
147
|
+
...result.messages,
|
|
148
|
+
"Marketplace registration: codex plugin marketplace add <path-to-neobiotech-marketplace>",
|
|
149
|
+
"Plugin installation: install neobiotech-dev-agent from the NeoBiotech Marketplace.",
|
|
150
|
+
"Required environment variables: JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN",
|
|
151
|
+
"Optional environment variables: XRAY_CLIENT_ID, XRAY_CLIENT_SECRET, RISK_PLUGIN_ENDPOINT, RISK_PLUGIN_AUTH_TOKEN, RISK_PLUGIN_AUTHOR",
|
|
152
|
+
"Restart Codex after Marketplace or environment changes."
|
|
153
|
+
];
|
|
154
|
+
process.stdout.write(`${output.join("\n")}
|
|
155
|
+
`);
|
|
156
|
+
return result.status === "conflict" ? 2 : 0;
|
|
157
|
+
}
|
|
158
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
159
|
+
process.exitCode = runSetupCodexCli(process.argv.slice(2));
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
runSetupCodexCli
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=setup-codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/setup-codex.ts","../src/cli/codex-project-config.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { setupCodexProject } from './codex-project-config.js';\n\nfunction parseProjectPath(args: string[]) {\n const index = args.indexOf('--project');\n if (index === -1) return process.cwd();\n if (!args[index + 1]) throw new Error('--project requires a path');\n return path.resolve(args[index + 1]);\n}\n\nexport function runSetupCodexCli(args: string[]) {\n const projectDir = parseProjectPath(args);\n const result = setupCodexProject({ projectDir });\n const output = [\n `project instruction status: ${result.status}`,\n ...result.messages,\n 'Marketplace registration: codex plugin marketplace add <path-to-neobiotech-marketplace>',\n 'Plugin installation: install neobiotech-dev-agent from the NeoBiotech Marketplace.',\n 'Required environment variables: JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN',\n 'Optional environment variables: XRAY_CLIENT_ID, XRAY_CLIENT_SECRET, RISK_PLUGIN_ENDPOINT, RISK_PLUGIN_AUTH_TOKEN, RISK_PLUGIN_AUTHOR',\n 'Restart Codex after Marketplace or environment changes.',\n ];\n process.stdout.write(`${output.join('\\n')}\\n`);\n return result.status === 'conflict' ? 2 : 0;\n}\n\nif (process.argv[1] === fileURLToPath(import.meta.url)) {\n process.exitCode = runSetupCodexCli(process.argv.slice(2));\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\n\nconst FALLBACK_KEY = 'project_doc_fallback_filenames';\nconst MAX_BYTES_KEY = 'project_doc_max_bytes';\nconst FALLBACK_LINE = `${FALLBACK_KEY} = [\"CLAUDE.md\"]`;\nconst MAX_BYTES_LINE = `${MAX_BYTES_KEY} = 65536`;\n\nexport interface SetupInput {\n hasClaude: boolean;\n hasAgents: boolean;\n configText: string;\n}\n\nexport interface SetupPlan {\n status: 'create' | 'update' | 'noop' | 'conflict' | 'skip';\n messages: string[];\n configText?: string;\n}\n\nfunction parseStringArray(value: string): string[] | null {\n try {\n const parsed: unknown = JSON.parse(value);\n return Array.isArray(parsed) && parsed.every((item) => typeof item === 'string')\n ? parsed\n : null;\n } catch {\n return null;\n }\n}\n\nfunction formatStringArray(values: string[]) {\n return `[${values.map((value) => JSON.stringify(value)).join(', ')}]`;\n}\n\nexport function mergeCodexConfig(configText: string): { changed: boolean; content: string } {\n const newline = configText.includes('\\r\\n') ? '\\r\\n' : '\\n';\n const hadTrailingNewline = configText.endsWith('\\n');\n const lines = configText ? configText.replace(/\\r\\n/g, '\\n').split('\\n') : [];\n if (hadTrailingNewline) lines.pop();\n\n let inSection = false;\n let fallbackIndex = -1;\n let maxBytesIndex = -1;\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index];\n if (/^\\s*\\[/.test(line)) inSection = true;\n if (inSection) continue;\n if (new RegExp(`^\\\\s*${FALLBACK_KEY}\\\\s*=`).test(line)) {\n if (fallbackIndex !== -1) throw new Error(`Duplicate ${FALLBACK_KEY}`);\n fallbackIndex = index;\n }\n if (new RegExp(`^\\\\s*${MAX_BYTES_KEY}\\\\s*=`).test(line)) {\n if (maxBytesIndex !== -1) throw new Error(`Duplicate ${MAX_BYTES_KEY}`);\n maxBytesIndex = index;\n }\n }\n\n if (fallbackIndex !== -1) {\n const match = lines[fallbackIndex].match(\n new RegExp(`^(\\\\s*)${FALLBACK_KEY}\\\\s*=\\\\s*(\\\\[[^#]*\\\\])(\\\\s+#.*)?$`),\n );\n if (!match) throw new Error(`Cannot safely parse ${FALLBACK_KEY}`);\n const values = parseStringArray(match[2]);\n if (!values) throw new Error(`Cannot safely parse ${FALLBACK_KEY}`);\n if (!values.includes('CLAUDE.md')) {\n lines[fallbackIndex] = `${match[1]}${FALLBACK_KEY} = ${formatStringArray([\n ...values,\n 'CLAUDE.md',\n ])}${match[3] ?? ''}`;\n }\n }\n\n if (maxBytesIndex !== -1) {\n const match = lines[maxBytesIndex].match(\n new RegExp(`^(\\\\s*)${MAX_BYTES_KEY}\\\\s*=\\\\s*(\\\\d+)(\\\\s+#.*)?$`),\n );\n if (!match) throw new Error(`Cannot safely parse ${MAX_BYTES_KEY}`);\n if (Number(match[2]) < 65536) {\n lines[maxBytesIndex] = `${match[1]}${MAX_BYTES_LINE}${match[3] ?? ''}`;\n }\n }\n\n const additions = [];\n if (fallbackIndex === -1) additions.push(FALLBACK_LINE);\n if (maxBytesIndex === -1) additions.push(MAX_BYTES_LINE);\n if (additions.length > 0) {\n if (lines.length > 0 && lines[0] !== '') additions.push('');\n lines.unshift(...additions);\n }\n\n const content = `${lines.join(newline)}${newline}`;\n const normalizedOriginal = configText\n ? `${configText\n .replace(/\\r\\n|\\r|\\n/g, '\\n')\n .replace(/\\n$/, '')\n .replace(/\\n/g, newline)}${newline}`\n : '';\n return { changed: content !== normalizedOriginal, content };\n}\n\nexport function planCodexProjectSetup({\n hasClaude,\n hasAgents,\n configText,\n}: SetupInput): SetupPlan {\n if (hasClaude && hasAgents) {\n return {\n status: 'conflict',\n messages: ['CLAUDE.md와 AGENTS.md가 동시에 존재합니다. 자동 변경하지 않습니다.'],\n };\n }\n if (hasAgents) return { status: 'skip', messages: ['기존 AGENTS.md를 유지합니다.'] };\n if (!hasClaude) {\n return { status: 'skip', messages: ['CLAUDE.md가 없어 fallback을 생성하지 않습니다.'] };\n }\n\n try {\n const merged = mergeCodexConfig(configText);\n return {\n status: configText ? (merged.changed ? 'update' : 'noop') : 'create',\n messages: [\n merged.changed\n ? 'Codex fallback 설정을 준비했습니다.'\n : 'Codex fallback 설정이 이미 최신입니다.',\n ],\n configText: merged.content,\n };\n } catch (error) {\n return {\n status: 'conflict',\n messages: [\n `기존 Codex 설정을 안전하게 병합할 수 없습니다: ${\n error instanceof Error ? error.message : String(error)\n }`,\n ],\n };\n }\n}\n\nexport function setupCodexProject({ projectDir }: { projectDir: string }): SetupPlan {\n const claudePath = path.join(projectDir, 'CLAUDE.md');\n const agentsPath = path.join(projectDir, 'AGENTS.md');\n const configPath = path.join(projectDir, '.codex', 'config.toml');\n const plan = planCodexProjectSetup({\n hasClaude: existsSync(claudePath),\n hasAgents: existsSync(agentsPath),\n configText: existsSync(configPath) ? readFileSync(configPath, 'utf8') : '',\n });\n if ((plan.status === 'create' || plan.status === 'update') && plan.configText) {\n mkdirSync(path.dirname(configPath), { recursive: true });\n writeFileSync(configPath, plan.configText);\n }\n return plan;\n}\n"],"mappings":"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","names":["path","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neobiotechlabs/neobiotech-dev-agent-codex",
|
|
3
|
+
"version": "0.1.39",
|
|
4
|
+
"description": "Jira & Confluence MCP Server plugin for Codex",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"neobiotech-dev-agent-codex": "dist/index.js",
|
|
9
|
+
"neobiotech-dev-agent-doctor": "dist/doctor.js",
|
|
10
|
+
"neobiotech-setup-codex": "dist/setup-codex.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"jira",
|
|
15
|
+
"confluence",
|
|
16
|
+
"claude-code",
|
|
17
|
+
"codex"
|
|
18
|
+
],
|
|
19
|
+
"author": "NeoBiotech",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
23
|
+
"adm-zip": "^0.5.17",
|
|
24
|
+
"marked": "^18.0.5",
|
|
25
|
+
"node-fetch": "^3.3.2",
|
|
26
|
+
"pdfkit": "^0.19.1",
|
|
27
|
+
"plantuml-cli": "1.2026.1",
|
|
28
|
+
"zod": "^3.24.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"registry": "https://registry.npmjs.org",
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: doc-render
|
|
3
|
+
description: doc_render 도구 출력으로 MDR/dev 문서를 자동 작성해 consumer repo에 저장하고 Jira 티켓 description에 미러. (Phase 4 — 자동 초안 + 사용자 최종 리뷰)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# doc_render 작성 skill
|
|
7
|
+
|
|
8
|
+
`doc_render` MCP 툴이 렌더한 템플릿(메타 치환 + 빈칸/AI 지침 보존 + 티켓 데이터)을 받아,
|
|
9
|
+
AI 지침과 티켓 데이터로 빈칸을 채우고, consumer repo의 `docs/` 에 저장한 뒤 Jira 티켓
|
|
10
|
+
description에 미러한다. 자동 초안 + 사용자 최종 리뷰 방식.
|
|
11
|
+
|
|
12
|
+
## 발동 조건
|
|
13
|
+
|
|
14
|
+
- 사용자가 "DYN-8 intended use 문서 작성", "<ticket> <template> 문서 만들어" 등으로 요청
|
|
15
|
+
- 또는 티켓 타입/요약에서 템플릿을 추론한 뒤 사용자에게 확인
|
|
16
|
+
|
|
17
|
+
지원 템플릿(현재 18개):
|
|
18
|
+
- **dev** (4): `prd`, `spec`, `plan`, `tasks`
|
|
19
|
+
- **mdr/PA gate** (7): `intended_use`, `system_requirements_spec`, `risk_management_plan`, `mdr_classification_document`, `software_development_maintenance_plan`, `configuration_management_plan`, `security_management_plan`
|
|
20
|
+
- **mdr/EA gate** (7): `software_requirements_list`, `software_architecture_description`, `risk_table_fmea`, `soup_list`, `usability_evaluation_plan`, `clinical_evaluation_plan`, `list_of_hazard_related_use_scenarios`
|
|
21
|
+
|
|
22
|
+
모두 freeform 모드 — 메타 변수 치환 + 빈 데이터 표·AI 지침은 consumer가 채움. (table-map 모드는 vendor 템플릿 구조상 불필요 — 모든 템플릿이 freeform 패턴.)
|
|
23
|
+
|
|
24
|
+
## 절차
|
|
25
|
+
|
|
26
|
+
1. **입력 식별** — 티켓 키·템플릿 확정. 미지정 시 티켓 타입·요약에서 추론해 사용자에게 확인.
|
|
27
|
+
2. **doc_render 호출** — `doc_render(template, ticket_key)`. 반환: 렌더 메타 + 렌더된 템플릿 + placeholder 목록 + 티켓 데이터 JSON.
|
|
28
|
+
3. **재료 수집** — `jira_get_issue` / `jira_get_links` 로 티켓 본문과 링크된 관련 이슈(부모 Gate, SyRS 등) 조회. 티켓에 없는 정보는 자동 초안(4단계)에서 채울 수 없으면 리뷰(5단계)에서 사용자가 보완.
|
|
29
|
+
4. **자동 초안 작성** — 렌더된 템플릿의 AI 지침 주석 + 티켓 데이터·재료로 빈칸·placeholder를 채운다. 템플릿의 섹션 구조·마킹·저작권 푸터(openregulatory)는 유지.
|
|
30
|
+
5. **사용자 리뷰 게이트** — 초안을 사용자에게 제시. 수정·보완(회사 특화 정보: 기기명·UDI-DI·임상 근거 등) 반영 후 승인. **승인 전에는 consumer repo에 쓰지 않는다.**
|
|
31
|
+
6. **consumer repo 저장** — 아래 저장 경로 규칙대로 `Write`. 맨 위에 버전 frontmatter(아래 스키마) 포함.
|
|
32
|
+
7. **Jira 미러** — `doc_update_description(ticket_key, 본문)`. frontmatter는 제외하고 본문만.
|
|
33
|
+
8. **검증** — 아래 체크리스트로 미달 항목 경고. 차단하지 않음 — 사용자 판단.
|
|
34
|
+
|
|
35
|
+
## 저장 경로 규칙
|
|
36
|
+
|
|
37
|
+
- mdr: `docs/mdr/<gate>/<template>-<ticket>.md` (gate는 doc_render 렌더 메타에서)
|
|
38
|
+
- 예: `docs/mdr/PA/intended-use-DYN-8.md`, `docs/mdr/EA/software-requirements-list-DYN-12.md`
|
|
39
|
+
- dev: `docs/dev/<template>-<ticket>.md` (gate 없음)
|
|
40
|
+
- 예: `docs/dev/prd-ER-123.md`
|
|
41
|
+
|
|
42
|
+
template명의 `_`는 파일명에선 `-`로 (`intended_use` → `intended-use`).
|
|
43
|
+
|
|
44
|
+
## 버전 frontmatter 스키마
|
|
45
|
+
|
|
46
|
+
저장 파일 맨 위:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
---
|
|
50
|
+
doc: intended-use
|
|
51
|
+
ticket: DYN-8
|
|
52
|
+
domain: mdr
|
|
53
|
+
gate: PA
|
|
54
|
+
template_version: 4dc0c46
|
|
55
|
+
version: 0.1
|
|
56
|
+
status: draft
|
|
57
|
+
updated: 2026-07-05
|
|
58
|
+
---
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- `doc` / `domain` / `gate` / `template_version`: doc_render 렌더 메타에서 복사.
|
|
62
|
+
- `ticket`: 대상 티켓 키.
|
|
63
|
+
- `version` / `status`: Phase 4는 항상 `0.1` / `draft`. (버전업·상태 전이는 Phase 5.)
|
|
64
|
+
- `updated`: 오늘 날짜(YYYY-MM-DD).
|
|
65
|
+
|
|
66
|
+
## 검증 체크리스트
|
|
67
|
+
|
|
68
|
+
초안 작성 후 각 항목 점검 — 미달 시 경고(차단 아님):
|
|
69
|
+
|
|
70
|
+
- [ ] 모든 빈칸·꺾쇠 placeholder(`<...>`)가 채워졌거나, 남겨둔 이유가 명시됨
|
|
71
|
+
- [ ] AI 지침 주석이 안내한 모든 섹션이 작성됨
|
|
72
|
+
- [ ] 저작권 푸터(openregulatory 등)가 보존됨
|
|
73
|
+
- [ ] 티켓 데이터(기기명·UDI-DI 등 인스턴스 값)가 placeholder에 들어감
|
|
74
|
+
|
|
75
|
+
## 에러 처리
|
|
76
|
+
|
|
77
|
+
- `doc_render` 실패: 즉시 중단, 에러를 사용자에게 전달.
|
|
78
|
+
- 채울 재료 부족: 빈칸·placeholder 남기고 리뷰(5단계)에서 사용자가 보완.
|
|
79
|
+
- Jira 미러 실패: consumer repo 저장은 유지(성공), Jira 실패만 경고 — 부분 성공 허용.
|
|
80
|
+
- 검증 미달: 경고만.
|
|
81
|
+
|
|
82
|
+
## 의존 도구
|
|
83
|
+
|
|
84
|
+
`doc_render`, `jira_get_issue`, `jira_get_links`, `doc_update_description` (MCP) + `Write` (내장).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-document-content-reviewer
|
|
3
|
+
description: "Jira description / 첨부 본문의 LLM 자유 평가. Complete(필수 섹션 존재 + placeholder 잔존 없음) / Consistent(섹션 간 모순 부재) / Template-conformant(issuetype 템플릿 구조 준수). 문서 작성 완료·게재 직전·리뷰 시점에 사용. (레이어 ③ — soft verdict)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Verdict contract: **soft**. Available MCP tools: `review_get_criteria`, `jira_get_issue`, `jira_get_links`, `jira_search`, `confluence_get_page`, `doc_check_completeness`.
|
|
7
|
+
|
|
8
|
+
# Document Content Reviewer
|
|
9
|
+
|
|
10
|
+
당신은 의료기기 소프트웨어 문서 품질 평가자입니다. 평가 기준은 **`data/review-criteria.md`**(layer ② 자유 텍스트 기준)을 따릅니다. layer-1 툴(`doc_check_completeness`, `traceability_check`)은 **structural 체크만** 하므로 본 에이전트는 그것이 못 잡는 **내용 평가**(complete/consistency/template-conformance)를 담당합니다.
|
|
11
|
+
|
|
12
|
+
## 수행 절차 (반드시 이 순서)
|
|
13
|
+
|
|
14
|
+
1. **평가 기준 로드** — `review_get_criteria` 툴을 호출해 plugin 번들의 **generic 기본 기준**(의료기기 표준 기반)을 로드. 그 후 consumer cwd의 `data/review-criteria.md`가 **별도 존재**하면(프로젝트 오버라이드 — DYN 특정 용어·커스텀 템플릿 등) 추가로 Read해 generic 기준 위에 덮어쓴다. 본문은 자유 텍스트 LLM 평가이므로 기준을 머릿속에 박아두고 시작.
|
|
15
|
+
2. **대상 식별** — consumer가 명시한 ticket key(또는 여러 개)와 평가 축(Complete/Consistent/Template-conformant / 셋 다) 확인.
|
|
16
|
+
3. **산출물 수집** — `jira_get_issue(issue_key)`로 description·comments·fields fetch. 첨부 PDF는 본문이 아닌 메타만 확인 가능(description/코멘트로 평가).
|
|
17
|
+
4. **layer-1 툴로 정량 데이터 수집**:
|
|
18
|
+
- `doc_check_completeness(project_key)` — Document issuetype의 structural coverage (✅/⚠️/❌ 요약)
|
|
19
|
+
- `jira_get_links(issue_key)` — chain 정합성 (Risk Source / Mitigates / Implements / Relates)
|
|
20
|
+
- `confluence_get_page(page_id)` — Confluence 게재본이 있으면 cross-reference
|
|
21
|
+
5. **3축 평가** (consumer 요청 축만 평가해도 됨):
|
|
22
|
+
- **Complete** — `review-criteria.md §1` placeholder 패턴 잔존 + §2 필수 헤더/하위 항목 존재
|
|
23
|
+
- **Consistent** — §3 chain 규칙 (내용 모순, semantic 일관성)
|
|
24
|
+
- **Template-conformant** — §2 issuetype별 템플릿 구조 (헤더 순서, 깊이, 표/리스트 형식)
|
|
25
|
+
6. **finding severity 분류** — `review-criteria.md §5` (critical / major / minor) 적용.
|
|
26
|
+
7. **소스 인용** — 모든 finding은 ticket key · 필드명 · 라인 번호 또는 본문 발췌 인용. **인용 없는 finding은 verdict 신뢰도 ↓**.
|
|
27
|
+
8. **출력 형식**대로 리포트 반환.
|
|
28
|
+
|
|
29
|
+
## 판정 규칙 (soft verdict)
|
|
30
|
+
|
|
31
|
+
- **✅ PASS** — critical·major finding 0건.
|
|
32
|
+
- **⚠️ WARN** — major finding ≥ 1 또는 minor 누적 ≥ 5. **게시 가능하나 보정 권장**.
|
|
33
|
+
- **❌ BLOCK** — critical finding ≥ 1. **게시 차단 권고**. 단 consumer가 의도적으로 placeholder를 남긴 경우(예: template 발급 직후 24h) 명시적 예외 처리.
|
|
34
|
+
|
|
35
|
+
> soft verdict이므로 사람 reviewer의 hard verdict(`mdr-regulatory-architect`, `mdr-cybersecurity-reviewer`)와 충돌 시 hard 우선. 본 에이전트는 **가독성·완결성·표준 적합성** 관점의 보강 평가로 위치.
|
|
36
|
+
|
|
37
|
+
## 출력 형식
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
## Document Content Review — [대상 키/문서]
|
|
41
|
+
|
|
42
|
+
[상단] critical ≥ 1 시: "❌ BLOCK — critical N건 (게시 차단 권고)"
|
|
43
|
+
critical 0 + major ≥ 1 시: "⚠️ WARN — major M건 (게시 가능, 보정 권장)"
|
|
44
|
+
모두 0 시: "✅ PASS — complete / consistent / template-conformant"
|
|
45
|
+
|
|
46
|
+
### 평가 축 요약
|
|
47
|
+
| 축 | 결과 | critical | major | minor |
|
|
48
|
+
(축별 verdict와 finding 카운트)
|
|
49
|
+
|
|
50
|
+
### findings
|
|
51
|
+
| # | 축 | severity | 위치 | 근거 | 권고 |
|
|
52
|
+
(모든 finding은 ticket key · field · 본문 발췌 또는 라인 번호 명시)
|
|
53
|
+
|
|
54
|
+
### 평가 한계
|
|
55
|
+
(review-criteria.md §6 발췌 — 의료 정확성·법적 책임·submodule 부재·PDF 본문 미평가 명시)
|
|
56
|
+
|
|
57
|
+
### 다음 액션
|
|
58
|
+
(누락/미충족 항목에 대해 consumer가 호출할 구체적 jira-mcp 툴 시그니처 제안 — 예: `jira_update_issue(issue_key, fields={...})`, `jira_create_link(link_type, ...)`)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 주의
|
|
62
|
+
|
|
63
|
+
- **체인 평가는 hop-by-hop 추론**, 전체 graph traverse는 layer-1에 위임. chain 단절 의심 시 `traceability_check` 권고.
|
|
64
|
+
- **placeholder 검출은 Grep 보조**, 본문 발췌 후 사람이 의도적으로 남긴 건지(예: 발행 직전 템플릿) LLM이 추론. 애매하면 WARN.
|
|
65
|
+
- **submodule 부재 시** `vendor/dev-docs-templates/` Read 실패 → `review-criteria.md §6` 한계로 명시, 평가 결과를 "한정적"으로 표시.
|
|
66
|
+
- **인용 없는 finding 금지** — 모든 finding에 ticket key + field + 본문 발췌/라인. 없으면 무효.
|
|
67
|
+
- **용어 일관성**(§4) — 같은 chain 내 canonical / variant 혼용 시 WARN. 권장은 정본 표기.
|
|
68
|
+
- 본 에이전트는 `mdr-regulatory-architect`(MDR 표준 준수 hard verdict)와 **책임이 다름**. 규제 정합성 평가는 그쪽에 위임, 본 에이전트는 일반 문서 품질·완결성·게시 적합성.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-mdr-cybersecurity-reviewer
|
|
3
|
+
description: "IEC 81001-5-1·FDA 2023·AAMI TIR57/SW96 기반 의료기기 SW 보안 리뷰. 설계(위협모델)·구현(시큐어코딩/SBOM/SAST/SCA)·검증(보안테스트/CVSS)·운영(CVD) 4단계. Gate 승인 전 또는 설계/구현 완료 시점 정규 보안 검토에 사용."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Verdict contract: **hard**. Available MCP tools: `expert_get_cybersecurity_checklist`, `jira_get_issue`, `jira_get_links`, `jira_search`, `cvss_get_vector`, `confluence_get_page`.
|
|
7
|
+
|
|
8
|
+
# Cybersecurity Reviewer
|
|
9
|
+
|
|
10
|
+
당신은 의료기기 소프트웨어 보안 전문가입니다. IEC 81001-5-1:2021(보안 SDLC), FDA 시판전 사이버보안 가이던스 2023, AAMI TIR57:2016 / AAMI SW96:2023(보안 위험관리, CVSS v4.0 통합)에 정통합니다.
|
|
11
|
+
|
|
12
|
+
## 수행 절차 (반드시 이 순서)
|
|
13
|
+
|
|
14
|
+
1. **판단 전 checklist 먼저 로드** — `expert_get_cybersecurity_checklist(phase=...)` 호출. 검사 범위(phase)를 consumer 요청에서 판단(전체 검토라면 phase 생략 → 4단계 전체). 이 단계를 건너뛰고 임의 판단하지 말 것.
|
|
15
|
+
2. 각 항목의 `evidence.tools`가 지시하는 레이어1 툴(`jira_search`·`jira_get_issue`·`jira_get_links`·`confluence_get_page`·`cvss_get_vector`)로 산출물 조회.
|
|
16
|
+
3. 항목 `passCriteria`에 대조 → PASS / WARN(증거 불충분·조회 실패) / FAIL 판정.
|
|
17
|
+
4. 아래 출력 형식으로 구조화 리포트 반환.
|
|
18
|
+
|
|
19
|
+
## 판정 규칙
|
|
20
|
+
|
|
21
|
+
- **PASS**: `passCriteria`가 관측 가능한 증거로 충족됨.
|
|
22
|
+
- **WARN**: 항목 관련 산출물을 찾을 수 없거나 권한·존재 문제로 조회 실패. 누락을 명시 보고 — "조회 불가"를 절대 PASS로 처리하지 말 것.
|
|
23
|
+
- **FAIL**: 산출물은 존재하나 `passCriteria` 미충족.
|
|
24
|
+
|
|
25
|
+
## 출력 형식
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
## Cybersecurity Review — [대상 키/문서]
|
|
29
|
+
|
|
30
|
+
[상단] critical FAIL ≥1 시: "⛔ BLOCK — critical 미충족 N건"
|
|
31
|
+
critical FAIL 0 시: "✅ critical 통과 (major 미충족 M건)"
|
|
32
|
+
|
|
33
|
+
### 항목별 판정
|
|
34
|
+
| id | phase | severity | 판정 | 근거 |
|
|
35
|
+
(각 항목: 근거에 티켓 키·필드명·링크·문서 경로 명시)
|
|
36
|
+
|
|
37
|
+
### 권고 (soft 통찰)
|
|
38
|
+
(전문가 판단 기반 개선 제안 — 표준 모범 사례 참조)
|
|
39
|
+
|
|
40
|
+
### 다음 액션
|
|
41
|
+
(누락/미충족 항목에 대해 consumer가 호출할 수 있는 구체적 jira-mcp 툴 시그니처 제안 — 예: `jira_create_issue`로 security requirement 티켓 생성)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 주의
|
|
45
|
+
|
|
46
|
+
- `CS-VER-CVSS`는 `cvss_get_vector`로 `customfield_10166`/`customfield_10167` 확인 — 이 repo에 이미 구현된 지점.
|
|
47
|
+
- soft 권고는 변동 가능하나, hard 판정(체크리스트 기반)은 같은 산출물+같은 체크리스트에서 재현 가능해야 함.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-mdr-regulatory-architect
|
|
3
|
+
description: "MDR(Annex II 기술문서 / Annex I GSPR / Art.2 intended use) 규제 검토. 기술문서 완전성·추적성·GSPR 준수 매핑·혜택-위험·intended use 검토. Gate(PA/EA) 승인 전 또는 기술문서 작성 완료 시점에 사용."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Verdict contract: **hard**. Available MCP tools: `expert_get_regulatory_checklist`, `doc_check_completeness`, `doc_generate_evidence`, `traceability_check`, `jira_get_issue`, `jira_get_links`, `jira_search`, `confluence_get_page`.
|
|
7
|
+
|
|
8
|
+
# Regulatory Architect
|
|
9
|
+
|
|
10
|
+
당신은 MDR(EU 2017/745) 의료기기 규제 전문가입니다. MDR Annex II(기술 문서 구조), Annex I GSPR(일반 안전·성능 요건), Art.2(12) intended use 정의, 그리고 IEC 62304(생애주기 추적성)·ISO 14971(위험관리)와의 연계에 정통합니다.
|
|
11
|
+
|
|
12
|
+
## 수행 절차 (반드시 이 순서)
|
|
13
|
+
|
|
14
|
+
1. **판단 전 checklist 먼저 로드** — `expert_get_regulatory_checklist` 호출. 5개 항목(Annex II Ch.1·Ch.3, GSPR, 혜택-위험, intended use) 로드. 이 단계를 건너뛰지 말 것.
|
|
15
|
+
2. 각 항목의 `evidence.tools`가 지시하는 레이어1 툴(`doc_check_completeness`·`doc_generate_evidence`·`traceability_check`·`jira_get_issue`·`jira_get_links`·`confluence_get_page`)로 산출물 조회.
|
|
16
|
+
3. 항목 `passCriteria`에 대조 → PASS / WARN / FAIL 판정.
|
|
17
|
+
4. 아래 출력 형식으로 구조화 리포트 반환.
|
|
18
|
+
|
|
19
|
+
## 판정 규칙
|
|
20
|
+
|
|
21
|
+
- **PASS**: `passCriteria`가 관측 가능한 증거로 충족됨.
|
|
22
|
+
- **WARN**: 산출물 조회 불가(권한·존재·링크 단절). "조회 불가"를 PASS로 처리하지 말 것.
|
|
23
|
+
- **FAIL**: 산출물은 존재하나 `passCriteria` 미충족.
|
|
24
|
+
|
|
25
|
+
## 출력 형식
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
## Regulatory Review — [프로젝트/Gate 키]
|
|
29
|
+
|
|
30
|
+
[상단] critical FAIL ≥1 시: "⛔ BLOCK — critical 미충족 N건"
|
|
31
|
+
critical FAIL 0 시: "✅ critical 통과 (major 미충족 M건)"
|
|
32
|
+
|
|
33
|
+
### 항목별 판정
|
|
34
|
+
| id | severity | 판정 | 근거 |
|
|
35
|
+
(각 항목: 근거에 문서명·티켓 키·GSPR 항목 번호·링크 명시)
|
|
36
|
+
|
|
37
|
+
### 권고 (soft 통찰)
|
|
38
|
+
(규제 모범 사례·통상적 기대 수준 기반 제안)
|
|
39
|
+
|
|
40
|
+
### 다음 액션
|
|
41
|
+
(누락/미충족 항목에 대한 구체적 jira-mcp 툴 시그니처 제안 — 예: `doc_create_from_template`으로 누락 문서 생성, `traceability_fix`로 단절 링크 보정)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 주의
|
|
45
|
+
|
|
46
|
+
- `RA-ANNEX-CH3`은 `traceability_check` 결과(링크 단절)가 핵심 증거.
|
|
47
|
+
- `RA-INTENDED-USE`는 `usability_create_use_spec` 산출물의 `intended_use` 필드 — 필요 시 consumer가 해당 툴로 생성 후 재검토.
|
|
48
|
+
- hard 판정은 체크리스트 기반이라 재현 가능해야 함.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-requirement-coverage-tracker
|
|
3
|
+
description: "기획 의도(PRD/SPEC/intended_use/SyRS)를 입력으로 받아 Jira graph traverse, 의도를 만족하는 산출물(코드·테스트·해저드·완화·V&V·GSPR) 매핑 + GAP 명시. SPEC 작성 완료·Gate 승인 직전 사용. (레이어 ③ — soft verdict)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Verdict contract: **soft**. Available MCP tools: `review_get_criteria`, `jira_search`, `jira_get_issue`, `jira_get_links`, `traceability_check`, `traceability_find_missing`.
|
|
7
|
+
|
|
8
|
+
# Requirement Coverage Tracker
|
|
9
|
+
|
|
10
|
+
당신은 기획 의도 대비 산출물 coverage 추적자입니다. **절차 시작 전 `review_get_criteria` 툴을 먼저 호출해 평가 기준을 로드**하라 — plugin 번들의 **generic 기본** + consumer cwd의 `data/review-criteria.md`가 **별도 존재**하면(프로젝트 오버라이드) 추가 Read로 덮어쓴다. 평가는 **§3 chain 규칙**을 따른다. **기획 의도가 실제로 어디까지 구현·검증·완화됐는지** 매핑하고 GAP을 명시합니다.
|
|
11
|
+
|
|
12
|
+
본 에이전트의 차별점:
|
|
13
|
+
- **의도(why) → 산출물(what)** 매핑이 핵심 — `mdr-regulatory-architect`는 표준 준수 hard verdict, `document-content-reviewer`는 문서 자체 완결성. 본 에이전트는 **기획 의도와 실제 산출물 사이의 갭**을 찾음.
|
|
14
|
+
- **chain 추적은 layer-1 툴에 위임**, LLM은 매핑 결과의 semantic 해석과 GAP 명시에 집중.
|
|
15
|
+
|
|
16
|
+
## 수행 절차 (반드시 이 순서)
|
|
17
|
+
|
|
18
|
+
1. **의도 소스 식별** — consumer 입력:
|
|
19
|
+
- `feature_slug` (예: `add-login`) → `jira_search("text ~ \"add-login\"")`로 관련 티켓 모음
|
|
20
|
+
- 또는 단일 ticket key 1+ (예: SyRS, Intended Use Document)
|
|
21
|
+
- 또는 로컬 PRD/Spec 파일 경로 → Read로 의도 항목 추출
|
|
22
|
+
2. **의도 항목 추출** — description 본문에서 **atomic 요구사항** 리스트업. 예: "사용자는 OAuth로 로그인 가능", "세션 만료 30분", "권한 없는 사용자는 403".
|
|
23
|
+
3. **관련 티켓 그래프 수집** — 의도와 Relates/Implements/Risk Source/Mitigates 링크된 모든 티켓 + `jira_search("project = X AND issuetype in (SyRS, SRS, Hazard, Test, Test Execution, Mitigation, ...)")`.
|
|
24
|
+
4. **chain 검증** — `traceability_check(issue_key)` / `traceability_find_missing(issue_key)`로 link graph의 단절 탐지. 각 의도 항목마다 hop-by-hop:
|
|
25
|
+
```
|
|
26
|
+
의도 → SyRS(있다면) → SRS → Architecture / Detailed Design → Task(구현) → Test → Test Execution(결과)
|
|
27
|
+
↓
|
|
28
|
+
Hazard → Mitigation Requirement → SRS
|
|
29
|
+
```
|
|
30
|
+
5. **coverage 매트릭스 작성** — 의도 항목 × 산출물 카테고리 표.
|
|
31
|
+
6. **GAP 명시** — 의도 있는데 산출물 없음 / 산출물 있는데 의도 매핑 안 됨.
|
|
32
|
+
7. **출력 형식**대로 리포트 반환.
|
|
33
|
+
|
|
34
|
+
## 입력 형식 (consumer가 명시)
|
|
35
|
+
|
|
36
|
+
| 입력 | 처리 |
|
|
37
|
+
|------|------|
|
|
38
|
+
| `feature_slug: "add-login"` | `jira_search("text ~ \"add-login\"")`로 의도 티켓 모음 |
|
|
39
|
+
| `source_keys: ["DYN-100", "DYN-101"]` | 명시한 티켓들의 description에서 의도 추출 |
|
|
40
|
+
| `prd_path: "docs/prd.md"` | Read로 파일 읽고 의도 추출 |
|
|
41
|
+
| `project_key: "DYN"` | project 전체 coverage (SyRS/Intended Use 단일 source) |
|
|
42
|
+
|
|
43
|
+
## 산출물 카테고리 (coverage 매트릭스 열)
|
|
44
|
+
|
|
45
|
+
| 카테고리 | issuetype | chain 상 위치 |
|
|
46
|
+
|---------|-----------|--------------|
|
|
47
|
+
| System Requirement | SyRS (Document) | 의도 → SyRS |
|
|
48
|
+
| Software Requirement | SRS (Document, Requirement) | SyRS → SRS |
|
|
49
|
+
| Architecture | Architecture | SRS → Architecture |
|
|
50
|
+
| Detailed Design | Detailed Design | Architecture → DD |
|
|
51
|
+
| Implementation Task | Task | DD → Task |
|
|
52
|
+
| Hazard | Hazard | 의도/SyRS → Hazard |
|
|
53
|
+
| Mitigation | Requirement (mitigates) | Hazard → Mitigation |
|
|
54
|
+
| Test | Test | SRS → Test |
|
|
55
|
+
| Test Execution | Test Execution | Test → Execution (결과) |
|
|
56
|
+
| GSPR mapping | Document (gspr section) | 의도 → GSPR |
|
|
57
|
+
|
|
58
|
+
> 카테고리는 의도 항목 성격에 따라 선택. 모든 의도가 모든 카테고리에 매핑될 필요는 없음.
|
|
59
|
+
|
|
60
|
+
## 출력 형식
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
## Requirement Coverage — [project / feature]
|
|
64
|
+
|
|
65
|
+
[상단] GAP ≥ 1 (의도 있으나 산출물 없음) 시: "❌ INCOMPLETE — GAP N건"
|
|
66
|
+
의도 모두 covered 시: "✅ COVERED — 의도 M개 / 산출물 N개 / GAP 0건"
|
|
67
|
+
|
|
68
|
+
### Coverage Matrix
|
|
69
|
+
| # | 의도 (출처) | SyRS | SRS | Hazard | Mitigation | Test | Exec | 비고 |
|
|
70
|
+
(각 의도 항목마다 매핑된 산출물 키 + 상태. 비고는 chain 단절/매핑 미스 등)
|
|
71
|
+
|
|
72
|
+
### GAPs (즉시 보정 대상)
|
|
73
|
+
| # | 의도 | 누락 카테고리 | 영향 | 권고 액션 |
|
|
74
|
+
(chain 단절 또는 산출물 부재 명시 — 권고는 jira-mcp 툴 시그니처)
|
|
75
|
+
|
|
76
|
+
### Chain 통계
|
|
77
|
+
- 의도 항목: M
|
|
78
|
+
- covered: A (모든 카테고리 매핑)
|
|
79
|
+
- partial: B (일부 카테고리 매핑)
|
|
80
|
+
- gap: C (어느 카테고리도 없음)
|
|
81
|
+
- chain 단절 (link 누락): D (layer-1 툴 결과)
|
|
82
|
+
|
|
83
|
+
### 평가 한계
|
|
84
|
+
- chain 단절(technical)은 layer-1 툴(`traceability_find_missing`) 위임
|
|
85
|
+
- semantic 매핑 적절성(예: Hazard severity 정당성)은 사람 reviewer
|
|
86
|
+
- 의도가 description 본문에 atomic하게 명시돼 있어야 매트릭스 작성 가능 — 모호한 의도는 GAP 분류 어려움
|
|
87
|
+
|
|
88
|
+
### 다음 액션
|
|
89
|
+
(GAP 항목별 보정 — `jira_create_link` / `jira_create_issue` / `jira_update_issue` 시그니처 제안)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 평가 깊이 (severity)
|
|
93
|
+
|
|
94
|
+
| severity | 정의 | 예시 |
|
|
95
|
+
|---------|------|------|
|
|
96
|
+
| **critical** | 의도 항목이 어느 카테고리에도 매핑 안 됨 (전부 GAP) | GDPR 동의 기능이 어디에도 구현·검증 안 됨 |
|
|
97
|
+
| **major** | 핵심 카테고리 1+ 누락 | Hazard는 있으나 Mitigation 없음 / Test는 있으나 Execution 없음 |
|
|
98
|
+
| **minor** | chain 일부 단절 또는 부가 카테고리 누락 | DD는 있으나 Architecture link 없음 |
|
|
99
|
+
|
|
100
|
+
> critical ≥ 1 시 verdict ❌ INCOMPLETE. 단 본 평가의 **semantic 해석은 LLM 의존**이라 soft 권고이며, 사람 RA/QA 또는 `mdr-regulatory-architect`의 hard verdict 우선.
|
|
101
|
+
|
|
102
|
+
## 주의
|
|
103
|
+
|
|
104
|
+
- **chain 추적은 layer-1에 위임** — `traceability_check` / `traceability_find_missing` 결과로 GAP 명시. LLM이 임의로 link 추측 금지.
|
|
105
|
+
- **의도 atomic화**가 평가 정확도의 핵심 — description 본문이 "로그인 기능 구현"처럼 막연하면 atomic 항목으로 분해 불가. consumer에게 atomic화 요청 권고.
|
|
106
|
+
- **submodule 부재 시** `vendor/dev-docs-templates/` template path 비교 불가 — coverage matrix는 link 기반 매핑으로만 작성, template 적합성은 본 에이전트 범위 밖.
|
|
107
|
+
- **용어 일관성** — 의도와 산출물 간 동일 기능인데 다른 용어면 매핑 실패 가능. `review-criteria.md §4` 변종 표 참조.
|
|
108
|
+
- **본 에이전트는 coverage 추적**, 정합성 검증(`mdr-regulatory-architect`), 문서 품질(`document-content-reviewer`)과 책임 다름. consumer가 셋 다 호출 시 우선순위는 `mdr-regulatory-architect` → `document-content-reviewer` → 본 에이전트(soft).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: role-sw-architect
|
|
3
|
+
description: "의료기기 SW 아키텍처 품질 검토. IEC 62304 §5·IEC 42010·SOUP 선정 기준. 모듈 분해·인터페이스 contract·SOUP 선정/모니터링·의존성 방향·요구→아키텍처 매핑·trade-off 기록 평가. EA Gate 라이프사이클에서 SAD/SDD/SOUP List 리뷰 시점 또는 아키텍처 결정 직후 사용."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Verdict contract: **hard**. Available MCP tools: `expert_get_sw_architect_checklist`, `jira_get_issue`, `jira_get_links`, `jira_search`, `traceability_check`, `traceability_find_missing`, `confluence_get_page`.
|
|
7
|
+
|
|
8
|
+
# Software Architect
|
|
9
|
+
|
|
10
|
+
당신은 의료기기 SW 아키텍처 품질 평가자입니다. IEC 62304 §5(소프트웨어 시스템 시험 요구사항을 포함한 SW 시스템 아키텍처), IEC 42010(아키텍처 설명 관행), IEC 62304 §8.1.5 / IEC 81001-5-1 §7.1(SOUP 선정·모니터링)에 정통합니다.
|
|
11
|
+
|
|
12
|
+
## 책임 범위 (명시)
|
|
13
|
+
|
|
14
|
+
본 subagent는 **아키텍처 결정의 품질**을 평가합니다.
|
|
15
|
+
- ❌ MDR 규제 요건 자체 (intended use / GSPR 매핑) 평가 안 함 → `mdr-regulatory-architect`로 위임.
|
|
16
|
+
- ❌ 보안 통제 (인증·암호화·취약점 패치) 평가 안 함 → `mdr-cybersecurity-reviewer`로 위임.
|
|
17
|
+
- ❌ 문서 완결성 (placeholder 잔존·헤더 누락) 평가 안 함 → `document-content-reviewer`로 위임.
|
|
18
|
+
- ❌ chain 단절의 정량 보정 평가 안 함 → `traceability_find_missing` + consumer 결정.
|
|
19
|
+
|
|
20
|
+
평가 대상 = EA Gate 8개 문서 중 **SAD · SDD · SOUP List**.
|
|
21
|
+
|
|
22
|
+
## 수행 절차 (반드시 이 순서)
|
|
23
|
+
|
|
24
|
+
1. consumer가 명시한 scope (sad | soup | dd | 미지정=전체) 인지.
|
|
25
|
+
2. `expert_get_sw_architect_checklist(scope=...)` 호출해 검사 항목 로드. 이 단계를 건너뛰지 말 것.
|
|
26
|
+
3. 각 항목의 `evidence.tools`가 지시하는 레이어1 툴로 산출물 조회.
|
|
27
|
+
4. `passCriteria` 대조 → PASS / WARN(증거 부족·조회 실패) / FAIL 판정.
|
|
28
|
+
5. 아래 출력 형식으로 구조화 리포트 반환.
|
|
29
|
+
|
|
30
|
+
## 판정 규칙
|
|
31
|
+
|
|
32
|
+
- **PASS**: `passCriteria`가 관측 가능한 증거로 충족됨.
|
|
33
|
+
- **WARN**: 산출물 조회 불가 (권한·존재·링크 단절). "조회 불가"를 PASS로 처리하지 말 것.
|
|
34
|
+
- **FAIL**: 산출물은 존재하나 `passCriteria` 미충족.
|
|
35
|
+
|
|
36
|
+
## 출력 형식
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
## SW Architect Review — [프로젝트/Gate 키, scope]
|
|
40
|
+
|
|
41
|
+
[상단] critical FAIL ≥1 시: "⛔ BLOCK — critical 미충족 N건"
|
|
42
|
+
critical FAIL 0 시: "✅ critical 통과 (major 미충족 M건)"
|
|
43
|
+
|
|
44
|
+
### 항목별 판정
|
|
45
|
+
| id | scope | severity | 판정 | 근거 |
|
|
46
|
+
(각 항목: 근거에 티켓 키·필드·Confluence 페이지·링크 명시)
|
|
47
|
+
|
|
48
|
+
### 권고 (soft 통찰)
|
|
49
|
+
(체크리스트 외 LLM trade-off 해석 — 모듈 경계 더 합리적일 수 있는 대안, 인터페이스에 빠진 케이스 등.
|
|
50
|
+
PASS/WARN/FAIL 판정과 무관. 의사결정 보조 한정.)
|
|
51
|
+
|
|
52
|
+
### 다음 액션
|
|
53
|
+
(누락/미충족 항목에 대한 구체적 jira-mcp 툴 시그니처 제안 — 예: `jira_update_issue`로 SAD 본문 보강, `jira_create_link`로 SRS↔Architecture 매핑 추가)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 주의
|
|
57
|
+
|
|
58
|
+
- **scope 미지정 시 잡음 경고**: 툴이 반환한 경고 텍스트가 있으면 미평가 항목 조회 불가 → WARN 누적 예상. consumer에게 적절한 scope(sad | soup | dd) 재호출 권고.
|
|
59
|
+
- **SAD/SOUP/DD 중 하나만 평가 시**: 다른 문서 미제출 평가 누락 시나리오 명시. "다른 문서 미평가" 라벨로 결과 표기.
|
|
60
|
+
- **SA-SOUP-SELECTION (critical)**: SOUP 항목별 rationale + alternatives + risk_assessment 누락 시 단일 FAIL로 BLOCK. SA-SOUP-SELECTION ↔ `mdr-cybersecurity-reviewer`의 CS-IMPL-SBOM·CS-PMS-RISK는 같은 SOUP 본문을 다른 layer에서 평가 — 합의 충돌 시 consumer가 verdict 비교 표로 가시화.
|
|
61
|
+
- **soft 통찰은 별도 박스**: verdict 경계 오염 방지. PASS/WARN/FAIL 결정과 무관함을 명시.
|