@neobiotechlabs/neobiotech-dev-agent 0.1.10 → 0.1.12
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 +84 -65
- 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.12"
|
|
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;
|
|
@@ -14731,7 +14734,12 @@ function listItemToBlocks(item) {
|
|
|
14731
14734
|
const subs = Array.isArray(item?.tokens) ? item.tokens : [];
|
|
14732
14735
|
const blocks = [];
|
|
14733
14736
|
for (const sub of subs) {
|
|
14734
|
-
const
|
|
14737
|
+
const tok = sub;
|
|
14738
|
+
if (tok?.type === "text" && Array.isArray(tok.tokens)) {
|
|
14739
|
+
blocks.push(paragraphFromTokens(tok.text, tok.tokens));
|
|
14740
|
+
continue;
|
|
14741
|
+
}
|
|
14742
|
+
const b2 = tokenToAdfBlock(tok);
|
|
14735
14743
|
if (b2) blocks.push(b2);
|
|
14736
14744
|
}
|
|
14737
14745
|
if (!blocks.length) {
|
|
@@ -14812,9 +14820,12 @@ function markdownToAdf(md) {
|
|
|
14812
14820
|
function escapeHtml(s2) {
|
|
14813
14821
|
return s2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
14814
14822
|
}
|
|
14823
|
+
function stripLeftoverStarsFromHtml(html) {
|
|
14824
|
+
return html.split(/(<code>[\s\S]*?<\/code>)/g).map((part, i2) => i2 % 2 === 1 ? part : part.replace(/\*\*/g, "")).join("");
|
|
14825
|
+
}
|
|
14815
14826
|
function inlineToHtml(text) {
|
|
14816
14827
|
const html = g.parseInline(text ?? "");
|
|
14817
|
-
return (typeof html === "string" ? html : "").replace(/<br\s*\/?>/gi, "<br/>");
|
|
14828
|
+
return stripLeftoverStarsFromHtml(typeof html === "string" ? html : "").replace(/<br\s*\/?>/gi, "<br/>");
|
|
14818
14829
|
}
|
|
14819
14830
|
function listItemToHtml(item) {
|
|
14820
14831
|
const subs = Array.isArray(item?.tokens) ? item.tokens : [];
|
|
@@ -31961,6 +31972,7 @@ init_jira_client();
|
|
|
31961
31972
|
|
|
31962
31973
|
// src/confluence-client.ts
|
|
31963
31974
|
init_src();
|
|
31975
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
31964
31976
|
var ConfluenceClient = class {
|
|
31965
31977
|
baseUrl;
|
|
31966
31978
|
auth;
|
|
@@ -31981,22 +31993,44 @@ var ConfluenceClient = class {
|
|
|
31981
31993
|
getBaseUrl() {
|
|
31982
31994
|
return this.baseUrl;
|
|
31983
31995
|
}
|
|
31996
|
+
/**
|
|
31997
|
+
* 공통 fetch 래퍼 — timeout(AbortController) + 인증 헤더 + 에러 정규화.
|
|
31998
|
+
* label은 에러 메시지 식별용(get/create/update/...). 빈 응답은 null 반환.
|
|
31999
|
+
* timeout 초과 시 throw(`Confluence <label> timed out after Ns`).
|
|
32000
|
+
*/
|
|
32001
|
+
async request(url, init) {
|
|
32002
|
+
const controller = new AbortController();
|
|
32003
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
32004
|
+
try {
|
|
32005
|
+
const resp = await fetch(url, {
|
|
32006
|
+
method: init.method || "GET",
|
|
32007
|
+
headers: { ...this.headers(), Authorization: this.authHeader() },
|
|
32008
|
+
body: init.body,
|
|
32009
|
+
signal: controller.signal
|
|
32010
|
+
});
|
|
32011
|
+
if (!resp.ok) {
|
|
32012
|
+
throw new Error(`Confluence ${init.label} ${resp.status}: ${await resp.text()}`);
|
|
32013
|
+
}
|
|
32014
|
+
const text = await resp.text();
|
|
32015
|
+
return text ? JSON.parse(text) : null;
|
|
32016
|
+
} catch (err) {
|
|
32017
|
+
if (err?.name === "AbortError") {
|
|
32018
|
+
throw new Error(`Confluence ${init.label} timed out after ${REQUEST_TIMEOUT_MS / 1e3}s`);
|
|
32019
|
+
}
|
|
32020
|
+
throw err;
|
|
32021
|
+
} finally {
|
|
32022
|
+
clearTimeout(timer);
|
|
32023
|
+
}
|
|
32024
|
+
}
|
|
31984
32025
|
async getPage(pageId, expand) {
|
|
31985
32026
|
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();
|
|
32027
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}${params}`, { label: "get" });
|
|
31992
32028
|
}
|
|
31993
32029
|
async search(cql, limit = 25) {
|
|
31994
|
-
|
|
32030
|
+
return this.request(
|
|
31995
32031
|
`${this.baseUrl}/wiki/rest/api/content/search?cql=${encodeURIComponent(cql)}&limit=${limit}`,
|
|
31996
|
-
{
|
|
32032
|
+
{ label: "search" }
|
|
31997
32033
|
);
|
|
31998
|
-
if (!resp.ok) throw new Error(`Confluence search ${resp.status}: ${await resp.text()}`);
|
|
31999
|
-
return resp.json();
|
|
32000
32034
|
}
|
|
32001
32035
|
async createPage(spaceKey, title, body, parentId) {
|
|
32002
32036
|
const payload = {
|
|
@@ -32013,65 +32047,44 @@ var ConfluenceClient = class {
|
|
|
32013
32047
|
if (parentId) {
|
|
32014
32048
|
payload.ancestors = [{ id: parentId }];
|
|
32015
32049
|
}
|
|
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();
|
|
32050
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content`, {
|
|
32051
|
+
method: "POST",
|
|
32052
|
+
label: "create",
|
|
32053
|
+
body: JSON.stringify(payload)
|
|
32054
|
+
});
|
|
32026
32055
|
}
|
|
32027
32056
|
async updatePage(pageId, title, body, version2) {
|
|
32028
|
-
|
|
32029
|
-
|
|
32030
|
-
|
|
32031
|
-
|
|
32032
|
-
|
|
32033
|
-
|
|
32034
|
-
|
|
32035
|
-
|
|
32036
|
-
|
|
32037
|
-
|
|
32038
|
-
|
|
32039
|
-
value: body,
|
|
32040
|
-
representation: "storage"
|
|
32041
|
-
}
|
|
32057
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}`, {
|
|
32058
|
+
method: "PUT",
|
|
32059
|
+
label: "update",
|
|
32060
|
+
body: JSON.stringify({
|
|
32061
|
+
type: "page",
|
|
32062
|
+
title,
|
|
32063
|
+
version: { number: version2 + 1 },
|
|
32064
|
+
body: {
|
|
32065
|
+
storage: {
|
|
32066
|
+
value: body,
|
|
32067
|
+
representation: "storage"
|
|
32042
32068
|
}
|
|
32043
|
-
}
|
|
32044
|
-
}
|
|
32045
|
-
);
|
|
32046
|
-
if (!resp.ok) throw new Error(`Confluence update ${resp.status}: ${await resp.text()}`);
|
|
32047
|
-
return resp.json();
|
|
32069
|
+
}
|
|
32070
|
+
})
|
|
32071
|
+
});
|
|
32048
32072
|
}
|
|
32049
32073
|
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()}`);
|
|
32074
|
+
await this.request(`${this.baseUrl}/wiki/rest/api/content/${pageId}`, {
|
|
32075
|
+
method: "DELETE",
|
|
32076
|
+
label: "delete"
|
|
32077
|
+
});
|
|
32058
32078
|
return { success: true };
|
|
32059
32079
|
}
|
|
32060
32080
|
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();
|
|
32081
|
+
return this.request(`${this.baseUrl}/wiki/rest/api/space?limit=100`, { label: "spaces" });
|
|
32067
32082
|
}
|
|
32068
32083
|
async getPageChildren(pageId, limit = 25) {
|
|
32069
|
-
|
|
32084
|
+
return this.request(
|
|
32070
32085
|
`${this.baseUrl}/wiki/rest/api/content/${pageId}/child/page?limit=${limit}`,
|
|
32071
|
-
{
|
|
32086
|
+
{ label: "children" }
|
|
32072
32087
|
);
|
|
32073
|
-
if (!resp.ok) throw new Error(`Confluence children ${resp.status}: ${await resp.text()}`);
|
|
32074
|
-
return resp.json();
|
|
32075
32088
|
}
|
|
32076
32089
|
};
|
|
32077
32090
|
|
|
@@ -32389,6 +32402,7 @@ var registerJiraCrudTools = (ctx2) => {
|
|
|
32389
32402
|
|
|
32390
32403
|
// src/tools/confluence.ts
|
|
32391
32404
|
init_markdown();
|
|
32405
|
+
var STORAGE_BODY_WARN_BYTES = 2 * 1024 * 1024;
|
|
32392
32406
|
var registerConfluenceTools = (ctx2) => {
|
|
32393
32407
|
const { server: server2, confluence: confluence2 } = ctx2;
|
|
32394
32408
|
server2.tool("confluence_get_page", "Get a Confluence page by ID", {
|
|
@@ -32448,6 +32462,9 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
32448
32462
|
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
32463
|
}, async ({ space_key, title, markdown, parent_page_id, page_id }) => {
|
|
32450
32464
|
const body = markdownToStorageFormat(markdown);
|
|
32465
|
+
const bodyBytes = Buffer.byteLength(body, "utf8");
|
|
32466
|
+
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;
|
|
32467
|
+
if (warning) console.error(`[confluence_publish_doc] ${warning}`);
|
|
32451
32468
|
let result;
|
|
32452
32469
|
let mode;
|
|
32453
32470
|
if (page_id) {
|
|
@@ -32472,7 +32489,9 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
32472
32489
|
space_key,
|
|
32473
32490
|
version: result?.version?.number,
|
|
32474
32491
|
url,
|
|
32475
|
-
body_chars: body.length
|
|
32492
|
+
body_chars: body.length,
|
|
32493
|
+
body_bytes: bodyBytes,
|
|
32494
|
+
...warning ? { warning } : {}
|
|
32476
32495
|
}, null, 2)
|
|
32477
32496
|
}]
|
|
32478
32497
|
};
|
|
@@ -33994,7 +34013,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
|
|
|
33994
34013
|
var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
|
|
33995
34014
|
var server = new McpServer({
|
|
33996
34015
|
name: "jira-confluence",
|
|
33997
|
-
version: "0.1.
|
|
34016
|
+
version: "0.1.12"
|
|
33998
34017
|
});
|
|
33999
34018
|
var ctx = { server, jira, confluence, risk, xray };
|
|
34000
34019
|
registerJiraCrudTools(ctx);
|