@neobiotechlabs/neobiotech-dev-agent 0.1.27 → 0.1.29
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/README.md +31 -1
- package/dist/build/plantuml-1.2026.1.jar +0 -0
- package/dist/index.js +609 -246
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -2995,7 +2995,7 @@ var require_compile = __commonJS({
|
|
|
2995
2995
|
const schOrFunc = root.refs[ref];
|
|
2996
2996
|
if (schOrFunc)
|
|
2997
2997
|
return schOrFunc;
|
|
2998
|
-
let _sch =
|
|
2998
|
+
let _sch = resolve2.call(this, root, ref);
|
|
2999
2999
|
if (_sch === void 0) {
|
|
3000
3000
|
const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
3001
3001
|
const { schemaId } = this.opts;
|
|
@@ -3022,7 +3022,7 @@ var require_compile = __commonJS({
|
|
|
3022
3022
|
function sameSchemaEnv(s1, s2) {
|
|
3023
3023
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3024
3024
|
}
|
|
3025
|
-
function
|
|
3025
|
+
function resolve2(root, ref) {
|
|
3026
3026
|
let sch;
|
|
3027
3027
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3028
3028
|
ref = sch;
|
|
@@ -3653,7 +3653,7 @@ var require_fast_uri = __commonJS({
|
|
|
3653
3653
|
}
|
|
3654
3654
|
return uri;
|
|
3655
3655
|
}
|
|
3656
|
-
function
|
|
3656
|
+
function resolve2(baseURI, relativeURI, options) {
|
|
3657
3657
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3658
3658
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3659
3659
|
schemelessOptions.skipEscape = true;
|
|
@@ -3917,7 +3917,7 @@ var require_fast_uri = __commonJS({
|
|
|
3917
3917
|
var fastUri = {
|
|
3918
3918
|
SCHEMES,
|
|
3919
3919
|
normalize,
|
|
3920
|
-
resolve,
|
|
3920
|
+
resolve: resolve2,
|
|
3921
3921
|
resolveComponent,
|
|
3922
3922
|
equal,
|
|
3923
3923
|
serialize,
|
|
@@ -6982,7 +6982,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
6982
6982
|
return new originalPromise(executor);
|
|
6983
6983
|
}
|
|
6984
6984
|
function promiseResolvedWith(value) {
|
|
6985
|
-
return newPromise((
|
|
6985
|
+
return newPromise((resolve2) => resolve2(value));
|
|
6986
6986
|
}
|
|
6987
6987
|
function promiseRejectedWith(reason) {
|
|
6988
6988
|
return originalPromiseReject(reason);
|
|
@@ -7152,8 +7152,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
7152
7152
|
return new TypeError("Cannot " + name + " a stream using a released reader");
|
|
7153
7153
|
}
|
|
7154
7154
|
function defaultReaderClosedPromiseInitialize(reader) {
|
|
7155
|
-
reader._closedPromise = newPromise((
|
|
7156
|
-
reader._closedPromise_resolve =
|
|
7155
|
+
reader._closedPromise = newPromise((resolve2, reject) => {
|
|
7156
|
+
reader._closedPromise_resolve = resolve2;
|
|
7157
7157
|
reader._closedPromise_reject = reject;
|
|
7158
7158
|
});
|
|
7159
7159
|
}
|
|
@@ -7327,8 +7327,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
7327
7327
|
}
|
|
7328
7328
|
let resolvePromise;
|
|
7329
7329
|
let rejectPromise;
|
|
7330
|
-
const promise = newPromise((
|
|
7331
|
-
resolvePromise =
|
|
7330
|
+
const promise = newPromise((resolve2, reject) => {
|
|
7331
|
+
resolvePromise = resolve2;
|
|
7332
7332
|
rejectPromise = reject;
|
|
7333
7333
|
});
|
|
7334
7334
|
const readRequest = {
|
|
@@ -7433,8 +7433,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
7433
7433
|
const reader = this._reader;
|
|
7434
7434
|
let resolvePromise;
|
|
7435
7435
|
let rejectPromise;
|
|
7436
|
-
const promise = newPromise((
|
|
7437
|
-
resolvePromise =
|
|
7436
|
+
const promise = newPromise((resolve2, reject) => {
|
|
7437
|
+
resolvePromise = resolve2;
|
|
7438
7438
|
rejectPromise = reject;
|
|
7439
7439
|
});
|
|
7440
7440
|
const readRequest = {
|
|
@@ -8453,8 +8453,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
8453
8453
|
}
|
|
8454
8454
|
let resolvePromise;
|
|
8455
8455
|
let rejectPromise;
|
|
8456
|
-
const promise = newPromise((
|
|
8457
|
-
resolvePromise =
|
|
8456
|
+
const promise = newPromise((resolve2, reject) => {
|
|
8457
|
+
resolvePromise = resolve2;
|
|
8458
8458
|
rejectPromise = reject;
|
|
8459
8459
|
});
|
|
8460
8460
|
const readIntoRequest = {
|
|
@@ -8766,10 +8766,10 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
8766
8766
|
wasAlreadyErroring = true;
|
|
8767
8767
|
reason = void 0;
|
|
8768
8768
|
}
|
|
8769
|
-
const promise = newPromise((
|
|
8769
|
+
const promise = newPromise((resolve2, reject) => {
|
|
8770
8770
|
stream2._pendingAbortRequest = {
|
|
8771
8771
|
_promise: void 0,
|
|
8772
|
-
_resolve:
|
|
8772
|
+
_resolve: resolve2,
|
|
8773
8773
|
_reject: reject,
|
|
8774
8774
|
_reason: reason,
|
|
8775
8775
|
_wasAlreadyErroring: wasAlreadyErroring
|
|
@@ -8786,9 +8786,9 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
8786
8786
|
if (state === "closed" || state === "errored") {
|
|
8787
8787
|
return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`));
|
|
8788
8788
|
}
|
|
8789
|
-
const promise = newPromise((
|
|
8789
|
+
const promise = newPromise((resolve2, reject) => {
|
|
8790
8790
|
const closeRequest = {
|
|
8791
|
-
_resolve:
|
|
8791
|
+
_resolve: resolve2,
|
|
8792
8792
|
_reject: reject
|
|
8793
8793
|
};
|
|
8794
8794
|
stream2._closeRequest = closeRequest;
|
|
@@ -8801,9 +8801,9 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
8801
8801
|
return promise;
|
|
8802
8802
|
}
|
|
8803
8803
|
function WritableStreamAddWriteRequest(stream2) {
|
|
8804
|
-
const promise = newPromise((
|
|
8804
|
+
const promise = newPromise((resolve2, reject) => {
|
|
8805
8805
|
const writeRequest = {
|
|
8806
|
-
_resolve:
|
|
8806
|
+
_resolve: resolve2,
|
|
8807
8807
|
_reject: reject
|
|
8808
8808
|
};
|
|
8809
8809
|
stream2._writeRequests.push(writeRequest);
|
|
@@ -9419,8 +9419,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
9419
9419
|
return new TypeError("Cannot " + name + " a stream using a released writer");
|
|
9420
9420
|
}
|
|
9421
9421
|
function defaultWriterClosedPromiseInitialize(writer) {
|
|
9422
|
-
writer._closedPromise = newPromise((
|
|
9423
|
-
writer._closedPromise_resolve =
|
|
9422
|
+
writer._closedPromise = newPromise((resolve2, reject) => {
|
|
9423
|
+
writer._closedPromise_resolve = resolve2;
|
|
9424
9424
|
writer._closedPromise_reject = reject;
|
|
9425
9425
|
writer._closedPromiseState = "pending";
|
|
9426
9426
|
});
|
|
@@ -9456,8 +9456,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
9456
9456
|
writer._closedPromiseState = "resolved";
|
|
9457
9457
|
}
|
|
9458
9458
|
function defaultWriterReadyPromiseInitialize(writer) {
|
|
9459
|
-
writer._readyPromise = newPromise((
|
|
9460
|
-
writer._readyPromise_resolve =
|
|
9459
|
+
writer._readyPromise = newPromise((resolve2, reject) => {
|
|
9460
|
+
writer._readyPromise_resolve = resolve2;
|
|
9461
9461
|
writer._readyPromise_reject = reject;
|
|
9462
9462
|
});
|
|
9463
9463
|
writer._readyPromiseState = "pending";
|
|
@@ -9544,7 +9544,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
9544
9544
|
source._disturbed = true;
|
|
9545
9545
|
let shuttingDown = false;
|
|
9546
9546
|
let currentWrite = promiseResolvedWith(void 0);
|
|
9547
|
-
return newPromise((
|
|
9547
|
+
return newPromise((resolve2, reject) => {
|
|
9548
9548
|
let abortAlgorithm;
|
|
9549
9549
|
if (signal !== void 0) {
|
|
9550
9550
|
abortAlgorithm = () => {
|
|
@@ -9689,7 +9689,7 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
9689
9689
|
if (isError) {
|
|
9690
9690
|
reject(error2);
|
|
9691
9691
|
} else {
|
|
9692
|
-
|
|
9692
|
+
resolve2(void 0);
|
|
9693
9693
|
}
|
|
9694
9694
|
return null;
|
|
9695
9695
|
}
|
|
@@ -9970,8 +9970,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
9970
9970
|
let branch1;
|
|
9971
9971
|
let branch2;
|
|
9972
9972
|
let resolveCancelPromise;
|
|
9973
|
-
const cancelPromise = newPromise((
|
|
9974
|
-
resolveCancelPromise =
|
|
9973
|
+
const cancelPromise = newPromise((resolve2) => {
|
|
9974
|
+
resolveCancelPromise = resolve2;
|
|
9975
9975
|
});
|
|
9976
9976
|
function pullAlgorithm() {
|
|
9977
9977
|
if (reading) {
|
|
@@ -10062,8 +10062,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
10062
10062
|
let branch1;
|
|
10063
10063
|
let branch2;
|
|
10064
10064
|
let resolveCancelPromise;
|
|
10065
|
-
const cancelPromise = newPromise((
|
|
10066
|
-
resolveCancelPromise =
|
|
10065
|
+
const cancelPromise = newPromise((resolve2) => {
|
|
10066
|
+
resolveCancelPromise = resolve2;
|
|
10067
10067
|
});
|
|
10068
10068
|
function forwardReaderError(thisReader) {
|
|
10069
10069
|
uponRejection(thisReader._closedPromise, (r2) => {
|
|
@@ -10843,8 +10843,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
10843
10843
|
const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1);
|
|
10844
10844
|
const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy);
|
|
10845
10845
|
let startPromise_resolve;
|
|
10846
|
-
const startPromise = newPromise((
|
|
10847
|
-
startPromise_resolve =
|
|
10846
|
+
const startPromise = newPromise((resolve2) => {
|
|
10847
|
+
startPromise_resolve = resolve2;
|
|
10848
10848
|
});
|
|
10849
10849
|
InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm);
|
|
10850
10850
|
SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
|
|
@@ -10937,8 +10937,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
10937
10937
|
if (stream2._backpressureChangePromise !== void 0) {
|
|
10938
10938
|
stream2._backpressureChangePromise_resolve();
|
|
10939
10939
|
}
|
|
10940
|
-
stream2._backpressureChangePromise = newPromise((
|
|
10941
|
-
stream2._backpressureChangePromise_resolve =
|
|
10940
|
+
stream2._backpressureChangePromise = newPromise((resolve2) => {
|
|
10941
|
+
stream2._backpressureChangePromise_resolve = resolve2;
|
|
10942
10942
|
});
|
|
10943
10943
|
stream2._backpressure = backpressure;
|
|
10944
10944
|
}
|
|
@@ -11106,8 +11106,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
11106
11106
|
return controller._finishPromise;
|
|
11107
11107
|
}
|
|
11108
11108
|
const readable = stream2._readable;
|
|
11109
|
-
controller._finishPromise = newPromise((
|
|
11110
|
-
controller._finishPromise_resolve =
|
|
11109
|
+
controller._finishPromise = newPromise((resolve2, reject) => {
|
|
11110
|
+
controller._finishPromise_resolve = resolve2;
|
|
11111
11111
|
controller._finishPromise_reject = reject;
|
|
11112
11112
|
});
|
|
11113
11113
|
const cancelPromise = controller._cancelAlgorithm(reason);
|
|
@@ -11133,8 +11133,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
11133
11133
|
return controller._finishPromise;
|
|
11134
11134
|
}
|
|
11135
11135
|
const readable = stream2._readable;
|
|
11136
|
-
controller._finishPromise = newPromise((
|
|
11137
|
-
controller._finishPromise_resolve =
|
|
11136
|
+
controller._finishPromise = newPromise((resolve2, reject) => {
|
|
11137
|
+
controller._finishPromise_resolve = resolve2;
|
|
11138
11138
|
controller._finishPromise_reject = reject;
|
|
11139
11139
|
});
|
|
11140
11140
|
const flushPromise = controller._flushAlgorithm();
|
|
@@ -11164,8 +11164,8 @@ var require_ponyfill_es2018 = __commonJS({
|
|
|
11164
11164
|
return controller._finishPromise;
|
|
11165
11165
|
}
|
|
11166
11166
|
const writable = stream2._writable;
|
|
11167
|
-
controller._finishPromise = newPromise((
|
|
11168
|
-
controller._finishPromise_resolve =
|
|
11167
|
+
controller._finishPromise = newPromise((resolve2, reject) => {
|
|
11168
|
+
controller._finishPromise_resolve = resolve2;
|
|
11169
11169
|
controller._finishPromise_reject = reject;
|
|
11170
11170
|
});
|
|
11171
11171
|
const cancelPromise = controller._cancelAlgorithm(reason);
|
|
@@ -13066,7 +13066,7 @@ import zlib from "zlib";
|
|
|
13066
13066
|
import Stream2, { PassThrough as PassThrough2, pipeline as pump } from "stream";
|
|
13067
13067
|
import { Buffer as Buffer3 } from "buffer";
|
|
13068
13068
|
async function fetch(url, options_) {
|
|
13069
|
-
return new Promise((
|
|
13069
|
+
return new Promise((resolve2, reject) => {
|
|
13070
13070
|
const request = new Request(url, options_);
|
|
13071
13071
|
const { parsedURL, options } = getNodeRequestOptions(request);
|
|
13072
13072
|
if (!supportedSchemas.has(parsedURL.protocol)) {
|
|
@@ -13075,7 +13075,7 @@ async function fetch(url, options_) {
|
|
|
13075
13075
|
if (parsedURL.protocol === "data:") {
|
|
13076
13076
|
const data = dist_default(request.url);
|
|
13077
13077
|
const response2 = new Response(data, { headers: { "Content-Type": data.typeFull } });
|
|
13078
|
-
|
|
13078
|
+
resolve2(response2);
|
|
13079
13079
|
return;
|
|
13080
13080
|
}
|
|
13081
13081
|
const send = (parsedURL.protocol === "https:" ? https : http2).request;
|
|
@@ -13197,7 +13197,7 @@ async function fetch(url, options_) {
|
|
|
13197
13197
|
if (responseReferrerPolicy) {
|
|
13198
13198
|
requestOptions.referrerPolicy = responseReferrerPolicy;
|
|
13199
13199
|
}
|
|
13200
|
-
|
|
13200
|
+
resolve2(fetch(new Request(locationURL, requestOptions)));
|
|
13201
13201
|
finalize();
|
|
13202
13202
|
return;
|
|
13203
13203
|
}
|
|
@@ -13230,7 +13230,7 @@ async function fetch(url, options_) {
|
|
|
13230
13230
|
const codings = headers.get("Content-Encoding");
|
|
13231
13231
|
if (!request.compress || request.method === "HEAD" || codings === null || response_.statusCode === 204 || response_.statusCode === 304) {
|
|
13232
13232
|
response = new Response(body, responseOptions);
|
|
13233
|
-
|
|
13233
|
+
resolve2(response);
|
|
13234
13234
|
return;
|
|
13235
13235
|
}
|
|
13236
13236
|
const zlibOptions = {
|
|
@@ -13244,7 +13244,7 @@ async function fetch(url, options_) {
|
|
|
13244
13244
|
}
|
|
13245
13245
|
});
|
|
13246
13246
|
response = new Response(body, responseOptions);
|
|
13247
|
-
|
|
13247
|
+
resolve2(response);
|
|
13248
13248
|
return;
|
|
13249
13249
|
}
|
|
13250
13250
|
if (codings === "deflate" || codings === "x-deflate") {
|
|
@@ -13268,12 +13268,12 @@ async function fetch(url, options_) {
|
|
|
13268
13268
|
});
|
|
13269
13269
|
}
|
|
13270
13270
|
response = new Response(body, responseOptions);
|
|
13271
|
-
|
|
13271
|
+
resolve2(response);
|
|
13272
13272
|
});
|
|
13273
13273
|
raw.once("end", () => {
|
|
13274
13274
|
if (!response) {
|
|
13275
13275
|
response = new Response(body, responseOptions);
|
|
13276
|
-
|
|
13276
|
+
resolve2(response);
|
|
13277
13277
|
}
|
|
13278
13278
|
});
|
|
13279
13279
|
return;
|
|
@@ -13285,11 +13285,11 @@ async function fetch(url, options_) {
|
|
|
13285
13285
|
}
|
|
13286
13286
|
});
|
|
13287
13287
|
response = new Response(body, responseOptions);
|
|
13288
|
-
|
|
13288
|
+
resolve2(response);
|
|
13289
13289
|
return;
|
|
13290
13290
|
}
|
|
13291
13291
|
response = new Response(body, responseOptions);
|
|
13292
|
-
|
|
13292
|
+
resolve2(response);
|
|
13293
13293
|
});
|
|
13294
13294
|
writeToStream(request_, request).catch(reject);
|
|
13295
13295
|
});
|
|
@@ -14845,7 +14845,7 @@ function listItemToHtml(item) {
|
|
|
14845
14845
|
if (paras.length) return paras.map((p) => inlineToHtml(p.text)).join("<br/>");
|
|
14846
14846
|
return inlineToHtml(item?.text);
|
|
14847
14847
|
}
|
|
14848
|
-
function tokenToStorageHtml(tok) {
|
|
14848
|
+
function tokenToStorageHtml(tok, nextPumlId, pumlRegistry) {
|
|
14849
14849
|
if (!tok || typeof tok !== "object") return "";
|
|
14850
14850
|
switch (tok.type) {
|
|
14851
14851
|
case "heading":
|
|
@@ -14853,6 +14853,12 @@ function tokenToStorageHtml(tok) {
|
|
|
14853
14853
|
case "paragraph":
|
|
14854
14854
|
return `<p>${inlineToHtml(tok.text)}</p>`;
|
|
14855
14855
|
case "code": {
|
|
14856
|
+
const lang = String(tok.lang ?? "").trim().toLowerCase();
|
|
14857
|
+
if (lang === "plantuml" || lang === "puml" || lang === "plantuml-markdown") {
|
|
14858
|
+
const id = nextPumlId();
|
|
14859
|
+
pumlRegistry.set(id, String(tok.text ?? ""));
|
|
14860
|
+
return `<p data-puml-id="${id}"></p>`;
|
|
14861
|
+
}
|
|
14856
14862
|
const langParam = tok.lang ? `<ac:parameter ac:name="language">${escapeHtml(String(tok.lang))}</ac:parameter>` : "";
|
|
14857
14863
|
return `<ac:structured-macro ac:name="code">${langParam}<ac:plain-text-body><![CDATA[${tok.text ?? ""}]]></ac:plain-text-body></ac:structured-macro>`;
|
|
14858
14864
|
}
|
|
@@ -14862,7 +14868,7 @@ function tokenToStorageHtml(tok) {
|
|
|
14862
14868
|
return `<${tag}>${items}</${tag}>`;
|
|
14863
14869
|
}
|
|
14864
14870
|
case "blockquote":
|
|
14865
|
-
return `<blockquote>${(tok.tokens || []).map((t2) => tokenToStorageHtml(t2)).join("")}</blockquote>`;
|
|
14871
|
+
return `<blockquote>${(tok.tokens || []).map((t2) => tokenToStorageHtml(t2, nextPumlId, pumlRegistry)).join("")}</blockquote>`;
|
|
14866
14872
|
case "table": {
|
|
14867
14873
|
const header = (tok.header || []).map((c) => `<th>${inlineToHtml(c.text)}</th>`).join("");
|
|
14868
14874
|
const rows = (tok.rows || []).map(
|
|
@@ -14878,12 +14884,17 @@ function tokenToStorageHtml(tok) {
|
|
|
14878
14884
|
}
|
|
14879
14885
|
function markdownToStorageFormat(md) {
|
|
14880
14886
|
const tokens = g.lexer(stripFrontmatter(md ?? ""));
|
|
14887
|
+
const pumlRegistry = /* @__PURE__ */ new Map();
|
|
14881
14888
|
const parts = [];
|
|
14889
|
+
let pumlCounter = 0;
|
|
14882
14890
|
for (const tok of tokens) {
|
|
14883
|
-
const html = tokenToStorageHtml(tok);
|
|
14891
|
+
const html = tokenToStorageHtml(tok, () => `PUML_${pumlCounter++}`, pumlRegistry);
|
|
14884
14892
|
if (html) parts.push(html);
|
|
14885
14893
|
}
|
|
14886
|
-
return
|
|
14894
|
+
return {
|
|
14895
|
+
storage: parts.join("\n") || "<p></p>",
|
|
14896
|
+
pumlRegistry
|
|
14897
|
+
};
|
|
14887
14898
|
}
|
|
14888
14899
|
var FRONTMATTER_RE;
|
|
14889
14900
|
var init_markdown = __esm({
|
|
@@ -17106,8 +17117,8 @@ var require_adm_zip = __commonJS({
|
|
|
17106
17117
|
return null;
|
|
17107
17118
|
}
|
|
17108
17119
|
function fixPath(zipPath) {
|
|
17109
|
-
const { join:
|
|
17110
|
-
return
|
|
17120
|
+
const { join: join6, normalize, sep } = pth.posix;
|
|
17121
|
+
return join6(pth.isAbsolute(zipPath) ? "/" : ".", normalize(sep + zipPath.split("\\").join(sep) + sep));
|
|
17111
17122
|
}
|
|
17112
17123
|
function filenameFilter(filterfn) {
|
|
17113
17124
|
if (filterfn instanceof RegExp) {
|
|
@@ -17503,10 +17514,10 @@ var require_adm_zip = __commonJS({
|
|
|
17503
17514
|
* @param {function|string} [props.namefix] - optional function to help fix filename
|
|
17504
17515
|
*/
|
|
17505
17516
|
addLocalFolderPromise: function(localPath, props) {
|
|
17506
|
-
return new Promise((
|
|
17517
|
+
return new Promise((resolve2, reject) => {
|
|
17507
17518
|
this.addLocalFolderAsync2(Object.assign({ localPath }, props), (err, done) => {
|
|
17508
17519
|
if (err) reject(err);
|
|
17509
|
-
if (done)
|
|
17520
|
+
if (done) resolve2(this);
|
|
17510
17521
|
});
|
|
17511
17522
|
});
|
|
17512
17523
|
},
|
|
@@ -17693,12 +17704,12 @@ var require_adm_zip = __commonJS({
|
|
|
17693
17704
|
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
17694
17705
|
overwrite = get_Bool(false, overwrite);
|
|
17695
17706
|
if (!callback) {
|
|
17696
|
-
return new Promise((
|
|
17707
|
+
return new Promise((resolve2, reject) => {
|
|
17697
17708
|
this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function(err) {
|
|
17698
17709
|
if (err) {
|
|
17699
17710
|
reject(err);
|
|
17700
17711
|
} else {
|
|
17701
|
-
|
|
17712
|
+
resolve2(this);
|
|
17702
17713
|
}
|
|
17703
17714
|
});
|
|
17704
17715
|
});
|
|
@@ -17796,11 +17807,11 @@ var require_adm_zip = __commonJS({
|
|
|
17796
17807
|
*/
|
|
17797
17808
|
writeZipPromise: function(targetFileName, props) {
|
|
17798
17809
|
const { overwrite, perm } = Object.assign({ overwrite: true }, props);
|
|
17799
|
-
return new Promise((
|
|
17810
|
+
return new Promise((resolve2, reject) => {
|
|
17800
17811
|
if (!targetFileName && opts.filename) targetFileName = opts.filename;
|
|
17801
17812
|
if (!targetFileName) reject("ADM-ZIP: ZIP File Name Missing");
|
|
17802
17813
|
this.toBufferPromise().then((zipData) => {
|
|
17803
|
-
const ret = (done) => done ?
|
|
17814
|
+
const ret = (done) => done ? resolve2(done) : reject("ADM-ZIP: Wasn't able to write zip file");
|
|
17804
17815
|
filetools.writeFileToAsync(targetFileName, zipData, overwrite, perm, ret);
|
|
17805
17816
|
}, reject);
|
|
17806
17817
|
});
|
|
@@ -17809,8 +17820,8 @@ var require_adm_zip = __commonJS({
|
|
|
17809
17820
|
* @returns {Promise<Buffer>} A promise to the Buffer.
|
|
17810
17821
|
*/
|
|
17811
17822
|
toBufferPromise: function() {
|
|
17812
|
-
return new Promise((
|
|
17813
|
-
_zip.toAsyncBuffer(
|
|
17823
|
+
return new Promise((resolve2, reject) => {
|
|
17824
|
+
_zip.toAsyncBuffer(resolve2, reject);
|
|
17814
17825
|
});
|
|
17815
17826
|
},
|
|
17816
17827
|
/**
|
|
@@ -18949,9 +18960,9 @@ var require_clone = __commonJS({
|
|
|
18949
18960
|
} else if (_instanceof(parent2, nativeSet)) {
|
|
18950
18961
|
child = new nativeSet();
|
|
18951
18962
|
} else if (_instanceof(parent2, nativePromise)) {
|
|
18952
|
-
child = new nativePromise(function(
|
|
18963
|
+
child = new nativePromise(function(resolve2, reject) {
|
|
18953
18964
|
parent2.then(function(value) {
|
|
18954
|
-
|
|
18965
|
+
resolve2(_clone(value, depth2 - 1));
|
|
18955
18966
|
}, function(err) {
|
|
18956
18967
|
reject(_clone(err, depth2 - 1));
|
|
18957
18968
|
});
|
|
@@ -157405,7 +157416,7 @@ var Protocol = class {
|
|
|
157405
157416
|
return;
|
|
157406
157417
|
}
|
|
157407
157418
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
157408
|
-
await new Promise((
|
|
157419
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
|
|
157409
157420
|
options?.signal?.throwIfAborted();
|
|
157410
157421
|
}
|
|
157411
157422
|
} catch (error2) {
|
|
@@ -157422,7 +157433,7 @@ var Protocol = class {
|
|
|
157422
157433
|
*/
|
|
157423
157434
|
request(request, resultSchema, options) {
|
|
157424
157435
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
157425
|
-
return new Promise((
|
|
157436
|
+
return new Promise((resolve2, reject) => {
|
|
157426
157437
|
const earlyReject = (error2) => {
|
|
157427
157438
|
reject(error2);
|
|
157428
157439
|
};
|
|
@@ -157500,7 +157511,7 @@ var Protocol = class {
|
|
|
157500
157511
|
if (!parseResult.success) {
|
|
157501
157512
|
reject(parseResult.error);
|
|
157502
157513
|
} else {
|
|
157503
|
-
|
|
157514
|
+
resolve2(parseResult.data);
|
|
157504
157515
|
}
|
|
157505
157516
|
} catch (error2) {
|
|
157506
157517
|
reject(error2);
|
|
@@ -157761,12 +157772,12 @@ var Protocol = class {
|
|
|
157761
157772
|
}
|
|
157762
157773
|
} catch {
|
|
157763
157774
|
}
|
|
157764
|
-
return new Promise((
|
|
157775
|
+
return new Promise((resolve2, reject) => {
|
|
157765
157776
|
if (signal.aborted) {
|
|
157766
157777
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
157767
157778
|
return;
|
|
157768
157779
|
}
|
|
157769
|
-
const timeoutId = setTimeout(
|
|
157780
|
+
const timeoutId = setTimeout(resolve2, interval);
|
|
157770
157781
|
signal.addEventListener("abort", () => {
|
|
157771
157782
|
clearTimeout(timeoutId);
|
|
157772
157783
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -158857,7 +158868,7 @@ var McpServer = class {
|
|
|
158857
158868
|
let task = createTaskResult.task;
|
|
158858
158869
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
158859
158870
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
158860
|
-
await new Promise((
|
|
158871
|
+
await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
|
|
158861
158872
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
158862
158873
|
if (!updatedTask) {
|
|
158863
158874
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -159521,12 +159532,12 @@ var StdioServerTransport = class {
|
|
|
159521
159532
|
this.onclose?.();
|
|
159522
159533
|
}
|
|
159523
159534
|
send(message) {
|
|
159524
|
-
return new Promise((
|
|
159535
|
+
return new Promise((resolve2) => {
|
|
159525
159536
|
const json = serializeMessage(message);
|
|
159526
159537
|
if (this._stdout.write(json)) {
|
|
159527
|
-
|
|
159538
|
+
resolve2();
|
|
159528
159539
|
} else {
|
|
159529
|
-
this._stdout.once("drain",
|
|
159540
|
+
this._stdout.once("drain", resolve2);
|
|
159530
159541
|
}
|
|
159531
159542
|
});
|
|
159532
159543
|
}
|
|
@@ -159651,7 +159662,83 @@ var ConfluenceClient = class {
|
|
|
159651
159662
|
{ label: "children" }
|
|
159652
159663
|
);
|
|
159653
159664
|
}
|
|
159665
|
+
/**
|
|
159666
|
+
* 페이지 첨부 업로드 (POST .../content/{pageId}/child/attachment).
|
|
159667
|
+
*
|
|
159668
|
+
* JSON 본문 기반 `request()`와 달리 multipart/form-data 자체 구성을 직접 한다.
|
|
159669
|
+
* - 헤더 `X-Atlassian-Token: no-check`는 첨부 시 **필수** (누락 시 403/404 — CSRF 차단).
|
|
159670
|
+
* - 자체 AbortController 60s timeout (attach만 — request() 미변경).
|
|
159671
|
+
* - Content-Type은 boundary 포함해서 직접 설정. node-fetch가 boundary 자동 계산 안 함.
|
|
159672
|
+
* - 응답은 `{ results: [{ id, title, extensions: { fileSize, mediaType }, _links: { content } }] }`
|
|
159673
|
+
* (Jira와 달리 `results` 래퍼 한 겹). 정규화하여 단일 객체로 반환.
|
|
159674
|
+
*
|
|
159675
|
+
* 가드(50MB warning / 100MB hard)는 호출 툴 핸들러에서 처리 — 본 메서드는 순수 클라이언트.
|
|
159676
|
+
*/
|
|
159677
|
+
async addAttachment(pageId, filename, content, mimeType = "application/octet-stream") {
|
|
159678
|
+
const ATTACH_TIMEOUT_MS = 6e4;
|
|
159679
|
+
const boundary = `----confluence-mcp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
159680
|
+
const safeFilename = escapeMimeFilename2(filename);
|
|
159681
|
+
const fileBuf = Buffer.isBuffer(content) ? content : Buffer.from(content);
|
|
159682
|
+
const head = `--${boundary}\r
|
|
159683
|
+
Content-Disposition: form-data; name="file"; filename="${safeFilename}"\r
|
|
159684
|
+
Content-Type: ${mimeType}\r
|
|
159685
|
+
\r
|
|
159686
|
+
`;
|
|
159687
|
+
const tail = `\r
|
|
159688
|
+
--${boundary}\r
|
|
159689
|
+
Content-Disposition: form-data; name="minorEdit"\r
|
|
159690
|
+
\r
|
|
159691
|
+
true\r
|
|
159692
|
+
--${boundary}--\r
|
|
159693
|
+
`;
|
|
159694
|
+
const headBuf = Buffer.from(head, "utf8");
|
|
159695
|
+
const tailBuf = Buffer.from(tail, "utf8");
|
|
159696
|
+
const body = Buffer.concat([headBuf, fileBuf, tailBuf]);
|
|
159697
|
+
const controller = new AbortController();
|
|
159698
|
+
const timer = setTimeout(() => controller.abort(), ATTACH_TIMEOUT_MS);
|
|
159699
|
+
try {
|
|
159700
|
+
const resp = await fetch(`${this.baseUrl}/wiki/rest/api/content/${encodeURIComponent(pageId)}/child/attachment`, {
|
|
159701
|
+
method: "POST",
|
|
159702
|
+
headers: {
|
|
159703
|
+
"Accept": "application/json",
|
|
159704
|
+
// Content-Type은 body boundary와 정확히 일치해야 함. node-fetch가 자동 설정하지 않음.
|
|
159705
|
+
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
159706
|
+
"Authorization": this.authHeader(),
|
|
159707
|
+
// 첨부 시 필수 헤더. 없으면 Atlassian CSRF 가드가 403/404 응답.
|
|
159708
|
+
"X-Atlassian-Token": "no-check"
|
|
159709
|
+
},
|
|
159710
|
+
body,
|
|
159711
|
+
signal: controller.signal
|
|
159712
|
+
});
|
|
159713
|
+
if (!resp.ok) {
|
|
159714
|
+
const text = await resp.text();
|
|
159715
|
+
throw new Error(`Confluence attachment API ${resp.status}: ${text}`);
|
|
159716
|
+
}
|
|
159717
|
+
const data = await resp.json();
|
|
159718
|
+
const item = Array.isArray(data?.results) ? data.results[0] : data;
|
|
159719
|
+
if (!item?.id) {
|
|
159720
|
+
throw new Error(`Confluence attachment API: missing id in response`);
|
|
159721
|
+
}
|
|
159722
|
+
return {
|
|
159723
|
+
id: String(item.id),
|
|
159724
|
+
title: String(item.title ?? filename),
|
|
159725
|
+
size: Number(item.extensions?.fileSize ?? fileBuf.length),
|
|
159726
|
+
mimeType: String(item.extensions?.mediaType ?? mimeType),
|
|
159727
|
+
content: String(item._links?.content ?? "")
|
|
159728
|
+
};
|
|
159729
|
+
} catch (err) {
|
|
159730
|
+
if (err?.name === "AbortError") {
|
|
159731
|
+
throw new Error(`Confluence attachment timed out after ${ATTACH_TIMEOUT_MS / 1e3}s`);
|
|
159732
|
+
}
|
|
159733
|
+
throw err;
|
|
159734
|
+
} finally {
|
|
159735
|
+
clearTimeout(timer);
|
|
159736
|
+
}
|
|
159737
|
+
}
|
|
159654
159738
|
};
|
|
159739
|
+
function escapeMimeFilename2(name) {
|
|
159740
|
+
return name.replace(/"/g, "%22").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
159741
|
+
}
|
|
159655
159742
|
|
|
159656
159743
|
// src/clients/risk-client.ts
|
|
159657
159744
|
init_src();
|
|
@@ -160007,6 +160094,106 @@ var registerJiraCrudTools = (ctx2) => {
|
|
|
160007
160094
|
// src/tools/confluence.ts
|
|
160008
160095
|
init_markdown();
|
|
160009
160096
|
import { readFileSync } from "fs";
|
|
160097
|
+
|
|
160098
|
+
// src/utils/plantuml-renderer.ts
|
|
160099
|
+
import { spawn } from "child_process";
|
|
160100
|
+
import { createHash } from "crypto";
|
|
160101
|
+
import { readdirSync as readdirSync2, existsSync } from "fs";
|
|
160102
|
+
import { resolve, dirname, join as join2 } from "path";
|
|
160103
|
+
import { fileURLToPath } from "url";
|
|
160104
|
+
var PNG_CT = "image/png";
|
|
160105
|
+
var SVG_CT = "image/svg+xml";
|
|
160106
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
160107
|
+
var DEFAULT_DPI = 96;
|
|
160108
|
+
var DEFAULT_FORMAT = "png";
|
|
160109
|
+
var JAR_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "build");
|
|
160110
|
+
function resolveJar() {
|
|
160111
|
+
if (!existsSync(JAR_DIR)) {
|
|
160112
|
+
throw new Error(
|
|
160113
|
+
`PlantUML jar directory not found at ${JAR_DIR}. Run 'npm run build' to copy the jar.`
|
|
160114
|
+
);
|
|
160115
|
+
}
|
|
160116
|
+
const jars = readdirSync2(JAR_DIR).filter((f3) => f3.endsWith(".jar"));
|
|
160117
|
+
if (jars.length === 0) {
|
|
160118
|
+
throw new Error(`No .jar files in ${JAR_DIR}. Run 'npm run build' to copy the jar.`);
|
|
160119
|
+
}
|
|
160120
|
+
if (jars.length > 1) {
|
|
160121
|
+
throw new Error(`Multiple .jar files in ${JAR_DIR}: ${jars.join(", ")}. Expected exactly one.`);
|
|
160122
|
+
}
|
|
160123
|
+
return join2(JAR_DIR, jars[0]);
|
|
160124
|
+
}
|
|
160125
|
+
var cache = /* @__PURE__ */ new Map();
|
|
160126
|
+
function makeCacheKey(source, format, dpi) {
|
|
160127
|
+
return createHash("sha256").update(`${source}|${format}|${dpi}`).digest("hex");
|
|
160128
|
+
}
|
|
160129
|
+
function isJavaMissing(err) {
|
|
160130
|
+
if (err?.code !== "ENOENT") return false;
|
|
160131
|
+
const haystack = `${err?.syscall ?? ""} ${err?.path ?? ""} ${JSON.stringify(err?.spawnargs ?? [])}`;
|
|
160132
|
+
return /java/i.test(haystack);
|
|
160133
|
+
}
|
|
160134
|
+
function spawnPlantUml(jarPath, source, format, dpi) {
|
|
160135
|
+
return new Promise((resolveP, rejectP) => {
|
|
160136
|
+
const args = ["-jar", jarPath, "-pipe", `-t${format}`, "-charset", "UTF-8"];
|
|
160137
|
+
if (dpi !== DEFAULT_DPI) {
|
|
160138
|
+
args.push(`-Sdpi=${dpi}`);
|
|
160139
|
+
}
|
|
160140
|
+
const proc = spawn("java", args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
160141
|
+
const chunks = [];
|
|
160142
|
+
proc.stdout.on("data", (c) => chunks.push(c));
|
|
160143
|
+
proc.stderr.on("data", () => {
|
|
160144
|
+
});
|
|
160145
|
+
proc.on("error", (err) => rejectP(err));
|
|
160146
|
+
proc.on("close", (code) => {
|
|
160147
|
+
if (code === 0) {
|
|
160148
|
+
resolveP(Buffer.concat(chunks));
|
|
160149
|
+
} else {
|
|
160150
|
+
rejectP(new Error(`PlantUML jar exited with code ${code}`));
|
|
160151
|
+
}
|
|
160152
|
+
});
|
|
160153
|
+
proc.stdin.write(source);
|
|
160154
|
+
proc.stdin.end();
|
|
160155
|
+
});
|
|
160156
|
+
}
|
|
160157
|
+
async function renderPlantUml(source, opts = {}) {
|
|
160158
|
+
const format = opts.format ?? DEFAULT_FORMAT;
|
|
160159
|
+
const dpi = opts.dpi ?? DEFAULT_DPI;
|
|
160160
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
160161
|
+
const cacheKey = makeCacheKey(source, format, dpi);
|
|
160162
|
+
const hit = cache.get(cacheKey);
|
|
160163
|
+
if (hit) return hit;
|
|
160164
|
+
const jarPath = resolveJar();
|
|
160165
|
+
let timer = null;
|
|
160166
|
+
try {
|
|
160167
|
+
const buffer = await Promise.race([
|
|
160168
|
+
spawnPlantUml(jarPath, source, format, dpi),
|
|
160169
|
+
new Promise((_2, reject) => {
|
|
160170
|
+
timer = setTimeout(
|
|
160171
|
+
() => reject(new Error(`PlantUML render timed out after ${timeoutMs}ms`)),
|
|
160172
|
+
timeoutMs
|
|
160173
|
+
);
|
|
160174
|
+
})
|
|
160175
|
+
]);
|
|
160176
|
+
if (timer) clearTimeout(timer);
|
|
160177
|
+
const rendered = {
|
|
160178
|
+
buffer,
|
|
160179
|
+
format,
|
|
160180
|
+
contentType: format === "png" ? PNG_CT : SVG_CT,
|
|
160181
|
+
cacheKey
|
|
160182
|
+
};
|
|
160183
|
+
cache.set(cacheKey, rendered);
|
|
160184
|
+
return rendered;
|
|
160185
|
+
} catch (err) {
|
|
160186
|
+
if (timer) clearTimeout(timer);
|
|
160187
|
+
if (isJavaMissing(err)) {
|
|
160188
|
+
throw new Error(
|
|
160189
|
+
`PlantUML render failed: spawn java ENOENT. Install Java 21+ (https://adoptium.net/) and ensure 'java -version' works on PATH. Original: ${err?.message ?? err}`
|
|
160190
|
+
);
|
|
160191
|
+
}
|
|
160192
|
+
throw new Error(`PlantUML render failed: ${err?.message ?? err}`);
|
|
160193
|
+
}
|
|
160194
|
+
}
|
|
160195
|
+
|
|
160196
|
+
// src/tools/confluence.ts
|
|
160010
160197
|
var STORAGE_BODY_WARN_BYTES = 2 * 1024 * 1024;
|
|
160011
160198
|
var registerConfluenceTools = (ctx2) => {
|
|
160012
160199
|
const { server: server2, confluence: confluence2 } = ctx2;
|
|
@@ -160065,8 +160252,11 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160065
160252
|
markdown: external_exports.string().optional().describe("Document content in markdown (inline). markdown_file\uACFC \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00. Headings (#), bullet/ordered lists, GFM tables, fenced code blocks, and inline marks (**bold**/*italic*/`code`) are supported."),
|
|
160066
160253
|
markdown_file: external_exports.string().optional().describe("\uB85C\uCEEC \uB9C8\uD06C\uB2E4\uC6B4 \uD30C\uC77C \uACBD\uB85C. \uD070 \uBB38\uC11C(25KB+)\uB294 \uBAA8\uB378 \uD234 \uD638\uCD9C \uCD9C\uB825 \uD55C\uACC4\uB85C inline markdown \uC778\uC790\uAC00 \uC798\uB9B4 \uC218 \uC788\uC5B4 \uD30C\uC77C \uC9C1\uC811 \uC77D\uAE30 \uAD8C\uC7A5. markdown\uACFC \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00."),
|
|
160067
160254
|
parent_page_id: external_exports.string().optional().describe("Parent page ID \u2014 create mode only, nests the new page under this parent. Ignored in update mode."),
|
|
160068
|
-
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.")
|
|
160069
|
-
|
|
160255
|
+
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."),
|
|
160256
|
+
render_diagrams: external_exports.boolean().optional().default(true).describe("Render ```plantuml fences to PNG/SVG and embed as attachments. Default true. Falls back to code block on render failure."),
|
|
160257
|
+
diagram_format: external_exports.enum(["png", "svg"]).optional().default("png").describe("Image format for rendered diagrams. Default png."),
|
|
160258
|
+
diagram_dpi: external_exports.number().optional().default(96).describe("Rendering DPI (PNG only, ignored for SVG). Default 96.")
|
|
160259
|
+
}, async ({ space_key, title, markdown, markdown_file, parent_page_id, page_id, render_diagrams = true, diagram_format = "png", diagram_dpi = 96 }) => {
|
|
160070
160260
|
if (!markdown && !markdown_file) {
|
|
160071
160261
|
throw new Error("Either markdown or markdown_file must be provided");
|
|
160072
160262
|
}
|
|
@@ -160083,22 +160273,60 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160083
160273
|
} else {
|
|
160084
160274
|
md = markdown;
|
|
160085
160275
|
}
|
|
160086
|
-
const
|
|
160087
|
-
|
|
160276
|
+
const { storage, pumlRegistry } = markdownToStorageFormat(md);
|
|
160277
|
+
console.error(`[confluence_publish_doc] pumlRegistry.size=${pumlRegistry.size}, render_diagrams=${render_diagrams}, md_len=${md.length}`);
|
|
160278
|
+
const bodyBytes = Buffer.byteLength(storage, "utf8");
|
|
160088
160279
|
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;
|
|
160089
160280
|
if (warning) console.error(`[confluence_publish_doc] ${warning}`);
|
|
160281
|
+
let diagramStats = { rendered: 0, failed: 0, java_missing: false };
|
|
160282
|
+
const renderedDiagrams = /* @__PURE__ */ new Map();
|
|
160283
|
+
if (render_diagrams && pumlRegistry.size > 0) {
|
|
160284
|
+
for (const [id, source] of pumlRegistry) {
|
|
160285
|
+
try {
|
|
160286
|
+
const diag = await renderPlantUml(source, { format: diagram_format, dpi: diagram_dpi });
|
|
160287
|
+
renderedDiagrams.set(id, diag);
|
|
160288
|
+
diagramStats.rendered++;
|
|
160289
|
+
} catch (err) {
|
|
160290
|
+
diagramStats.failed++;
|
|
160291
|
+
if (/Install Java 21\+/.test(err?.message ?? "")) diagramStats.java_missing = true;
|
|
160292
|
+
console.error(`[confluence_publish_doc] plantuml render failed for ${id}: ${err?.message ?? err}`);
|
|
160293
|
+
}
|
|
160294
|
+
}
|
|
160295
|
+
}
|
|
160090
160296
|
let result;
|
|
160091
160297
|
let mode;
|
|
160298
|
+
let currentPageId;
|
|
160299
|
+
let currentVersion;
|
|
160300
|
+
let versionsUsed = 1;
|
|
160092
160301
|
if (page_id) {
|
|
160093
160302
|
mode = "update";
|
|
160094
160303
|
const current = await confluence2.getPage(page_id, ["version"]);
|
|
160095
|
-
|
|
160096
|
-
result = await confluence2.updatePage(page_id, title,
|
|
160304
|
+
currentVersion = current?.version?.number ?? 0;
|
|
160305
|
+
result = await confluence2.updatePage(page_id, title, storage, currentVersion);
|
|
160306
|
+
currentPageId = page_id;
|
|
160097
160307
|
} else {
|
|
160098
160308
|
mode = "create";
|
|
160099
|
-
result = await confluence2.createPage(space_key, title,
|
|
160309
|
+
result = await confluence2.createPage(space_key, title, storage, parent_page_id);
|
|
160310
|
+
currentPageId = result?.id;
|
|
160311
|
+
currentVersion = result?.version?.number ?? 1;
|
|
160312
|
+
}
|
|
160313
|
+
let finalStorage = storage;
|
|
160314
|
+
if (render_diagrams && renderedDiagrams.size > 0) {
|
|
160315
|
+
for (const [id, diag] of renderedDiagrams) {
|
|
160316
|
+
const filename = `diagram-${id}.${diag.format}`;
|
|
160317
|
+
try {
|
|
160318
|
+
await confluence2.addAttachment(currentPageId, filename, diag.buffer, diag.contentType);
|
|
160319
|
+
} catch (err) {
|
|
160320
|
+
console.error(`[confluence_publish_doc] attachment upload failed for ${id}: ${err?.message ?? err}`);
|
|
160321
|
+
renderedDiagrams.delete(id);
|
|
160322
|
+
diagramStats.rendered--;
|
|
160323
|
+
}
|
|
160324
|
+
}
|
|
160325
|
+
finalStorage = replacePumlMarkers(storage, renderedDiagrams, pumlRegistry);
|
|
160326
|
+
result = await confluence2.updatePage(currentPageId, title, finalStorage, currentVersion);
|
|
160327
|
+
versionsUsed = 2;
|
|
160100
160328
|
}
|
|
160101
|
-
const pageIdOut = result?.id ??
|
|
160329
|
+
const pageIdOut = result?.id ?? currentPageId;
|
|
160102
160330
|
const webui = result?._links?.webui;
|
|
160103
160331
|
const url = webui ? webui.startsWith("http") ? webui : `${confluence2.getBaseUrl()}${webui}` : void 0;
|
|
160104
160332
|
return {
|
|
@@ -160110,17 +160338,41 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160110
160338
|
title,
|
|
160111
160339
|
space_key,
|
|
160112
160340
|
version: result?.version?.number,
|
|
160341
|
+
versions_used: versionsUsed,
|
|
160113
160342
|
url,
|
|
160114
160343
|
input_chars: md.length,
|
|
160115
160344
|
input_source: markdown_file ?? "inline",
|
|
160116
|
-
body_chars:
|
|
160117
|
-
body_bytes:
|
|
160345
|
+
body_chars: finalStorage.length,
|
|
160346
|
+
body_bytes: Buffer.byteLength(finalStorage, "utf8"),
|
|
160347
|
+
diagram_stats: diagramStats,
|
|
160348
|
+
puml_blocks_detected: pumlRegistry.size,
|
|
160118
160349
|
...warning ? { warning } : {}
|
|
160119
160350
|
}, null, 2)
|
|
160120
160351
|
}]
|
|
160121
160352
|
};
|
|
160122
160353
|
});
|
|
160123
160354
|
};
|
|
160355
|
+
function replacePumlMarkers(storage, rendered, pumlRegistry) {
|
|
160356
|
+
let out = storage;
|
|
160357
|
+
for (const [id, diag] of rendered) {
|
|
160358
|
+
const filename = `diagram-${id}.${diag.format}`;
|
|
160359
|
+
const imageMacro = `<ac:image ac:alt="PlantUML Diagram ${id}"><ri:attachment ri:filename="${filename}"/></ac:image>`;
|
|
160360
|
+
out = out.replace(
|
|
160361
|
+
new RegExp(`<p data-puml-id="${id}"></p>`),
|
|
160362
|
+
imageMacro
|
|
160363
|
+
);
|
|
160364
|
+
}
|
|
160365
|
+
for (const [id, source] of pumlRegistry) {
|
|
160366
|
+
if (!rendered.has(id)) {
|
|
160367
|
+
const safeSource = source.replace(/]]>/g, "]]]]><![CDATA[>");
|
|
160368
|
+
out = out.replace(
|
|
160369
|
+
new RegExp(`<p data-puml-id="${id}"></p>`),
|
|
160370
|
+
`<ac:structured-macro ac:name="code"><ac:plain-text-body><![CDATA[${safeSource}]]></ac:plain-text-body></ac:structured-macro>`
|
|
160371
|
+
);
|
|
160372
|
+
}
|
|
160373
|
+
}
|
|
160374
|
+
return out;
|
|
160375
|
+
}
|
|
160124
160376
|
|
|
160125
160377
|
// src/config/risk-models.ts
|
|
160126
160378
|
var RISK_MODELS = {
|
|
@@ -161107,123 +161359,174 @@ var TOOL_CATALOG = [
|
|
|
161107
161359
|
category: "\uBB38\uC11C \uB9AC\uBDF0"
|
|
161108
161360
|
}
|
|
161109
161361
|
];
|
|
161110
|
-
var WORKFLOWS =
|
|
161111
|
-
|
|
161112
|
-
|
|
161113
|
-
"",
|
|
161114
|
-
"
|
|
161115
|
-
|
|
161116
|
-
|
|
161117
|
-
|
|
161118
|
-
|
|
161119
|
-
|
|
161120
|
-
|
|
161121
|
-
|
|
161122
|
-
|
|
161123
|
-
|
|
161124
|
-
|
|
161125
|
-
|
|
161126
|
-
|
|
161127
|
-
|
|
161128
|
-
|
|
161129
|
-
"",
|
|
161130
|
-
|
|
161131
|
-
|
|
161132
|
-
|
|
161133
|
-
"
|
|
161134
|
-
"
|
|
161135
|
-
|
|
161136
|
-
|
|
161137
|
-
|
|
161138
|
-
|
|
161139
|
-
|
|
161140
|
-
|
|
161141
|
-
|
|
161142
|
-
|
|
161143
|
-
|
|
161144
|
-
|
|
161145
|
-
|
|
161146
|
-
|
|
161147
|
-
|
|
161148
|
-
|
|
161149
|
-
|
|
161150
|
-
"
|
|
161151
|
-
|
|
161152
|
-
|
|
161153
|
-
|
|
161154
|
-
|
|
161155
|
-
|
|
161156
|
-
|
|
161157
|
-
|
|
161158
|
-
|
|
161159
|
-
|
|
161160
|
-
|
|
161161
|
-
|
|
161162
|
-
|
|
161163
|
-
"
|
|
161164
|
-
|
|
161165
|
-
|
|
161166
|
-
|
|
161167
|
-
"
|
|
161168
|
-
"
|
|
161169
|
-
|
|
161170
|
-
|
|
161171
|
-
|
|
161172
|
-
|
|
161173
|
-
|
|
161174
|
-
|
|
161175
|
-
|
|
161176
|
-
|
|
161177
|
-
|
|
161178
|
-
|
|
161179
|
-
|
|
161180
|
-
|
|
161181
|
-
|
|
161182
|
-
|
|
161183
|
-
|
|
161184
|
-
|
|
161185
|
-
|
|
161186
|
-
|
|
161187
|
-
"
|
|
161188
|
-
|
|
161189
|
-
|
|
161190
|
-
|
|
161191
|
-
"
|
|
161192
|
-
"",
|
|
161193
|
-
|
|
161194
|
-
|
|
161195
|
-
|
|
161196
|
-
|
|
161197
|
-
|
|
161198
|
-
|
|
161199
|
-
|
|
161200
|
-
|
|
161201
|
-
|
|
161202
|
-
|
|
161203
|
-
|
|
161204
|
-
|
|
161205
|
-
|
|
161206
|
-
|
|
161207
|
-
|
|
161208
|
-
"
|
|
161209
|
-
"
|
|
161210
|
-
|
|
161211
|
-
|
|
161212
|
-
|
|
161213
|
-
|
|
161214
|
-
|
|
161215
|
-
|
|
161216
|
-
|
|
161217
|
-
|
|
161218
|
-
|
|
161219
|
-
|
|
161220
|
-
}
|
|
161362
|
+
var WORKFLOWS = [
|
|
161363
|
+
{
|
|
161364
|
+
id: "pa",
|
|
161365
|
+
title: "PA Gate \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161366
|
+
description: "IEC 62304 PA(Planning Analysis) \uB2E8\uACC4 \u2014 \uC0AC\uC6A9\uC790/\uD658\uACBD/\uC758\uB3C4\uB41C \uC0AC\uC6A9 \uC815\uC758 \u2192 \uC2DC\uC2A4\uD15C \uC694\uAD6C\uC0AC\uD56D \u2192 \uBD84\uB958 \u2192 \uAC1C\uBC1C/\uB9AC\uC2A4\uD06C/\uBCF4\uC548/\uD615\uC0C1 \uAD00\uB9AC \uACC4\uD68D.",
|
|
161367
|
+
steps: [
|
|
161368
|
+
"1. iec_create_gate \u2192 PA Gate + 7\uAC1C Document \uD2F0\uCF13 \uC0DD\uC131",
|
|
161369
|
+
"2. [Intended Use] Document \u2192 IU \uD2F0\uCF13 \uC0DD\uC131 (\uC0AC\uC6A9\uC790, \uD658\uACBD, \uBAA9\uC801 \uC815\uC758)",
|
|
161370
|
+
"3. [System Requirement Spec] \u2192 SyRS \uD2F0\uCF13 \uC0DD\uC131 (IU \uAE30\uBC18 \uC2DC\uC2A4\uD15C \uC694\uAD6C\uC0AC\uD56D)",
|
|
161371
|
+
"4. [Classification] \u2192 \uBD84\uB958 \uD2F0\uCF13 (MDR Class \uD310\uC815)",
|
|
161372
|
+
"5. [SW Development Plan] \u2192 \uAC1C\uBC1C \uACC4\uD68D\uC11C \uC791\uC131",
|
|
161373
|
+
"6. [Risk Management Plan] \u2192 \uB9AC\uC2A4\uD06C \uAD00\uB9AC \uACC4\uD68D\uC11C \uC791\uC131",
|
|
161374
|
+
"7. [Security Management Plan] \u2192 \uBCF4\uC548 \uAD00\uB9AC \uACC4\uD68D\uC11C (IEC 81001-5-1)",
|
|
161375
|
+
"8. [Configuration Management Plan] \u2192 \uD615\uC0C1 \uAD00\uB9AC \uACC4\uD68D\uC11C",
|
|
161376
|
+
"",
|
|
161377
|
+
"\uC0AC\uC6A9\uC131 \uACF5\uD559 (IEC 62366-1)\uB3C4 PA \uB2E8\uACC4\uC5D0\uC11C \uC2DC\uC791:",
|
|
161378
|
+
"9. usability_create_use_spec \u2192 Use Specification \uC815\uC758",
|
|
161379
|
+
"10. usability_create_scenarios \u2192 Normal/Abnormal \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4"
|
|
161380
|
+
],
|
|
161381
|
+
related: ["iec_create_gate", "usability_create_use_spec", "usability_create_scenarios"]
|
|
161382
|
+
},
|
|
161383
|
+
{
|
|
161384
|
+
id: "ea",
|
|
161385
|
+
title: "EA Gate \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161386
|
+
description: "IEC 62304 EA(Engineering Analysis) \uB2E8\uACC4 \u2014 8\uAC1C living document(RMR/SRS/SAD/SDD/SOUP List/Usability Eval Plan/Clinical Eval Plan/Hazard-Related Use Scenarios). \uCD08\uAE30 \uACB0\uC815 \u2192 ER \uAC31\uC2E0 \u2192 CA \uD655\uC815.",
|
|
161387
|
+
steps: [
|
|
161388
|
+
"1. iec_create_gate \u2192 EA Gate + 8\uAC1C Document \uD2F0\uCF13 \uC0DD\uC131 (living documents)",
|
|
161389
|
+
"2. [Risk Management Report] \u2192 risk_create_hazards (FMEA) + usability_link_to_hazard",
|
|
161390
|
+
"3. [SW Requirements Spec] \u2192 FR/NFR \uC815\uB9AC + risk_create_mitigation",
|
|
161391
|
+
"4. [SW Architecture Document] \u2192 \uC544\uD0A4\uD14D\uCC98 \uACB0\uC815",
|
|
161392
|
+
"5. [SW Detailed Design Document] \u2192 \uC720\uB2DB \uC0C1\uC138\uC124\uACC4 + bottom-up Tasks",
|
|
161393
|
+
"6. [SOUP List] \u2192 doc_render(soup_list)",
|
|
161394
|
+
"7. [Usability Evaluation Plan] \u2192 usability_create_use_spec/scenarios \uC5F0\uACC4 + doc_render",
|
|
161395
|
+
"8. [Clinical Evaluation Plan] \u2192 doc_render(clinical_evaluation_plan)",
|
|
161396
|
+
"9. [List of Hazard-Related Use Scenarios] \u2192 usability_create_scenarios(abnormal) \uC5F0\uACC4",
|
|
161397
|
+
"",
|
|
161398
|
+
"EA 8\uAC1C \uBB38\uC11C = living document (IEC 62304 evolutionary \uBAA8\uB378):",
|
|
161399
|
+
" \u2022 EA: \uCD08\uAE30 \uACB0\uC815\xB7\uC2B9\uC778 / ER: \uAC1C\uBC1C\xB7\uAC80\uC99D \uC911 \uAC31\uC2E0 / CA: \uCD5C\uC885 \uD655\uC815",
|
|
161400
|
+
" \u2022 \uAC31\uC2E0 \uD2B8\uB9AC\uAC70:",
|
|
161401
|
+
" - SRS: \uC694\uAD6C\uC0AC\uD56D \uBCC0\uACBD/\uCD94\uAC00 (change-evaluation-list \uC5F0\uACC4)",
|
|
161402
|
+
" - SAD: \uC544\uD0A4\uD14D\uCC98 \uBCC0\uACBD/\uC0C1\uC138\uD654 (architecture-checklist)",
|
|
161403
|
+
" - SDD: sprint \uC720\uB2DB \uCD94\uAC00/\uC0C1\uC138\uD654",
|
|
161404
|
+
" - FMEA Risk Table: \uC0C8 \uC704\uD5D8\xB7\uD1B5\uC81C \uC2DD\uBCC4 (hazard \uCD94\uAC00)",
|
|
161405
|
+
" - SOUP List: \uC758\uC874\uC131 \uBCC0\uACBD (\u2192 CA \uCD5C\uC885 SBOM \uAE30\uBC18 \uD655\uC815)",
|
|
161406
|
+
" - Usability/Clinical Eval Plan: \uD3C9\uAC00 \uACB0\uACFC \uBC18\uC601\xB7\uACC4\uD68D \uC870\uC815",
|
|
161407
|
+
" - Hazard-Related Use Scenarios: \uC0C8 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4",
|
|
161408
|
+
"",
|
|
161409
|
+
"\uAC80\uC99D:",
|
|
161410
|
+
"10. xray_create_test \u2192 \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 \uC0DD\uC131",
|
|
161411
|
+
"11. usability_create_validation \u2192 \uC0AC\uC6A9\uC131 \uAC80\uC99D",
|
|
161412
|
+
"12. doc_check_completeness \u2192 \uAE30\uC220 \uBB38\uC11C \uC644\uC804\uC131 \uAC80\uC99D",
|
|
161413
|
+
"13. doc_generate_evidence \u2192 NB \uC2EC\uC0AC\uC6A9 \uC99D\uAC70 \uD328\uD0A4\uC9C0 \uC0DD\uC131"
|
|
161414
|
+
],
|
|
161415
|
+
related: ["iec_create_gate", "risk_create_hazards", "risk_create_mitigation", "doc_render", "xray_create_test", "usability_create_validation", "doc_check_completeness", "doc_generate_evidence"]
|
|
161416
|
+
},
|
|
161417
|
+
{
|
|
161418
|
+
id: "risk",
|
|
161419
|
+
title: "\uB9AC\uC2A4\uD06C \uAD00\uB9AC \uC6CC\uD06C\uD50C\uB85C\uC6B0 (3 \uBAA8\uB378 \uBA40\uD2F0\uC785\uB825, 0.1.21+)",
|
|
161420
|
+
description: "SoftComply Risk Management Plugin \u2014 P1-P2 ISO 14971 / RPN FMEA / CIA Cyber Sec 3 \uBAA8\uB378 \uB3D9\uC2DC \uC785\uB825. \uC635\uC158 name \u2192 UUID \uC790\uB3D9 \uB9E4\uD551.",
|
|
161421
|
+
steps: [
|
|
161422
|
+
"\uB3C4\uAD6C \uC778\uD130\uD398\uC774\uC2A4:",
|
|
161423
|
+
"- 3 \uBAA8\uB378 \uB3D9\uC2DC \uC785\uB825 \uAC00\uB2A5 \u2014 p1_p2_iso14971 (Severity/P1/P2, ISO 14971) / rpn (Severity/Occurrence/Detectability, FMEA RPN) / cia (Confidentiality/Availability/Integrity + Likelihood, Cyber Sec)",
|
|
161424
|
+
"- \uC635\uC158\uC740 name \uBB38\uC790\uC5F4 \uC785\uB825 \u2014 \uB3C4\uAD6C\uAC00 UUID \uC790\uB3D9 \uB9E4\uD551 (SoftComply RMP \uACF5\uC2DD schema)",
|
|
161425
|
+
"- lookup \uC2E4\uD328 \uC635\uC158\uC740 SKIPPED \uD45C\uC2DC, \uB098\uBA38\uC9C0 \uC815\uC0C1 \uC9C4\uD589",
|
|
161426
|
+
"",
|
|
161427
|
+
"1. risk_get_config \u2192 \uD504\uB85C\uC81D\uD2B8\uC758 3 \uBAA8\uB378 \uC815\uC758 + \uC635\uC158 name \uBAA9\uB85D \uC870\uD68C",
|
|
161428
|
+
"2. IU/SyRS \uBD84\uC11D \u2192 Hazard \uC2DD\uBCC4 (P1-P2 ISO 14971)",
|
|
161429
|
+
"3. risk_create_hazards \u2192 Hazard \uC77C\uAD04 \uC0DD\uC131 + 3 \uBAA8\uB378 risk values \uC790\uB3D9 \uC14B\uD305 + Risk Source/Relates \uB9C1\uD06C",
|
|
161430
|
+
" - hazard \uAC1D\uCCB4 \uC548\uC5D0 p1_p2_iso14971 / rpn / cia \uC635\uC154\uB110 \uAC1D\uCCB4 \uC785\uB825. \uC785\uB825\uD55C \uBAA8\uB378\uB9CC \uC790\uB3D9 setValues \uD638\uCD9C",
|
|
161431
|
+
"4. risk_set_values \u2192 \uAE30\uC874 Hazard\uC5D0 \uCD94\uAC00/\uC218\uC815 risk \uAC12 \uC785\uB825 (3 \uBAA8\uB378 \uB3D9\uC2DC \uB610\uB294 \uBD80\uBD84)",
|
|
161432
|
+
"5. \uC644\uD654 \uC870\uCE58 \uC124\uACC4 \u2192 risk_create_mitigation \u2192 Requirement \uC0DD\uC131 + Hazard Current P2 \uC790\uB3D9 \uC5C5\uB370\uC774\uD2B8 (P1-P2 \uBAA8\uB378)",
|
|
161433
|
+
"6. RMP Panel\uC5D0\uC11C \uC9C1\uC811 \uC785\uB825\uD558\uB294 \uBAA8\uB378 (Risk Score Calculation / Cyber Sec Risk Model) \uC740",
|
|
161434
|
+
" risk_create_hazards / risk_set_values \uC758 rpn / cia \uAC1D\uCCB4\uB85C \uC790\uB3D9 \uC14B\uD305 \uAC00\uB2A5 \u2014 UI \uC218\uB3D9 \uBD88\uD544\uC694",
|
|
161435
|
+
"7. traceability_check \u2192 \uCD94\uC801\uC131 \uD655\uC778",
|
|
161436
|
+
"8. traceability_find_missing \u2192 \uB204\uB77D \uB9C1\uD06C \uAC80\uC0C9",
|
|
161437
|
+
"9. traceability_fix \u2192 \uB204\uB77D \uB9C1\uD06C \uC790\uB3D9 \uC0DD\uC131"
|
|
161438
|
+
],
|
|
161439
|
+
related: ["risk_get_config", "risk_create_hazards", "risk_set_values", "risk_create_mitigation", "traceability_check", "traceability_find_missing", "traceability_fix"]
|
|
161440
|
+
},
|
|
161441
|
+
{
|
|
161442
|
+
id: "usability",
|
|
161443
|
+
title: "\uC0AC\uC6A9\uC131 \uACF5\uD559 (IEC 62366-1) \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161444
|
+
description: "Use Specification \u2192 Normal/Abnormal \uC2DC\uB098\uB9AC\uC624 \u2192 Hazard \uC5F0\uACB0(Risk Source) \u2192 \uAC80\uC99D \uACB0\uACFC \uAE30\uB85D.",
|
|
161445
|
+
steps: [
|
|
161446
|
+
"1. usability_create_use_spec \u2192 Use Specification \uC815\uC758",
|
|
161447
|
+
" (\uC0AC\uC6A9\uC790 \uD504\uB85C\uD30C\uC77C, \uC0AC\uC6A9 \uD658\uACBD, \uC758\uB3C4\uB41C \uC0AC\uC6A9)",
|
|
161448
|
+
"2. usability_create_scenarios \u2192 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4",
|
|
161449
|
+
" - Normal Use: \uC815\uC0C1 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624",
|
|
161450
|
+
" - Abnormal Use: \uBE44\uC815\uC0C1 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 (Hazard \uC6D0\uCC9C)",
|
|
161451
|
+
"3. usability_link_to_hazard \u2192 \uC2DC\uB098\uB9AC\uC624 \u2192 Hazard \uC5F0\uACB0",
|
|
161452
|
+
" (Risk Source \uB9C1\uD06C\uB85C \uC790\uB3D9 \uC5F0\uACB0)",
|
|
161453
|
+
"4. usability_create_validation \u2192 \uC0AC\uC6A9\uC131 \uAC80\uC99D \uACB0\uACFC \uAE30\uB85D",
|
|
161454
|
+
" (\uAC80\uC99D \uBC29\uBC95, \uACB0\uACFC, \uC99D\uBE59)"
|
|
161455
|
+
],
|
|
161456
|
+
related: ["usability_create_use_spec", "usability_create_scenarios", "usability_link_to_hazard", "usability_create_validation"]
|
|
161457
|
+
},
|
|
161458
|
+
{
|
|
161459
|
+
id: "mdr",
|
|
161460
|
+
title: "MDR \uAE30\uC220 \uBB38\uC11C (Annex II) \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161461
|
+
description: "NB(Notified Body) \uC2EC\uC0AC\uC6A9 MDR Annex II \uAE30\uC220\uBB38\uC11C \u2014 \uC644\uC804\uC131 \uAC80\uC0AC + \uCD94\uC801\uC131 \uB9E4\uD2B8\uB9AD\uC2A4 + \uB9AC\uC2A4\uD06C \uB9E4\uD2B8\uB9AD\uC2A4 + V&V \uC694\uC57D.",
|
|
161462
|
+
steps: [
|
|
161463
|
+
"1. doc_create_from_template \u2192 Annex II \uAD6C\uC870\uB85C \uBB38\uC11C \uD2F0\uCF13 \uC0DD\uC131",
|
|
161464
|
+
"2. \uAC01 \uC139\uC158\uBCC4 \uB0B4\uC6A9 \uC791\uC131",
|
|
161465
|
+
"3. doc_check_completeness \u2192 \uB204\uB77D/\uBBF8\uC2B9\uC778 \uD56D\uBAA9 \uAC80\uC0AC",
|
|
161466
|
+
"4. doc_generate_evidence \u2192 \uC99D\uAC70 \uD328\uD0A4\uC9C0 \uC0DD\uC131",
|
|
161467
|
+
" - \uCD94\uC801\uC131 \uB9E4\uD2B8\uB9AD\uC2A4 (IU \u2192 SyRS \u2192 Req \u2192 DD \u2192 Task \u2192 Test)",
|
|
161468
|
+
" - \uB9AC\uC2A4\uD06C \uB9E4\uD2B8\uB9AD\uC2A4 (Hazard \xD7 Severity \xD7 P1/P2)",
|
|
161469
|
+
" - V&V \uC694\uC57D (\uD14C\uC2A4\uD2B8 \uD1B5\uACFC\uC728)"
|
|
161470
|
+
],
|
|
161471
|
+
related: ["doc_create_from_template", "doc_check_completeness", "doc_generate_evidence"]
|
|
161472
|
+
},
|
|
161473
|
+
{
|
|
161474
|
+
id: "customfield",
|
|
161475
|
+
title: "customfield / \uBB38\uC11C \uD544\uB4DC \uCC44\uC6B0\uAE30 \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161476
|
+
description: '\uBE48 \uD2F0\uCF13 "\uBE48 \uAE61\uD1B5" \uBC29\uC9C0 \u2014 schema \uC6B0\uC120 \uC870\uD68C \u2192 ADF \uD544\uB4DC \uC2DD\uBCC4 \u2192 \uBA85\uC2DC \uB610\uB294 auto_detect \uBCC0\uD658.',
|
|
161477
|
+
steps: [
|
|
161478
|
+
"\uC8FC\uC758: customfield \uC911 \uC77C\uBD80\uB294 rich text(ADF)\uB97C \uC694\uAD6C\uD558\uC9C0\uB9CC, createmeta\uAC00 string\uC73C\uB85C",
|
|
161479
|
+
'\uC798\uBABB \uBCF4\uACE0\uD558\uB294 \uACBD\uC6B0\uAC00 \uC788\uB2E4 (\uBE48 \uD2F0\uCF13 "\uBE48 \uAE61\uD1B5"\uC758 \uC8FC\uC6D0\uC778). \uC544\uB798 \uC808\uCC28\uB85C \uBC29\uC9C0\uD55C\uB2E4.',
|
|
161480
|
+
"",
|
|
161481
|
+
"1. jira_get_issue_type_schema \u2192 \uC774\uC288\uD0C0\uC785 \uD544\uB4DC \uAD6C\uC870 + inferredFormat \uD655\uC778",
|
|
161482
|
+
" inferredFormat \uAC12: adf(\uD655\uC815) / adf-suspect(string\uC774\uB098 textarea, \uC758\uC2EC) /",
|
|
161483
|
+
" option / string / number / date ...",
|
|
161484
|
+
"2. ADF \uD544\uB4DC(customfield_*) \uC2DD\uBCC4 \u2014 inferredFormat\uC774 adf \uB610\uB294 adf-suspect\uC778 \uD544\uB4DC",
|
|
161485
|
+
"3. jira_create_issue / jira_update_issue \uD638\uCD9C \uC2DC:",
|
|
161486
|
+
" - \uC790\uB3D9 \uAC10\uC9C0: auto_detect_rich_text: true (schema\uC5D0\uC11C ADF \uD544\uB4DC \uC790\uB3D9 \uCD94\uC815)",
|
|
161487
|
+
' - \uBA85\uC2DC \uC9C0\uC815: rich_text_custom_fields: ["customfield_xxxx", ...] (\uCD5C\uC885 \uBCF4\uC218)',
|
|
161488
|
+
" - \uD3C9\uBB38\uC744 \uB118\uAE30\uBA74 \uC790\uB3D9\uC73C\uB85C ADF\uB85C \uBCC0\uD658\uB428 (\uC774\uBBF8 ADF \uAC1D\uCCB4\uBA74 \uADF8\uB300\uB85C)",
|
|
161489
|
+
'4. option \uD544\uB4DC(\uC608: Phase)\uB294 { value: "PA" } \uD615\uD0DC\uB85C extra_fields/fields\uC5D0 \uC804\uB2EC',
|
|
161490
|
+
"",
|
|
161491
|
+
"\uD45C\uC900 \uC6D0\uCE59: \uBB38\uC11C \uD2F0\uCF13\uC744 \uB9CC\uB4E4 \uB54C\uB294 \uBC18\uB4DC\uC2DC schema\uB97C \uBA3C\uC800 \uBCF4\uACE0,",
|
|
161492
|
+
"customfield\uB97C \uADF8 \uAD6C\uC870\uC5D0 \uB9DE\uCDB0 \uCC44\uC6B4\uB2E4 \u2014 \uBE48 \uD2F0\uCF13\uC744 \uBC29\uCE58\uD558\uC9C0 \uC54A\uB294\uB2E4."
|
|
161493
|
+
],
|
|
161494
|
+
related: ["jira_get_issue_type_schema", "jira_create_issue", "jira_update_issue"]
|
|
161495
|
+
},
|
|
161496
|
+
{
|
|
161497
|
+
id: "diagram",
|
|
161498
|
+
title: "PlantUML \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uB80C\uB354\uB9C1",
|
|
161499
|
+
description: "confluence_publish_doc / markdown_to_pdf / jira_attach_pdf_from_markdown \uD638\uCD9C \uC2DC ```plantuml \uD39C\uC2A4\uB97C PNG\uB85C \uC790\uB3D9 \uB80C\uB354\uB9C1. Java 21+ \uC0AC\uC804 \uC694\uAD6C. GPL-3.0 \uAC80\uD1A0 \uC644\uB8CC(2026-07-31).",
|
|
161500
|
+
steps: [
|
|
161501
|
+
"1. Java 21+ \uC124\uCE58 \uD655\uC778: java -version (\uC5C6\uC73C\uBA74 https://adoptium.net/)",
|
|
161502
|
+
"2. Graphviz \uBBF8\uC124\uCE58 \uC2DC\uC5D0\uB3C4 \uB3D9\uC791 \u2014 PlantUML\uC774 smetana \uC5D4\uC9C4\uC73C\uB85C layout \uCC98\uB9AC (PlantUML \uAE30\uBCF8 \uD65C\uC131\uD654). \uB2E4\uB9CC \uC77C\uBD80 \uB2E4\uC774\uC5B4\uADF8\uB7A8(\uBCF5\uC7A1 graph)\uC740 Graphviz \uD544\uC694\uD560 \uC218 \uC788\uC74C.",
|
|
161503
|
+
"3. confluence_publish_doc \uD638\uCD9C \uC2DC render_diagrams: true(\uAE30\uBCF8\uAC12)\uB85C \uC790\uB3D9 \uC784\uBCA0\uB4DC. \uC2E4\uD328 \uBE14\uB85D\uC740 \uCF54\uB4DC \uB9E4\uD06C\uB85C\uB85C \uD3F4\uBC31.",
|
|
161504
|
+
"4. markdown_to_pdf / jira_attach_pdf_from_markdown \uD638\uCD9C \uC2DC render_plantuml: true(\uAE30\uBCF8\uAC12)\uB85C PDF \uB0B4 \uC774\uBBF8\uC9C0 \uBC15\uC2A4 \uC0BD\uC785.",
|
|
161505
|
+
"5. \uC635\uD2B8\uC544\uC6C3: render_diagrams: false \uB610\uB294 render_plantuml: false. \uBD80\uBD84 disable \uAC00\uB2A5.",
|
|
161506
|
+
"6. \uACB0\uACFC JSON\uC758 diagram_stats (rendered/failed/java_missing) \uD544\uB4DC\uB85C \uB80C\uB354 \uACB0\uACFC \uD655\uC778."
|
|
161507
|
+
],
|
|
161508
|
+
related: ["confluence_publish_doc", "markdown_to_pdf", "jira_attach_pdf_from_markdown"]
|
|
161509
|
+
}
|
|
161510
|
+
];
|
|
161511
|
+
function workflowToText(w2) {
|
|
161512
|
+
const lines = [];
|
|
161513
|
+
lines.push(`=== ${w2.title} ===`);
|
|
161514
|
+
lines.push("");
|
|
161515
|
+
if (w2.description) {
|
|
161516
|
+
lines.push(w2.description);
|
|
161517
|
+
lines.push("");
|
|
161518
|
+
}
|
|
161519
|
+
for (const step of w2.steps) {
|
|
161520
|
+
lines.push(step);
|
|
161521
|
+
}
|
|
161522
|
+
return lines.join("\n");
|
|
161523
|
+
}
|
|
161221
161524
|
|
|
161222
161525
|
// src/tools/help.ts
|
|
161223
161526
|
var registerHelpTools = ({ server: server2 }) => {
|
|
161224
161527
|
server2.tool("help", "Show available tools, workflows, and usage guides. Call without arguments for full catalog, or specify a topic.", {
|
|
161225
161528
|
topic: external_exports.string().optional().describe(
|
|
161226
|
-
'Topic: "tools" (all tools), "workflows" (all workflows), "pa", "ea", "risk", "usability", "mdr", or a specific tool name (e.g. "risk_create_hazards")'
|
|
161529
|
+
'Topic: "tools" (all tools), "workflows" (all workflows), "pa", "ea", "risk", "usability", "mdr", "customfield", "diagram", or a specific tool name (e.g. "risk_create_hazards")'
|
|
161227
161530
|
)
|
|
161228
161531
|
}, async ({ topic }) => {
|
|
161229
161532
|
if (!topic) {
|
|
@@ -161236,19 +161539,21 @@ var registerHelpTools = ({ server: server2 }) => {
|
|
|
161236
161539
|
}
|
|
161237
161540
|
lines.push("");
|
|
161238
161541
|
}
|
|
161239
|
-
|
|
161542
|
+
const wfIds2 = WORKFLOWS.map((w2) => w2.id).join(", ");
|
|
161543
|
+
lines.push(`\uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAC00\uC774\uB4DC: help(topic="workflows") \uB610\uB294 help(topic="<id>") \u2014 \uC0AC\uC6A9 \uAC00\uB2A5 id: ${wfIds2}`);
|
|
161240
161544
|
lines.push('\uD2B9\uC815 \uD234 \uC0C1\uC138: help(topic="\uD234\uC774\uB984")');
|
|
161241
161545
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
161242
161546
|
}
|
|
161243
|
-
|
|
161244
|
-
|
|
161547
|
+
const workflow = WORKFLOWS.find((w2) => w2.id === topic);
|
|
161548
|
+
if (workflow) {
|
|
161549
|
+
return { content: [{ type: "text", text: workflowToText(workflow) }] };
|
|
161245
161550
|
}
|
|
161246
161551
|
if (topic === "tools") {
|
|
161247
161552
|
const lines = TOOL_CATALOG.map((t2) => `${t2.name} [${t2.category}]: ${t2.description}`);
|
|
161248
161553
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
161249
161554
|
}
|
|
161250
161555
|
if (topic === "workflows") {
|
|
161251
|
-
const lines =
|
|
161556
|
+
const lines = WORKFLOWS.map(workflowToText).join("\n\n");
|
|
161252
161557
|
return { content: [{ type: "text", text: lines }] };
|
|
161253
161558
|
}
|
|
161254
161559
|
const tool = TOOL_CATALOG.find((t2) => t2.name === topic);
|
|
@@ -161258,8 +161563,9 @@ ${tool.description}
|
|
|
161258
161563
|
|
|
161259
161564
|
\uC790\uC138\uD55C \uD30C\uB77C\uBBF8\uD130\uB294 \uC774 \uD234\uC744 \uC9C1\uC811 \uD638\uCD9C\uD558\uC5EC \uD655\uC778\uD558\uC138\uC694.` }] };
|
|
161260
161565
|
}
|
|
161566
|
+
const wfIds = WORKFLOWS.map((w2) => w2.id).join(", ");
|
|
161261
161567
|
return { content: [{ type: "text", text: `\uC54C \uC218 \uC5C6\uB294 \uD1A0\uD53D: "${topic}"
|
|
161262
|
-
\uC0AC\uC6A9 \uAC00\uB2A5: tools, workflows,
|
|
161568
|
+
\uC0AC\uC6A9 \uAC00\uB2A5: tools, workflows, ${wfIds}, \uB610\uB294 \uD234 \uC774\uB984` }] };
|
|
161263
161569
|
});
|
|
161264
161570
|
};
|
|
161265
161571
|
|
|
@@ -161747,8 +162053,8 @@ var registerDocValidationTools = (ctx2) => {
|
|
|
161747
162053
|
};
|
|
161748
162054
|
|
|
161749
162055
|
// src/tools/init.ts
|
|
161750
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "fs";
|
|
161751
|
-
import { join as
|
|
162056
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
|
|
162057
|
+
import { join as join3 } from "path";
|
|
161752
162058
|
var registerInitTools = ({ server: server2 }) => {
|
|
161753
162059
|
server2.tool(
|
|
161754
162060
|
"jira_init_project",
|
|
@@ -161758,11 +162064,11 @@ var registerInitTools = ({ server: server2 }) => {
|
|
|
161758
162064
|
},
|
|
161759
162065
|
async ({ project_key }) => {
|
|
161760
162066
|
const cwd = process.cwd();
|
|
161761
|
-
const claudeMdPath =
|
|
162067
|
+
const claudeMdPath = join3(cwd, "CLAUDE.md");
|
|
161762
162068
|
const line = `\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 Jira key\uB294 ${project_key}\uC785\uB2C8\uB2E4.`;
|
|
161763
162069
|
try {
|
|
161764
162070
|
let content = "";
|
|
161765
|
-
if (
|
|
162071
|
+
if (existsSync2(claudeMdPath)) {
|
|
161766
162072
|
content = readFileSync2(claudeMdPath, "utf-8");
|
|
161767
162073
|
if (content.includes(line)) {
|
|
161768
162074
|
return { content: [{ type: "text", text: `\uC774\uBBF8 CLAUDE.md\uC5D0 ${project_key} \uD504\uB85C\uC81D\uD2B8 \uC124\uC815\uC774 \uC788\uC2B5\uB2C8\uB2E4.` }] };
|
|
@@ -161789,7 +162095,7 @@ var registerInitTools = ({ server: server2 }) => {
|
|
|
161789
162095
|
|
|
161790
162096
|
// src/tools/doc-render.ts
|
|
161791
162097
|
import { readFileSync as readFileSync3 } from "fs";
|
|
161792
|
-
import { fileURLToPath } from "url";
|
|
162098
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
161793
162099
|
import path from "path";
|
|
161794
162100
|
|
|
161795
162101
|
// src/utils/doc-render.ts
|
|
@@ -161854,7 +162160,7 @@ var TEMPLATE_VERSION = "17d0c4e";
|
|
|
161854
162160
|
|
|
161855
162161
|
// src/tools/doc-render.ts
|
|
161856
162162
|
init_adf();
|
|
161857
|
-
var __dirname2 = path.dirname(
|
|
162163
|
+
var __dirname2 = path.dirname(fileURLToPath2(import.meta.url));
|
|
161858
162164
|
var TEMPLATE_DIR = path.resolve(__dirname2, "../vendor/dev-docs-templates/templates");
|
|
161859
162165
|
var registerDocRenderTools = (ctx2) => {
|
|
161860
162166
|
const { server: server2, jira: jira2 } = ctx2;
|
|
@@ -161949,7 +162255,7 @@ import { execFileSync } from "child_process";
|
|
|
161949
162255
|
// src/utils/markdownToPdf.ts
|
|
161950
162256
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
161951
162257
|
import { tmpdir } from "os";
|
|
161952
|
-
import { join as
|
|
162258
|
+
import { join as join5 } from "path";
|
|
161953
162259
|
import { randomUUID } from "crypto";
|
|
161954
162260
|
|
|
161955
162261
|
// node_modules/pdfkit/js/pdfkit.es.js
|
|
@@ -163841,12 +164147,12 @@ function $e71565f2ce09cb6b$export$69a3209f1a06c04d(target, key, descriptor) {
|
|
|
163841
164147
|
let fn = descriptor.value;
|
|
163842
164148
|
return {
|
|
163843
164149
|
get() {
|
|
163844
|
-
let
|
|
164150
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
163845
164151
|
function memoized(...args) {
|
|
163846
164152
|
let key2 = args.length > 0 ? args[0] : "value";
|
|
163847
|
-
if (
|
|
164153
|
+
if (cache2.has(key2)) return cache2.get(key2);
|
|
163848
164154
|
let result = fn.apply(this, args);
|
|
163849
|
-
|
|
164155
|
+
cache2.set(key2, result);
|
|
163850
164156
|
return result;
|
|
163851
164157
|
}
|
|
163852
164158
|
Object.defineProperty(this, key, {
|
|
@@ -170517,8 +170823,8 @@ var $55f71433a605c87d$export$2e2bcd8739ae039 = class {
|
|
|
170517
170823
|
}
|
|
170518
170824
|
if (count === 1) {
|
|
170519
170825
|
let result = input.map((g3) => g3.id);
|
|
170520
|
-
let
|
|
170521
|
-
if (
|
|
170826
|
+
let cache2 = this.inputCache[found];
|
|
170827
|
+
if (cache2) cache2.push(result);
|
|
170522
170828
|
else this.inputCache[found] = [
|
|
170523
170829
|
result
|
|
170524
170830
|
];
|
|
@@ -182989,14 +183295,14 @@ var SubsetMixin = {
|
|
|
182989
183295
|
var ROW_FIELDS = ["height", "minHeight", "maxHeight"];
|
|
182990
183296
|
var COLUMN_FIELDS = ["width", "minWidth", "maxWidth"];
|
|
182991
183297
|
function memoize(fn, maxSize) {
|
|
182992
|
-
const
|
|
183298
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
182993
183299
|
return function(...args) {
|
|
182994
183300
|
const key = args[0];
|
|
182995
|
-
if (!
|
|
182996
|
-
|
|
182997
|
-
if (
|
|
183301
|
+
if (!cache2.has(key)) {
|
|
183302
|
+
cache2.set(key, fn(...args));
|
|
183303
|
+
if (cache2.size > maxSize) cache2.delete(cache2.keys().next());
|
|
182998
183304
|
}
|
|
182999
|
-
return
|
|
183305
|
+
return cache2.get(key);
|
|
183000
183306
|
};
|
|
183001
183307
|
}
|
|
183002
183308
|
function isObject2(item) {
|
|
@@ -184000,23 +184306,23 @@ PDFDocument.LineWrapper = LineWrapper;
|
|
|
184000
184306
|
init_marked_esm();
|
|
184001
184307
|
|
|
184002
184308
|
// src/utils/pdf-fonts.ts
|
|
184003
|
-
import { existsSync as
|
|
184004
|
-
import { join as
|
|
184005
|
-
import { fileURLToPath as
|
|
184309
|
+
import { existsSync as existsSync3 } from "fs";
|
|
184310
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
184311
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
184006
184312
|
var BUNDLED_FONT_FAMILY = "BodyFont";
|
|
184007
184313
|
var BUNDLED_FONT_FAMILY_BOLD = "BodyFont-Bold";
|
|
184008
184314
|
var DEFAULT_FAMILY = "BodyFont";
|
|
184009
184315
|
function bundledFontPaths() {
|
|
184010
|
-
const here = typeof __dirname !== "undefined" ? __dirname :
|
|
184011
|
-
const rootFromSrc =
|
|
184012
|
-
const candidates = [
|
|
184316
|
+
const here = typeof __dirname !== "undefined" ? __dirname : dirname2(fileURLToPath3(import.meta.url));
|
|
184317
|
+
const rootFromSrc = join4(here, "..", "..");
|
|
184318
|
+
const candidates = [join4(here, "fonts"), join4(rootFromSrc, "dist", "fonts")];
|
|
184013
184319
|
const fontsDir = candidates.find(
|
|
184014
|
-
(d2) =>
|
|
184320
|
+
(d2) => existsSync3(join4(d2, "Pretendard-Regular.ttf")) && existsSync3(join4(d2, "Pretendard-Bold.ttf"))
|
|
184015
184321
|
);
|
|
184016
184322
|
const dir = fontsDir || candidates[0];
|
|
184017
184323
|
return {
|
|
184018
|
-
regular:
|
|
184019
|
-
bold:
|
|
184324
|
+
regular: join4(dir, "Pretendard-Regular.ttf"),
|
|
184325
|
+
bold: join4(dir, "Pretendard-Bold.ttf")
|
|
184020
184326
|
};
|
|
184021
184327
|
}
|
|
184022
184328
|
function resolveFonts(opts) {
|
|
@@ -184029,7 +184335,7 @@ function resolveFonts(opts) {
|
|
|
184029
184335
|
};
|
|
184030
184336
|
}
|
|
184031
184337
|
const paths = bundledFontPaths();
|
|
184032
|
-
if (
|
|
184338
|
+
if (existsSync3(paths.regular) && existsSync3(paths.bold)) {
|
|
184033
184339
|
return {
|
|
184034
184340
|
regularFamily: BUNDLED_FONT_FAMILY,
|
|
184035
184341
|
boldFamily: BUNDLED_FONT_FAMILY_BOLD,
|
|
@@ -184051,6 +184357,21 @@ var FRONTMATTER_RE2 = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
|
|
|
184051
184357
|
function stripFrontmatter2(md) {
|
|
184052
184358
|
return md.replace(FRONTMATTER_RE2, "");
|
|
184053
184359
|
}
|
|
184360
|
+
function lexAndExtractPlantUml(body) {
|
|
184361
|
+
const tokens = g.lexer(stripFrontmatter2(body ?? ""));
|
|
184362
|
+
const pumlRegistry = /* @__PURE__ */ new Map();
|
|
184363
|
+
let counter = 0;
|
|
184364
|
+
for (const tok of tokens) {
|
|
184365
|
+
if (tok?.type !== "code") continue;
|
|
184366
|
+
const lang = String(tok.lang ?? "").trim().toLowerCase();
|
|
184367
|
+
if (lang === "plantuml" || lang === "puml" || lang === "plantuml-markdown") {
|
|
184368
|
+
const id = `PUML_${counter++}`;
|
|
184369
|
+
pumlRegistry.set(id, String(tok.text ?? ""));
|
|
184370
|
+
tok._pumlId = id;
|
|
184371
|
+
}
|
|
184372
|
+
}
|
|
184373
|
+
return { tokens, pumlRegistry };
|
|
184374
|
+
}
|
|
184054
184375
|
var PAGE_SIZE_DEFAULT = "A4";
|
|
184055
184376
|
var MARGIN_DEFAULT = 56;
|
|
184056
184377
|
async function markdownToPdf(md, opts = {}) {
|
|
@@ -184064,7 +184385,9 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184064
184385
|
pageSize = PAGE_SIZE_DEFAULT,
|
|
184065
184386
|
margin = {},
|
|
184066
184387
|
language = "en",
|
|
184067
|
-
collectWarnings = false
|
|
184388
|
+
collectWarnings = false,
|
|
184389
|
+
renderPlantUml: renderPUML = true,
|
|
184390
|
+
diagramDpi = 96
|
|
184068
184391
|
} = opts;
|
|
184069
184392
|
const top = margin.top ?? MARGIN_DEFAULT;
|
|
184070
184393
|
const bottom = margin.bottom ?? MARGIN_DEFAULT;
|
|
@@ -184121,10 +184444,22 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184121
184444
|
doc.fillColor("#000");
|
|
184122
184445
|
doc.addPage();
|
|
184123
184446
|
}
|
|
184124
|
-
const
|
|
184125
|
-
const
|
|
184447
|
+
const { tokens, pumlRegistry } = lexAndExtractPlantUml(md ?? "");
|
|
184448
|
+
const pumlImages = /* @__PURE__ */ new Map();
|
|
184449
|
+
if (renderPUML && pumlRegistry.size > 0) {
|
|
184450
|
+
await Promise.all(
|
|
184451
|
+
[...pumlRegistry].map(async ([id, source]) => {
|
|
184452
|
+
try {
|
|
184453
|
+
const diag = await renderPlantUml(source, { format: "png", dpi: diagramDpi });
|
|
184454
|
+
pumlImages.set(id, diag.buffer);
|
|
184455
|
+
} catch (err) {
|
|
184456
|
+
console.error(`[markdownToPdf] plantuml render failed for ${id}: ${err?.message ?? err}`);
|
|
184457
|
+
}
|
|
184458
|
+
})
|
|
184459
|
+
);
|
|
184460
|
+
}
|
|
184126
184461
|
for (const tok of tokens) {
|
|
184127
|
-
renderToken(doc, tok, fonts);
|
|
184462
|
+
renderToken(doc, tok, fonts, pumlImages);
|
|
184128
184463
|
}
|
|
184129
184464
|
if (tokens.length === 0) {
|
|
184130
184465
|
doc.fontSize(11).fillColor("#000").text("");
|
|
@@ -184177,9 +184512,9 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184177
184512
|
doc.restore();
|
|
184178
184513
|
}
|
|
184179
184514
|
const chunks = [];
|
|
184180
|
-
const ended = new Promise((
|
|
184515
|
+
const ended = new Promise((resolve2, reject) => {
|
|
184181
184516
|
doc.on("data", (c) => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c)));
|
|
184182
|
-
doc.on("end", () =>
|
|
184517
|
+
doc.on("end", () => resolve2());
|
|
184183
184518
|
doc.on("error", (err) => reject(err));
|
|
184184
184519
|
});
|
|
184185
184520
|
doc.end();
|
|
@@ -184220,7 +184555,7 @@ function lineHeightOf(doc) {
|
|
|
184220
184555
|
const size = doc._fontSize ?? 11;
|
|
184221
184556
|
return size * 1.2;
|
|
184222
184557
|
}
|
|
184223
|
-
function renderToken(doc, tok, fonts) {
|
|
184558
|
+
function renderToken(doc, tok, fonts, pumlImages) {
|
|
184224
184559
|
if (!tok || typeof tok !== "object") return;
|
|
184225
184560
|
switch (tok.type) {
|
|
184226
184561
|
case "heading":
|
|
@@ -184230,13 +184565,24 @@ function renderToken(doc, tok, fonts) {
|
|
|
184230
184565
|
renderParagraph(doc, tok, fonts);
|
|
184231
184566
|
return;
|
|
184232
184567
|
case "code":
|
|
184568
|
+
if (tok._pumlId) {
|
|
184569
|
+
const buf = pumlImages.get(tok._pumlId);
|
|
184570
|
+
if (buf) {
|
|
184571
|
+
try {
|
|
184572
|
+
renderPlantUmlImage(doc, buf);
|
|
184573
|
+
return;
|
|
184574
|
+
} catch (err) {
|
|
184575
|
+
console.error(`[markdownToPdf] image() failed for ${tok._pumlId}: ${err?.message ?? err}`);
|
|
184576
|
+
}
|
|
184577
|
+
}
|
|
184578
|
+
}
|
|
184233
184579
|
renderCodeBlock(doc, tok);
|
|
184234
184580
|
return;
|
|
184235
184581
|
case "blockquote":
|
|
184236
184582
|
renderBlockquote(doc, tok, fonts);
|
|
184237
184583
|
return;
|
|
184238
184584
|
case "list":
|
|
184239
|
-
renderList(doc, tok, fonts, 0);
|
|
184585
|
+
renderList(doc, tok, fonts, 0, pumlImages);
|
|
184240
184586
|
return;
|
|
184241
184587
|
case "table":
|
|
184242
184588
|
renderTable(doc, tok, fonts);
|
|
@@ -184253,6 +184599,13 @@ function renderToken(doc, tok, fonts) {
|
|
|
184253
184599
|
}
|
|
184254
184600
|
}
|
|
184255
184601
|
}
|
|
184602
|
+
function renderPlantUmlImage(doc, buf) {
|
|
184603
|
+
const marginL = doc.page.margins.left;
|
|
184604
|
+
const marginR = doc.page.margins.right;
|
|
184605
|
+
const availableWidth = doc.page.width - marginL - marginR;
|
|
184606
|
+
doc.y += SPACE2.CODE_BEFORE;
|
|
184607
|
+
doc.image(buf, { fit: [availableWidth, 200], align: "center" });
|
|
184608
|
+
}
|
|
184256
184609
|
function renderHeading(doc, tok, fonts) {
|
|
184257
184610
|
const level = Math.min(Math.max(Number(tok.depth) || 1, 1), 6);
|
|
184258
184611
|
const size = HEADING_SIZES[level - 1];
|
|
@@ -184369,7 +184722,7 @@ function extractInlineText(node) {
|
|
|
184369
184722
|
if (Array.isArray(node.tokens)) return node.tokens.map(extractInlineText).join("");
|
|
184370
184723
|
return "";
|
|
184371
184724
|
}
|
|
184372
|
-
function renderList(doc, tok, fonts, depth) {
|
|
184725
|
+
function renderList(doc, tok, fonts, depth, pumlImages) {
|
|
184373
184726
|
const items = tok.items ?? [];
|
|
184374
184727
|
const ordered = !!tok.ordered;
|
|
184375
184728
|
const marginL = doc.page.margins.left;
|
|
@@ -184409,9 +184762,9 @@ function renderList(doc, tok, fonts, depth) {
|
|
|
184409
184762
|
} else if (sub?.type === "list") {
|
|
184410
184763
|
doc.x = marginL + indent + 12;
|
|
184411
184764
|
doc.y = doc.y + SPACE2.LIST_ITEM_BEFORE;
|
|
184412
|
-
renderList(doc, sub, fonts, depth + 1);
|
|
184765
|
+
renderList(doc, sub, fonts, depth + 1, pumlImages);
|
|
184413
184766
|
} else {
|
|
184414
|
-
renderToken(doc, sub, fonts);
|
|
184767
|
+
renderToken(doc, sub, fonts, pumlImages);
|
|
184415
184768
|
}
|
|
184416
184769
|
}
|
|
184417
184770
|
if (!drewAnything && item.text) {
|
|
@@ -184512,7 +184865,7 @@ function renderHr(doc) {
|
|
|
184512
184865
|
doc.y = y2 + SPACE2.HR_AFTER;
|
|
184513
184866
|
}
|
|
184514
184867
|
function writePdfToTempFile(buffer) {
|
|
184515
|
-
const path3 =
|
|
184868
|
+
const path3 = join5(tmpdir(), `${randomUUID()}.pdf`);
|
|
184516
184869
|
writeFileSync3(path3, buffer);
|
|
184517
184870
|
return path3;
|
|
184518
184871
|
}
|
|
@@ -184564,9 +184917,11 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184564
184917
|
font_path: external_exports.string().optional().describe("\uD3F0\uD2B8 \uD30C\uC77C \uC808\uB300 \uACBD\uB85C (.ttf/.otf/.ttc). \uBBF8\uC9C0\uC815 \uC2DC \uBC88\uB4E4 Pretendard \uC0AC\uC6A9 (\uBD80\uC7AC \uC2DC Helvetica \uD3F4\uBC31)"),
|
|
184565
184918
|
font_family_name: external_exports.string().optional().describe('pdfkit registerFont \uC774\uB984 (\uAE30\uBCF8 "BodyFont")'),
|
|
184566
184919
|
page_size: external_exports.enum(["A4", "LETTER", "LEGAL"]).optional().default("A4").describe("\uD398\uC774\uC9C0 \uD06C\uAE30"),
|
|
184567
|
-
output_mode: external_exports.enum(["base64", "tmpfile"]).optional().default("base64").describe("base64(\uAE30\uBCF8, JSON \uC548\uC804) / tmpfile(\uC808\uB300\uACBD\uB85C \uBC18\uD658, consumer\uAC00 unlink \uCC45\uC784)")
|
|
184920
|
+
output_mode: external_exports.enum(["base64", "tmpfile"]).optional().default("base64").describe("base64(\uAE30\uBCF8, JSON \uC548\uC804) / tmpfile(\uC808\uB300\uACBD\uB85C \uBC18\uD658, consumer\uAC00 unlink \uCC45\uC784)"),
|
|
184921
|
+
render_plantuml: external_exports.boolean().optional().default(true).describe("Render ```plantuml fences to PNG and embed in PDF. Default true."),
|
|
184922
|
+
diagram_dpi: external_exports.number().optional().default(96).describe("PlantUML rendering DPI. Default 96.")
|
|
184568
184923
|
},
|
|
184569
|
-
async ({ markdown, markdown_file, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode }) => {
|
|
184924
|
+
async ({ markdown, markdown_file, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode, render_plantuml, diagram_dpi }) => {
|
|
184570
184925
|
if (!markdown && !markdown_file) {
|
|
184571
184926
|
throw new Error("Either markdown or markdown_file must be provided");
|
|
184572
184927
|
}
|
|
@@ -184591,6 +184946,8 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184591
184946
|
...font_path !== void 0 ? { fontPath: font_path } : {},
|
|
184592
184947
|
...font_family_name !== void 0 ? { fontFamilyName: font_family_name } : {},
|
|
184593
184948
|
pageSize: page_size,
|
|
184949
|
+
renderPlantUml: render_plantuml,
|
|
184950
|
+
diagramDpi: diagram_dpi,
|
|
184594
184951
|
collectWarnings: true
|
|
184595
184952
|
});
|
|
184596
184953
|
const buffer = result.buffer;
|
|
@@ -184685,7 +185042,9 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184685
185042
|
author: external_exports.string().optional().describe("PDF /Author \uBA54\uD0C0"),
|
|
184686
185043
|
font_path: external_exports.string().optional().describe("\uD3F0\uD2B8 \uD30C\uC77C \uC808\uB300 \uACBD\uB85C"),
|
|
184687
185044
|
font_family_name: external_exports.string().optional().describe("pdfkit registerFont \uC774\uB984"),
|
|
184688
|
-
page_size: external_exports.enum(["A4", "LETTER", "LEGAL"]).optional().default("A4").describe("\uD398\uC774\uC9C0 \uD06C\uAE30")
|
|
185045
|
+
page_size: external_exports.enum(["A4", "LETTER", "LEGAL"]).optional().default("A4").describe("\uD398\uC774\uC9C0 \uD06C\uAE30"),
|
|
185046
|
+
render_plantuml: external_exports.boolean().optional().default(true).describe("Render ```plantuml fences to PNG and embed in PDF. Default true."),
|
|
185047
|
+
diagram_dpi: external_exports.number().optional().default(96).describe("PlantUML rendering DPI. Default 96.")
|
|
184689
185048
|
},
|
|
184690
185049
|
async ({
|
|
184691
185050
|
issue_key,
|
|
@@ -184699,7 +185058,9 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184699
185058
|
author,
|
|
184700
185059
|
font_path,
|
|
184701
185060
|
font_family_name,
|
|
184702
|
-
page_size
|
|
185061
|
+
page_size,
|
|
185062
|
+
render_plantuml,
|
|
185063
|
+
diagram_dpi
|
|
184703
185064
|
}) => {
|
|
184704
185065
|
if (!markdown && !markdown_file) {
|
|
184705
185066
|
throw new Error("Either markdown or markdown_file must be provided");
|
|
@@ -184725,6 +185086,8 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184725
185086
|
...font_path !== void 0 ? { fontPath: font_path } : {},
|
|
184726
185087
|
...font_family_name !== void 0 ? { fontFamilyName: font_family_name } : {},
|
|
184727
185088
|
pageSize: page_size,
|
|
185089
|
+
renderPlantUml: render_plantuml,
|
|
185090
|
+
diagramDpi: diagram_dpi,
|
|
184728
185091
|
collectWarnings: true
|
|
184729
185092
|
});
|
|
184730
185093
|
const buffer = result.buffer;
|
|
@@ -185121,9 +185484,9 @@ var registerExpertTools = (ctx2) => {
|
|
|
185121
185484
|
|
|
185122
185485
|
// src/tools/review-criteria.ts
|
|
185123
185486
|
import { readFileSync as readFileSync5 } from "fs";
|
|
185124
|
-
import { fileURLToPath as
|
|
185487
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
185125
185488
|
import path2 from "path";
|
|
185126
|
-
var __dirname3 = path2.dirname(
|
|
185489
|
+
var __dirname3 = path2.dirname(fileURLToPath4(import.meta.url));
|
|
185127
185490
|
var CRITERIA_PATH = path2.resolve(__dirname3, "../data/review-criteria.md");
|
|
185128
185491
|
var registerReviewCriteriaTools = (ctx2) => {
|
|
185129
185492
|
ctx2.server.tool(
|
|
@@ -185170,7 +185533,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
|
|
|
185170
185533
|
var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
|
|
185171
185534
|
var server = new McpServer({
|
|
185172
185535
|
name: "jira-confluence",
|
|
185173
|
-
version: "0.1.
|
|
185536
|
+
version: "0.1.29"
|
|
185174
185537
|
});
|
|
185175
185538
|
var ctx = { server, jira, confluence, risk, xray };
|
|
185176
185539
|
registerJiraCrudTools(ctx);
|