@neobiotechlabs/neobiotech-dev-agent 0.1.10 → 0.1.11
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 +1 -1
- package/dist/index.js +78 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"source": "npm",
|
|
11
11
|
"package": "@neobiotechlabs/neobiotech-dev-agent",
|
|
12
12
|
"registry": "https://registry.npmjs.org",
|
|
13
|
-
"version": "0.1.
|
|
13
|
+
"version": "0.1.11"
|
|
14
14
|
},
|
|
15
15
|
"description": "의료기기 SW 규제 개발 자동화 (Jira·Confluence·Risk·CVSS·Xray·IEC 62304/62366·MDR·문서 렌더)",
|
|
16
16
|
"category": "medical-device",
|
package/dist/index.js
CHANGED
|
@@ -14666,6 +14666,9 @@ __export(markdown_exports, {
|
|
|
14666
14666
|
function stripFrontmatter(md) {
|
|
14667
14667
|
return md.replace(FRONTMATTER_RE, "");
|
|
14668
14668
|
}
|
|
14669
|
+
function stripLeftoverStars(s2) {
|
|
14670
|
+
return s2.replace(/\*\*/g, "");
|
|
14671
|
+
}
|
|
14669
14672
|
function inlineTokensToAdf(tokens, parentMarks) {
|
|
14670
14673
|
if (!Array.isArray(tokens)) return [];
|
|
14671
14674
|
const out = [];
|
|
@@ -14687,22 +14690,22 @@ function inlineTokensToAdf(tokens, parentMarks) {
|
|
|
14687
14690
|
break;
|
|
14688
14691
|
case "text":
|
|
14689
14692
|
case "escape":
|
|
14690
|
-
out.push({ type: "text", text: String(tok.text ?? ""), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14693
|
+
out.push({ type: "text", text: stripLeftoverStars(String(tok.text ?? "")), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14691
14694
|
break;
|
|
14692
14695
|
case "link":
|
|
14693
14696
|
out.push(...inlineTokensToAdf(tok.tokens, parentMarks));
|
|
14694
14697
|
break;
|
|
14695
14698
|
case "image":
|
|
14696
|
-
if (tok.text) out.push({ type: "text", text: String(tok.text), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14699
|
+
if (tok.text) out.push({ type: "text", text: stripLeftoverStars(String(tok.text)), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14697
14700
|
break;
|
|
14698
14701
|
case "br":
|
|
14699
14702
|
out.push({ type: "text", text: "\n", marks: parentMarks.length ? parentMarks : void 0 });
|
|
14700
14703
|
break;
|
|
14701
14704
|
case "html":
|
|
14702
|
-
out.push({ type: "text", text: String(tok.text ?? "").replace(/<[^>]+>/g, ""), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14705
|
+
out.push({ type: "text", text: stripLeftoverStars(String(tok.text ?? "").replace(/<[^>]+>/g, "")), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14703
14706
|
break;
|
|
14704
14707
|
default:
|
|
14705
|
-
if (tok.text) out.push({ type: "text", text: String(tok.text), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14708
|
+
if (tok.text) out.push({ type: "text", text: stripLeftoverStars(String(tok.text)), marks: parentMarks.length ? parentMarks : void 0 });
|
|
14706
14709
|
}
|
|
14707
14710
|
}
|
|
14708
14711
|
return out;
|
|
@@ -14812,9 +14815,12 @@ function markdownToAdf(md) {
|
|
|
14812
14815
|
function escapeHtml(s2) {
|
|
14813
14816
|
return s2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
14814
14817
|
}
|
|
14818
|
+
function stripLeftoverStarsFromHtml(html) {
|
|
14819
|
+
return html.split(/(<code>[\s\S]*?<\/code>)/g).map((part, i2) => i2 % 2 === 1 ? part : part.replace(/\*\*/g, "")).join("");
|
|
14820
|
+
}
|
|
14815
14821
|
function inlineToHtml(text) {
|
|
14816
14822
|
const html = g.parseInline(text ?? "");
|
|
14817
|
-
return (typeof html === "string" ? html : "").replace(/<br\s*\/?>/gi, "<br/>");
|
|
14823
|
+
return stripLeftoverStarsFromHtml(typeof html === "string" ? html : "").replace(/<br\s*\/?>/gi, "<br/>");
|
|
14818
14824
|
}
|
|
14819
14825
|
function listItemToHtml(item) {
|
|
14820
14826
|
const subs = Array.isArray(item?.tokens) ? item.tokens : [];
|
|
@@ -31961,6 +31967,7 @@ init_jira_client();
|
|
|
31961
31967
|
|
|
31962
31968
|
// src/confluence-client.ts
|
|
31963
31969
|
init_src();
|
|
31970
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
31964
31971
|
var ConfluenceClient = class {
|
|
31965
31972
|
baseUrl;
|
|
31966
31973
|
auth;
|
|
@@ -31981,22 +31988,44 @@ var ConfluenceClient = class {
|
|
|
31981
31988
|
getBaseUrl() {
|
|
31982
31989
|
return this.baseUrl;
|
|
31983
31990
|
}
|
|
31991
|
+
/**
|
|
31992
|
+
* 공통 fetch 래퍼 — timeout(AbortController) + 인증 헤더 + 에러 정규화.
|
|
31993
|
+
* label은 에러 메시지 식별용(get/create/update/...). 빈 응답은 null 반환.
|
|
31994
|
+
* timeout 초과 시 throw(`Confluence <label> timed out after Ns`).
|
|
31995
|
+
*/
|
|
31996
|
+
async request(url, init) {
|
|
31997
|
+
const controller = new AbortController();
|
|
31998
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
31999
|
+
try {
|
|
32000
|
+
const resp = await fetch(url, {
|
|
32001
|
+
method: init.method || "GET",
|
|
32002
|
+
headers: { ...this.headers(), Authorization: this.authHeader() },
|
|
32003
|
+
body: init.body,
|
|
32004
|
+
signal: controller.signal
|
|
32005
|
+
});
|
|
32006
|
+
if (!resp.ok) {
|
|
32007
|
+
throw new Error(`Confluence ${init.label} ${resp.status}: ${await resp.text()}`);
|
|
32008
|
+
}
|
|
32009
|
+
const text = await resp.text();
|
|
32010
|
+
return text ? JSON.parse(text) : null;
|
|
32011
|
+
} catch (err) {
|
|
32012
|
+
if (err?.name === "AbortError") {
|
|
32013
|
+
throw new Error(`Confluence ${init.label} timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`);
|
|
32014
|
+
}
|
|
32015
|
+
throw err;
|
|
32016
|
+
} finally {
|
|
32017
|
+
clearTimeout(timer);
|
|
32018
|
+
}
|
|
32019
|
+
}
|
|
31984
32020
|
async getPage(pageId, expand) {
|
|
31985
32021
|
const params = expand?.length ? `?expand=${expand.join(",")}` : "";
|
|
31986
|
-
|
|
31987
|
-
`${this.baseUrl}/wiki/rest/api/content/${pageId}${params}`,
|
|
31988
|
-
{ headers: { ...this.headers(), Authorization: this.authHeader() } }
|
|
31989
|
-
);
|
|
31990
|
-
if (!resp.ok) throw new Error(`Confluence get ${resp.status}: ${await resp.text()}`);
|
|
31991
|
-
return resp.json();
|
|
32022
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}${params}`, { label: "get" });
|
|
31992
32023
|
}
|
|
31993
32024
|
async search(cql, limit = 25) {
|
|
31994
|
-
|
|
32025
|
+
return this.request(
|
|
31995
32026
|
`${this.baseUrl}/wiki/rest/api/content/search?cql=${encodeURIComponent(cql)}&limit=${limit}`,
|
|
31996
|
-
{
|
|
32027
|
+
{ label: "search" }
|
|
31997
32028
|
);
|
|
31998
|
-
if (!resp.ok) throw new Error(`Confluence search ${resp.status}: ${await resp.text()}`);
|
|
31999
|
-
return resp.json();
|
|
32000
32029
|
}
|
|
32001
32030
|
async createPage(spaceKey, title, body, parentId) {
|
|
32002
32031
|
const payload = {
|
|
@@ -32013,65 +32042,44 @@ var ConfluenceClient = class {
|
|
|
32013
32042
|
if (parentId) {
|
|
32014
32043
|
payload.ancestors = [{ id: parentId }];
|
|
32015
32044
|
}
|
|
32016
|
-
|
|
32017
|
-
|
|
32018
|
-
|
|
32019
|
-
|
|
32020
|
-
|
|
32021
|
-
body: JSON.stringify(payload)
|
|
32022
|
-
}
|
|
32023
|
-
);
|
|
32024
|
-
if (!resp.ok) throw new Error(`Confluence create ${resp.status}: ${await resp.text()}`);
|
|
32025
|
-
return resp.json();
|
|
32045
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content`, {
|
|
32046
|
+
method: "POST",
|
|
32047
|
+
label: "create",
|
|
32048
|
+
body: JSON.stringify(payload)
|
|
32049
|
+
});
|
|
32026
32050
|
}
|
|
32027
32051
|
async updatePage(pageId, title, body, version2) {
|
|
32028
|
-
|
|
32029
|
-
|
|
32030
|
-
|
|
32031
|
-
|
|
32032
|
-
|
|
32033
|
-
|
|
32034
|
-
|
|
32035
|
-
|
|
32036
|
-
|
|
32037
|
-
|
|
32038
|
-
|
|
32039
|
-
value: body,
|
|
32040
|
-
representation: "storage"
|
|
32041
|
-
}
|
|
32052
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}`, {
|
|
32053
|
+
method: "PUT",
|
|
32054
|
+
label: "update",
|
|
32055
|
+
body: JSON.stringify({
|
|
32056
|
+
type: "page",
|
|
32057
|
+
title,
|
|
32058
|
+
version: { number: version2 + 1 },
|
|
32059
|
+
body: {
|
|
32060
|
+
storage: {
|
|
32061
|
+
value: body,
|
|
32062
|
+
representation: "storage"
|
|
32042
32063
|
}
|
|
32043
|
-
}
|
|
32044
|
-
}
|
|
32045
|
-
);
|
|
32046
|
-
if (!resp.ok) throw new Error(`Confluence update ${resp.status}: ${await resp.text()}`);
|
|
32047
|
-
return resp.json();
|
|
32064
|
+
}
|
|
32065
|
+
})
|
|
32066
|
+
});
|
|
32048
32067
|
}
|
|
32049
32068
|
async deletePage(pageId) {
|
|
32050
|
-
|
|
32051
|
-
|
|
32052
|
-
|
|
32053
|
-
|
|
32054
|
-
headers: { ...this.headers(), Authorization: this.authHeader() }
|
|
32055
|
-
}
|
|
32056
|
-
);
|
|
32057
|
-
if (!resp.ok) throw new Error(`Confluence delete ${resp.status}: ${await resp.text()}`);
|
|
32069
|
+
await this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}`, {
|
|
32070
|
+
method: "DELETE",
|
|
32071
|
+
label: "delete"
|
|
32072
|
+
});
|
|
32058
32073
|
return { success: true };
|
|
32059
32074
|
}
|
|
32060
32075
|
async getSpaces() {
|
|
32061
|
-
|
|
32062
|
-
`${this.baseUrl}/wiki/rest/api/space?limit=100`,
|
|
32063
|
-
{ headers: { ...this.headers(), Authorization: this.authHeader() } }
|
|
32064
|
-
);
|
|
32065
|
-
if (!resp.ok) throw new Error(`Confluence spaces ${resp.status}: ${await resp.text()}`);
|
|
32066
|
-
return resp.json();
|
|
32076
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/space?limit=100`, { label: "spaces" });
|
|
32067
32077
|
}
|
|
32068
32078
|
async getPageChildren(pageId, limit = 25) {
|
|
32069
|
-
|
|
32079
|
+
return this.request(
|
|
32070
32080
|
`${this.baseUrl}/wiki/rest/api/content/${pageId}/child/page?limit=${limit}`,
|
|
32071
|
-
{
|
|
32081
|
+
{ label: "children" }
|
|
32072
32082
|
);
|
|
32073
|
-
if (!resp.ok) throw new Error(`Confluence children ${resp.status}: ${await resp.text()}`);
|
|
32074
|
-
return resp.json();
|
|
32075
32083
|
}
|
|
32076
32084
|
};
|
|
32077
32085
|
|
|
@@ -32389,6 +32397,7 @@ var registerJiraCrudTools = (ctx2) => {
|
|
|
32389
32397
|
|
|
32390
32398
|
// src/tools/confluence.ts
|
|
32391
32399
|
init_markdown();
|
|
32400
|
+
var STORAGE_BODY_WARN_BYTES = 2 * 1024 * 1024;
|
|
32392
32401
|
var registerConfluenceTools = (ctx2) => {
|
|
32393
32402
|
const { server: server2, confluence: confluence2 } = ctx2;
|
|
32394
32403
|
server2.tool("confluence_get_page", "Get a Confluence page by ID", {
|
|
@@ -32448,6 +32457,9 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
32448
32457
|
page_id: external_exports.string().optional().describe("Existing page ID. When provided, the page is UPDATED (current version fetched then incremented). When omitted, a NEW page is created.")
|
|
32449
32458
|
}, async ({ space_key, title, markdown, parent_page_id, page_id }) => {
|
|
32450
32459
|
const body = markdownToStorageFormat(markdown);
|
|
32460
|
+
const bodyBytes = Buffer.byteLength(body, "utf8");
|
|
32461
|
+
const warning = bodyBytes > STORAGE_BODY_WARN_BYTES ? `storage body is ${bodyBytes} bytes (> ${STORAGE_BODY_WARN_BYTES}). Confluence may reject or render slowly \u2014 consider splitting into child pages.` : void 0;
|
|
32462
|
+
if (warning) console.error(`[confluence_publish_doc] ${warning}`);
|
|
32451
32463
|
let result;
|
|
32452
32464
|
let mode;
|
|
32453
32465
|
if (page_id) {
|
|
@@ -32472,7 +32484,9 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
32472
32484
|
space_key,
|
|
32473
32485
|
version: result?.version?.number,
|
|
32474
32486
|
url,
|
|
32475
|
-
body_chars: body.length
|
|
32487
|
+
body_chars: body.length,
|
|
32488
|
+
body_bytes: bodyBytes,
|
|
32489
|
+
...warning ? { warning } : {}
|
|
32476
32490
|
}, null, 2)
|
|
32477
32491
|
}]
|
|
32478
32492
|
};
|
|
@@ -33994,7 +34008,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
|
|
|
33994
34008
|
var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
|
|
33995
34009
|
var server = new McpServer({
|
|
33996
34010
|
name: "jira-confluence",
|
|
33997
|
-
version: "0.1.
|
|
34011
|
+
version: "0.1.11"
|
|
33998
34012
|
});
|
|
33999
34013
|
var ctx = { server, jira, confluence, risk, xray };
|
|
34000
34014
|
registerJiraCrudTools(ctx);
|