@neobiotechlabs/neobiotech-dev-agent 0.1.37 → 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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +13 -1
- package/.mcp.json +6 -2
- package/dist/doctor.js +15106 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.js +1212 -886
- package/dist/index.js.map +1 -1
- package/dist/setup-codex.js +164 -0
- package/dist/setup-codex.js.map +1 -0
- package/package.json +4 -33
- package/skills/doc-render/SKILL.md +2 -2
- package/README.md +0 -493
|
@@ -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
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neobiotechlabs/neobiotech-dev-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
4
4
|
"description": "Jira & Confluence MCP Server for Claude Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"neobiotech-dev-agent": "dist/index.js"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc --noEmit && tsup && node scripts/copy-pdfkit-data.mjs && node scripts/copy-fonts.mjs && node scripts/copy-plantuml-jar.mjs",
|
|
12
|
-
"dev": "tsup --watch",
|
|
13
|
-
"start": "node dist/index.js",
|
|
14
|
-
"test": "vitest run",
|
|
15
|
-
"test:watch": "vitest",
|
|
16
|
-
"prepublishOnly": "npm run build && node scripts/sync-plugin-version.mjs && chmod +x dist/index.js",
|
|
17
|
-
"version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin/plugin.json .claude-plugin/marketplace.json"
|
|
18
|
-
},
|
|
19
10
|
"keywords": [
|
|
20
11
|
"mcp",
|
|
21
12
|
"jira",
|
|
@@ -24,19 +15,6 @@
|
|
|
24
15
|
],
|
|
25
16
|
"author": "NeoBiotech",
|
|
26
17
|
"license": "MIT",
|
|
27
|
-
"files": [
|
|
28
|
-
"dist",
|
|
29
|
-
"vendor/dev-docs-templates/templates",
|
|
30
|
-
"data",
|
|
31
|
-
".claude-plugin",
|
|
32
|
-
"skills",
|
|
33
|
-
"agents",
|
|
34
|
-
".mcp.json"
|
|
35
|
-
],
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"registry": "https://registry.npmjs.org",
|
|
38
|
-
"access": "public"
|
|
39
|
-
},
|
|
40
18
|
"dependencies": {
|
|
41
19
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
42
20
|
"adm-zip": "^0.5.17",
|
|
@@ -46,15 +24,8 @@
|
|
|
46
24
|
"plantuml-cli": "1.2026.1",
|
|
47
25
|
"zod": "^3.24.0"
|
|
48
26
|
},
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"@types/pdfkit": "^0.17.6",
|
|
53
|
-
"@types/pngjs": "^6.0.5",
|
|
54
|
-
"playwright": "^1.61.1",
|
|
55
|
-
"pngjs": "^7.0.0",
|
|
56
|
-
"tsup": "^8.5.1",
|
|
57
|
-
"typescript": "^5.7.0",
|
|
58
|
-
"vitest": "^4.1.6"
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"registry": "https://registry.npmjs.org",
|
|
29
|
+
"access": "public"
|
|
59
30
|
}
|
|
60
31
|
}
|
|
@@ -14,9 +14,9 @@ description에 미러한다. 자동 초안 + 사용자 최종 리뷰 방식.
|
|
|
14
14
|
- 사용자가 "DYN-8 intended use 문서 작성", "<ticket> <template> 문서 만들어" 등으로 요청
|
|
15
15
|
- 또는 티켓 타입/요약에서 템플릿을 추론한 뒤 사용자에게 확인
|
|
16
16
|
|
|
17
|
-
지원 템플릿(현재
|
|
17
|
+
지원 템플릿(현재 18개):
|
|
18
18
|
- **dev** (4): `prd`, `spec`, `plan`, `tasks`
|
|
19
|
-
- **mdr/PA gate** (
|
|
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
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
21
|
|
|
22
22
|
모두 freeform 모드 — 메타 변수 치환 + 빈 데이터 표·AI 지침은 consumer가 채움. (table-map 모드는 vendor 템플릿 구조상 불필요 — 모든 템플릿이 freeform 패턴.)
|