@neobiotechlabs/neobiotech-dev-agent 0.1.26 → 0.1.28
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 +607 -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 ?? "");
|
|
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,59 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160083
160273
|
} else {
|
|
160084
160274
|
md = markdown;
|
|
160085
160275
|
}
|
|
160086
|
-
const
|
|
160087
|
-
const bodyBytes = Buffer.byteLength(
|
|
160276
|
+
const { storage, pumlRegistry } = markdownToStorageFormat(md);
|
|
160277
|
+
const bodyBytes = Buffer.byteLength(storage, "utf8");
|
|
160088
160278
|
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
160279
|
if (warning) console.error(`[confluence_publish_doc] ${warning}`);
|
|
160280
|
+
let diagramStats = { rendered: 0, failed: 0, java_missing: false };
|
|
160281
|
+
const renderedDiagrams = /* @__PURE__ */ new Map();
|
|
160282
|
+
if (render_diagrams && pumlRegistry.size > 0) {
|
|
160283
|
+
for (const [id, source] of pumlRegistry) {
|
|
160284
|
+
try {
|
|
160285
|
+
const diag = await renderPlantUml(source, { format: diagram_format, dpi: diagram_dpi });
|
|
160286
|
+
renderedDiagrams.set(id, diag);
|
|
160287
|
+
diagramStats.rendered++;
|
|
160288
|
+
} catch (err) {
|
|
160289
|
+
diagramStats.failed++;
|
|
160290
|
+
if (/Install Java 21\+/.test(err?.message ?? "")) diagramStats.java_missing = true;
|
|
160291
|
+
console.error(`[confluence_publish_doc] plantuml render failed for ${id}: ${err?.message ?? err}`);
|
|
160292
|
+
}
|
|
160293
|
+
}
|
|
160294
|
+
}
|
|
160090
160295
|
let result;
|
|
160091
160296
|
let mode;
|
|
160297
|
+
let currentPageId;
|
|
160298
|
+
let currentVersion;
|
|
160299
|
+
let versionsUsed = 1;
|
|
160092
160300
|
if (page_id) {
|
|
160093
160301
|
mode = "update";
|
|
160094
160302
|
const current = await confluence2.getPage(page_id, ["version"]);
|
|
160095
|
-
|
|
160096
|
-
result = await confluence2.updatePage(page_id, title,
|
|
160303
|
+
currentVersion = current?.version?.number ?? 0;
|
|
160304
|
+
result = await confluence2.updatePage(page_id, title, storage, currentVersion);
|
|
160305
|
+
currentPageId = page_id;
|
|
160097
160306
|
} else {
|
|
160098
160307
|
mode = "create";
|
|
160099
|
-
result = await confluence2.createPage(space_key, title,
|
|
160308
|
+
result = await confluence2.createPage(space_key, title, storage, parent_page_id);
|
|
160309
|
+
currentPageId = result?.id;
|
|
160310
|
+
currentVersion = result?.version?.number ?? 1;
|
|
160311
|
+
}
|
|
160312
|
+
let finalStorage = storage;
|
|
160313
|
+
if (render_diagrams && renderedDiagrams.size > 0) {
|
|
160314
|
+
for (const [id, diag] of renderedDiagrams) {
|
|
160315
|
+
const filename = `diagram-${id}.${diag.format}`;
|
|
160316
|
+
try {
|
|
160317
|
+
await confluence2.addAttachment(currentPageId, filename, diag.buffer, diag.contentType);
|
|
160318
|
+
} catch (err) {
|
|
160319
|
+
console.error(`[confluence_publish_doc] attachment upload failed for ${id}: ${err?.message ?? err}`);
|
|
160320
|
+
renderedDiagrams.delete(id);
|
|
160321
|
+
diagramStats.rendered--;
|
|
160322
|
+
}
|
|
160323
|
+
}
|
|
160324
|
+
finalStorage = replacePumlMarkers(storage, renderedDiagrams, pumlRegistry);
|
|
160325
|
+
result = await confluence2.updatePage(currentPageId, title, finalStorage, currentVersion);
|
|
160326
|
+
versionsUsed = 2;
|
|
160100
160327
|
}
|
|
160101
|
-
const pageIdOut = result?.id ??
|
|
160328
|
+
const pageIdOut = result?.id ?? currentPageId;
|
|
160102
160329
|
const webui = result?._links?.webui;
|
|
160103
160330
|
const url = webui ? webui.startsWith("http") ? webui : `${confluence2.getBaseUrl()}${webui}` : void 0;
|
|
160104
160331
|
return {
|
|
@@ -160110,17 +160337,40 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160110
160337
|
title,
|
|
160111
160338
|
space_key,
|
|
160112
160339
|
version: result?.version?.number,
|
|
160340
|
+
versions_used: versionsUsed,
|
|
160113
160341
|
url,
|
|
160114
160342
|
input_chars: md.length,
|
|
160115
160343
|
input_source: markdown_file ?? "inline",
|
|
160116
|
-
body_chars:
|
|
160117
|
-
body_bytes:
|
|
160344
|
+
body_chars: finalStorage.length,
|
|
160345
|
+
body_bytes: Buffer.byteLength(finalStorage, "utf8"),
|
|
160346
|
+
diagram_stats: diagramStats,
|
|
160118
160347
|
...warning ? { warning } : {}
|
|
160119
160348
|
}, null, 2)
|
|
160120
160349
|
}]
|
|
160121
160350
|
};
|
|
160122
160351
|
});
|
|
160123
160352
|
};
|
|
160353
|
+
function replacePumlMarkers(storage, rendered, pumlRegistry) {
|
|
160354
|
+
let out = storage;
|
|
160355
|
+
for (const [id, diag] of rendered) {
|
|
160356
|
+
const filename = `diagram-${id}.${diag.format}`;
|
|
160357
|
+
const imageMacro = `<ac:image ac:alt="PlantUML Diagram ${id}"><ri:attachment ri:filename="${filename}"/></ac:image>`;
|
|
160358
|
+
out = out.replace(
|
|
160359
|
+
new RegExp(`<p data-puml-id="${id}"></p>`),
|
|
160360
|
+
imageMacro
|
|
160361
|
+
);
|
|
160362
|
+
}
|
|
160363
|
+
for (const [id, source] of pumlRegistry) {
|
|
160364
|
+
if (!rendered.has(id)) {
|
|
160365
|
+
const safeSource = source.replace(/]]>/g, "]]]]><![CDATA[>");
|
|
160366
|
+
out = out.replace(
|
|
160367
|
+
new RegExp(`<p data-puml-id="${id}"></p>`),
|
|
160368
|
+
`<ac:structured-macro ac:name="code"><ac:plain-text-body><![CDATA[${safeSource}]]></ac:plain-text-body></ac:structured-macro>`
|
|
160369
|
+
);
|
|
160370
|
+
}
|
|
160371
|
+
}
|
|
160372
|
+
return out;
|
|
160373
|
+
}
|
|
160124
160374
|
|
|
160125
160375
|
// src/config/risk-models.ts
|
|
160126
160376
|
var RISK_MODELS = {
|
|
@@ -161107,123 +161357,174 @@ var TOOL_CATALOG = [
|
|
|
161107
161357
|
category: "\uBB38\uC11C \uB9AC\uBDF0"
|
|
161108
161358
|
}
|
|
161109
161359
|
];
|
|
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
|
-
}
|
|
161360
|
+
var WORKFLOWS = [
|
|
161361
|
+
{
|
|
161362
|
+
id: "pa",
|
|
161363
|
+
title: "PA Gate \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161364
|
+
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.",
|
|
161365
|
+
steps: [
|
|
161366
|
+
"1. iec_create_gate \u2192 PA Gate + 7\uAC1C Document \uD2F0\uCF13 \uC0DD\uC131",
|
|
161367
|
+
"2. [Intended Use] Document \u2192 IU \uD2F0\uCF13 \uC0DD\uC131 (\uC0AC\uC6A9\uC790, \uD658\uACBD, \uBAA9\uC801 \uC815\uC758)",
|
|
161368
|
+
"3. [System Requirement Spec] \u2192 SyRS \uD2F0\uCF13 \uC0DD\uC131 (IU \uAE30\uBC18 \uC2DC\uC2A4\uD15C \uC694\uAD6C\uC0AC\uD56D)",
|
|
161369
|
+
"4. [Classification] \u2192 \uBD84\uB958 \uD2F0\uCF13 (MDR Class \uD310\uC815)",
|
|
161370
|
+
"5. [SW Development Plan] \u2192 \uAC1C\uBC1C \uACC4\uD68D\uC11C \uC791\uC131",
|
|
161371
|
+
"6. [Risk Management Plan] \u2192 \uB9AC\uC2A4\uD06C \uAD00\uB9AC \uACC4\uD68D\uC11C \uC791\uC131",
|
|
161372
|
+
"7. [Security Management Plan] \u2192 \uBCF4\uC548 \uAD00\uB9AC \uACC4\uD68D\uC11C (IEC 81001-5-1)",
|
|
161373
|
+
"8. [Configuration Management Plan] \u2192 \uD615\uC0C1 \uAD00\uB9AC \uACC4\uD68D\uC11C",
|
|
161374
|
+
"",
|
|
161375
|
+
"\uC0AC\uC6A9\uC131 \uACF5\uD559 (IEC 62366-1)\uB3C4 PA \uB2E8\uACC4\uC5D0\uC11C \uC2DC\uC791:",
|
|
161376
|
+
"9. usability_create_use_spec \u2192 Use Specification \uC815\uC758",
|
|
161377
|
+
"10. usability_create_scenarios \u2192 Normal/Abnormal \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4"
|
|
161378
|
+
],
|
|
161379
|
+
related: ["iec_create_gate", "usability_create_use_spec", "usability_create_scenarios"]
|
|
161380
|
+
},
|
|
161381
|
+
{
|
|
161382
|
+
id: "ea",
|
|
161383
|
+
title: "EA Gate \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161384
|
+
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.",
|
|
161385
|
+
steps: [
|
|
161386
|
+
"1. iec_create_gate \u2192 EA Gate + 8\uAC1C Document \uD2F0\uCF13 \uC0DD\uC131 (living documents)",
|
|
161387
|
+
"2. [Risk Management Report] \u2192 risk_create_hazards (FMEA) + usability_link_to_hazard",
|
|
161388
|
+
"3. [SW Requirements Spec] \u2192 FR/NFR \uC815\uB9AC + risk_create_mitigation",
|
|
161389
|
+
"4. [SW Architecture Document] \u2192 \uC544\uD0A4\uD14D\uCC98 \uACB0\uC815",
|
|
161390
|
+
"5. [SW Detailed Design Document] \u2192 \uC720\uB2DB \uC0C1\uC138\uC124\uACC4 + bottom-up Tasks",
|
|
161391
|
+
"6. [SOUP List] \u2192 doc_render(soup_list)",
|
|
161392
|
+
"7. [Usability Evaluation Plan] \u2192 usability_create_use_spec/scenarios \uC5F0\uACC4 + doc_render",
|
|
161393
|
+
"8. [Clinical Evaluation Plan] \u2192 doc_render(clinical_evaluation_plan)",
|
|
161394
|
+
"9. [List of Hazard-Related Use Scenarios] \u2192 usability_create_scenarios(abnormal) \uC5F0\uACC4",
|
|
161395
|
+
"",
|
|
161396
|
+
"EA 8\uAC1C \uBB38\uC11C = living document (IEC 62304 evolutionary \uBAA8\uB378):",
|
|
161397
|
+
" \u2022 EA: \uCD08\uAE30 \uACB0\uC815\xB7\uC2B9\uC778 / ER: \uAC1C\uBC1C\xB7\uAC80\uC99D \uC911 \uAC31\uC2E0 / CA: \uCD5C\uC885 \uD655\uC815",
|
|
161398
|
+
" \u2022 \uAC31\uC2E0 \uD2B8\uB9AC\uAC70:",
|
|
161399
|
+
" - SRS: \uC694\uAD6C\uC0AC\uD56D \uBCC0\uACBD/\uCD94\uAC00 (change-evaluation-list \uC5F0\uACC4)",
|
|
161400
|
+
" - SAD: \uC544\uD0A4\uD14D\uCC98 \uBCC0\uACBD/\uC0C1\uC138\uD654 (architecture-checklist)",
|
|
161401
|
+
" - SDD: sprint \uC720\uB2DB \uCD94\uAC00/\uC0C1\uC138\uD654",
|
|
161402
|
+
" - FMEA Risk Table: \uC0C8 \uC704\uD5D8\xB7\uD1B5\uC81C \uC2DD\uBCC4 (hazard \uCD94\uAC00)",
|
|
161403
|
+
" - SOUP List: \uC758\uC874\uC131 \uBCC0\uACBD (\u2192 CA \uCD5C\uC885 SBOM \uAE30\uBC18 \uD655\uC815)",
|
|
161404
|
+
" - Usability/Clinical Eval Plan: \uD3C9\uAC00 \uACB0\uACFC \uBC18\uC601\xB7\uACC4\uD68D \uC870\uC815",
|
|
161405
|
+
" - Hazard-Related Use Scenarios: \uC0C8 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4",
|
|
161406
|
+
"",
|
|
161407
|
+
"\uAC80\uC99D:",
|
|
161408
|
+
"10. xray_create_test \u2192 \uD14C\uC2A4\uD2B8 \uCF00\uC774\uC2A4 \uC0DD\uC131",
|
|
161409
|
+
"11. usability_create_validation \u2192 \uC0AC\uC6A9\uC131 \uAC80\uC99D",
|
|
161410
|
+
"12. doc_check_completeness \u2192 \uAE30\uC220 \uBB38\uC11C \uC644\uC804\uC131 \uAC80\uC99D",
|
|
161411
|
+
"13. doc_generate_evidence \u2192 NB \uC2EC\uC0AC\uC6A9 \uC99D\uAC70 \uD328\uD0A4\uC9C0 \uC0DD\uC131"
|
|
161412
|
+
],
|
|
161413
|
+
related: ["iec_create_gate", "risk_create_hazards", "risk_create_mitigation", "doc_render", "xray_create_test", "usability_create_validation", "doc_check_completeness", "doc_generate_evidence"]
|
|
161414
|
+
},
|
|
161415
|
+
{
|
|
161416
|
+
id: "risk",
|
|
161417
|
+
title: "\uB9AC\uC2A4\uD06C \uAD00\uB9AC \uC6CC\uD06C\uD50C\uB85C\uC6B0 (3 \uBAA8\uB378 \uBA40\uD2F0\uC785\uB825, 0.1.21+)",
|
|
161418
|
+
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.",
|
|
161419
|
+
steps: [
|
|
161420
|
+
"\uB3C4\uAD6C \uC778\uD130\uD398\uC774\uC2A4:",
|
|
161421
|
+
"- 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)",
|
|
161422
|
+
"- \uC635\uC158\uC740 name \uBB38\uC790\uC5F4 \uC785\uB825 \u2014 \uB3C4\uAD6C\uAC00 UUID \uC790\uB3D9 \uB9E4\uD551 (SoftComply RMP \uACF5\uC2DD schema)",
|
|
161423
|
+
"- lookup \uC2E4\uD328 \uC635\uC158\uC740 SKIPPED \uD45C\uC2DC, \uB098\uBA38\uC9C0 \uC815\uC0C1 \uC9C4\uD589",
|
|
161424
|
+
"",
|
|
161425
|
+
"1. risk_get_config \u2192 \uD504\uB85C\uC81D\uD2B8\uC758 3 \uBAA8\uB378 \uC815\uC758 + \uC635\uC158 name \uBAA9\uB85D \uC870\uD68C",
|
|
161426
|
+
"2. IU/SyRS \uBD84\uC11D \u2192 Hazard \uC2DD\uBCC4 (P1-P2 ISO 14971)",
|
|
161427
|
+
"3. risk_create_hazards \u2192 Hazard \uC77C\uAD04 \uC0DD\uC131 + 3 \uBAA8\uB378 risk values \uC790\uB3D9 \uC14B\uD305 + Risk Source/Relates \uB9C1\uD06C",
|
|
161428
|
+
" - 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",
|
|
161429
|
+
"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)",
|
|
161430
|
+
"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)",
|
|
161431
|
+
"6. RMP Panel\uC5D0\uC11C \uC9C1\uC811 \uC785\uB825\uD558\uB294 \uBAA8\uB378 (Risk Score Calculation / Cyber Sec Risk Model) \uC740",
|
|
161432
|
+
" 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",
|
|
161433
|
+
"7. traceability_check \u2192 \uCD94\uC801\uC131 \uD655\uC778",
|
|
161434
|
+
"8. traceability_find_missing \u2192 \uB204\uB77D \uB9C1\uD06C \uAC80\uC0C9",
|
|
161435
|
+
"9. traceability_fix \u2192 \uB204\uB77D \uB9C1\uD06C \uC790\uB3D9 \uC0DD\uC131"
|
|
161436
|
+
],
|
|
161437
|
+
related: ["risk_get_config", "risk_create_hazards", "risk_set_values", "risk_create_mitigation", "traceability_check", "traceability_find_missing", "traceability_fix"]
|
|
161438
|
+
},
|
|
161439
|
+
{
|
|
161440
|
+
id: "usability",
|
|
161441
|
+
title: "\uC0AC\uC6A9\uC131 \uACF5\uD559 (IEC 62366-1) \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161442
|
+
description: "Use Specification \u2192 Normal/Abnormal \uC2DC\uB098\uB9AC\uC624 \u2192 Hazard \uC5F0\uACB0(Risk Source) \u2192 \uAC80\uC99D \uACB0\uACFC \uAE30\uB85D.",
|
|
161443
|
+
steps: [
|
|
161444
|
+
"1. usability_create_use_spec \u2192 Use Specification \uC815\uC758",
|
|
161445
|
+
" (\uC0AC\uC6A9\uC790 \uD504\uB85C\uD30C\uC77C, \uC0AC\uC6A9 \uD658\uACBD, \uC758\uB3C4\uB41C \uC0AC\uC6A9)",
|
|
161446
|
+
"2. usability_create_scenarios \u2192 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 \uC2DD\uBCC4",
|
|
161447
|
+
" - Normal Use: \uC815\uC0C1 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624",
|
|
161448
|
+
" - Abnormal Use: \uBE44\uC815\uC0C1 \uC0AC\uC6A9 \uC2DC\uB098\uB9AC\uC624 (Hazard \uC6D0\uCC9C)",
|
|
161449
|
+
"3. usability_link_to_hazard \u2192 \uC2DC\uB098\uB9AC\uC624 \u2192 Hazard \uC5F0\uACB0",
|
|
161450
|
+
" (Risk Source \uB9C1\uD06C\uB85C \uC790\uB3D9 \uC5F0\uACB0)",
|
|
161451
|
+
"4. usability_create_validation \u2192 \uC0AC\uC6A9\uC131 \uAC80\uC99D \uACB0\uACFC \uAE30\uB85D",
|
|
161452
|
+
" (\uAC80\uC99D \uBC29\uBC95, \uACB0\uACFC, \uC99D\uBE59)"
|
|
161453
|
+
],
|
|
161454
|
+
related: ["usability_create_use_spec", "usability_create_scenarios", "usability_link_to_hazard", "usability_create_validation"]
|
|
161455
|
+
},
|
|
161456
|
+
{
|
|
161457
|
+
id: "mdr",
|
|
161458
|
+
title: "MDR \uAE30\uC220 \uBB38\uC11C (Annex II) \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161459
|
+
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.",
|
|
161460
|
+
steps: [
|
|
161461
|
+
"1. doc_create_from_template \u2192 Annex II \uAD6C\uC870\uB85C \uBB38\uC11C \uD2F0\uCF13 \uC0DD\uC131",
|
|
161462
|
+
"2. \uAC01 \uC139\uC158\uBCC4 \uB0B4\uC6A9 \uC791\uC131",
|
|
161463
|
+
"3. doc_check_completeness \u2192 \uB204\uB77D/\uBBF8\uC2B9\uC778 \uD56D\uBAA9 \uAC80\uC0AC",
|
|
161464
|
+
"4. doc_generate_evidence \u2192 \uC99D\uAC70 \uD328\uD0A4\uC9C0 \uC0DD\uC131",
|
|
161465
|
+
" - \uCD94\uC801\uC131 \uB9E4\uD2B8\uB9AD\uC2A4 (IU \u2192 SyRS \u2192 Req \u2192 DD \u2192 Task \u2192 Test)",
|
|
161466
|
+
" - \uB9AC\uC2A4\uD06C \uB9E4\uD2B8\uB9AD\uC2A4 (Hazard \xD7 Severity \xD7 P1/P2)",
|
|
161467
|
+
" - V&V \uC694\uC57D (\uD14C\uC2A4\uD2B8 \uD1B5\uACFC\uC728)"
|
|
161468
|
+
],
|
|
161469
|
+
related: ["doc_create_from_template", "doc_check_completeness", "doc_generate_evidence"]
|
|
161470
|
+
},
|
|
161471
|
+
{
|
|
161472
|
+
id: "customfield",
|
|
161473
|
+
title: "customfield / \uBB38\uC11C \uD544\uB4DC \uCC44\uC6B0\uAE30 \uC6CC\uD06C\uD50C\uB85C\uC6B0",
|
|
161474
|
+
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.',
|
|
161475
|
+
steps: [
|
|
161476
|
+
"\uC8FC\uC758: customfield \uC911 \uC77C\uBD80\uB294 rich text(ADF)\uB97C \uC694\uAD6C\uD558\uC9C0\uB9CC, createmeta\uAC00 string\uC73C\uB85C",
|
|
161477
|
+
'\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.',
|
|
161478
|
+
"",
|
|
161479
|
+
"1. jira_get_issue_type_schema \u2192 \uC774\uC288\uD0C0\uC785 \uD544\uB4DC \uAD6C\uC870 + inferredFormat \uD655\uC778",
|
|
161480
|
+
" inferredFormat \uAC12: adf(\uD655\uC815) / adf-suspect(string\uC774\uB098 textarea, \uC758\uC2EC) /",
|
|
161481
|
+
" option / string / number / date ...",
|
|
161482
|
+
"2. ADF \uD544\uB4DC(customfield_*) \uC2DD\uBCC4 \u2014 inferredFormat\uC774 adf \uB610\uB294 adf-suspect\uC778 \uD544\uB4DC",
|
|
161483
|
+
"3. jira_create_issue / jira_update_issue \uD638\uCD9C \uC2DC:",
|
|
161484
|
+
" - \uC790\uB3D9 \uAC10\uC9C0: auto_detect_rich_text: true (schema\uC5D0\uC11C ADF \uD544\uB4DC \uC790\uB3D9 \uCD94\uC815)",
|
|
161485
|
+
' - \uBA85\uC2DC \uC9C0\uC815: rich_text_custom_fields: ["customfield_xxxx", ...] (\uCD5C\uC885 \uBCF4\uC218)',
|
|
161486
|
+
" - \uD3C9\uBB38\uC744 \uB118\uAE30\uBA74 \uC790\uB3D9\uC73C\uB85C ADF\uB85C \uBCC0\uD658\uB428 (\uC774\uBBF8 ADF \uAC1D\uCCB4\uBA74 \uADF8\uB300\uB85C)",
|
|
161487
|
+
'4. option \uD544\uB4DC(\uC608: Phase)\uB294 { value: "PA" } \uD615\uD0DC\uB85C extra_fields/fields\uC5D0 \uC804\uB2EC',
|
|
161488
|
+
"",
|
|
161489
|
+
"\uD45C\uC900 \uC6D0\uCE59: \uBB38\uC11C \uD2F0\uCF13\uC744 \uB9CC\uB4E4 \uB54C\uB294 \uBC18\uB4DC\uC2DC schema\uB97C \uBA3C\uC800 \uBCF4\uACE0,",
|
|
161490
|
+
"customfield\uB97C \uADF8 \uAD6C\uC870\uC5D0 \uB9DE\uCDB0 \uCC44\uC6B4\uB2E4 \u2014 \uBE48 \uD2F0\uCF13\uC744 \uBC29\uCE58\uD558\uC9C0 \uC54A\uB294\uB2E4."
|
|
161491
|
+
],
|
|
161492
|
+
related: ["jira_get_issue_type_schema", "jira_create_issue", "jira_update_issue"]
|
|
161493
|
+
},
|
|
161494
|
+
{
|
|
161495
|
+
id: "diagram",
|
|
161496
|
+
title: "PlantUML \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uB80C\uB354\uB9C1",
|
|
161497
|
+
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).",
|
|
161498
|
+
steps: [
|
|
161499
|
+
"1. Java 21+ \uC124\uCE58 \uD655\uC778: java -version (\uC5C6\uC73C\uBA74 https://adoptium.net/)",
|
|
161500
|
+
"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.",
|
|
161501
|
+
"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.",
|
|
161502
|
+
"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.",
|
|
161503
|
+
"5. \uC635\uD2B8\uC544\uC6C3: render_diagrams: false \uB610\uB294 render_plantuml: false. \uBD80\uBD84 disable \uAC00\uB2A5.",
|
|
161504
|
+
"6. \uACB0\uACFC JSON\uC758 diagram_stats (rendered/failed/java_missing) \uD544\uB4DC\uB85C \uB80C\uB354 \uACB0\uACFC \uD655\uC778."
|
|
161505
|
+
],
|
|
161506
|
+
related: ["confluence_publish_doc", "markdown_to_pdf", "jira_attach_pdf_from_markdown"]
|
|
161507
|
+
}
|
|
161508
|
+
];
|
|
161509
|
+
function workflowToText(w2) {
|
|
161510
|
+
const lines = [];
|
|
161511
|
+
lines.push(`=== ${w2.title} ===`);
|
|
161512
|
+
lines.push("");
|
|
161513
|
+
if (w2.description) {
|
|
161514
|
+
lines.push(w2.description);
|
|
161515
|
+
lines.push("");
|
|
161516
|
+
}
|
|
161517
|
+
for (const step of w2.steps) {
|
|
161518
|
+
lines.push(step);
|
|
161519
|
+
}
|
|
161520
|
+
return lines.join("\n");
|
|
161521
|
+
}
|
|
161221
161522
|
|
|
161222
161523
|
// src/tools/help.ts
|
|
161223
161524
|
var registerHelpTools = ({ server: server2 }) => {
|
|
161224
161525
|
server2.tool("help", "Show available tools, workflows, and usage guides. Call without arguments for full catalog, or specify a topic.", {
|
|
161225
161526
|
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")'
|
|
161527
|
+
'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
161528
|
)
|
|
161228
161529
|
}, async ({ topic }) => {
|
|
161229
161530
|
if (!topic) {
|
|
@@ -161236,19 +161537,21 @@ var registerHelpTools = ({ server: server2 }) => {
|
|
|
161236
161537
|
}
|
|
161237
161538
|
lines.push("");
|
|
161238
161539
|
}
|
|
161239
|
-
|
|
161540
|
+
const wfIds2 = WORKFLOWS.map((w2) => w2.id).join(", ");
|
|
161541
|
+
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
161542
|
lines.push('\uD2B9\uC815 \uD234 \uC0C1\uC138: help(topic="\uD234\uC774\uB984")');
|
|
161241
161543
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
161242
161544
|
}
|
|
161243
|
-
|
|
161244
|
-
|
|
161545
|
+
const workflow = WORKFLOWS.find((w2) => w2.id === topic);
|
|
161546
|
+
if (workflow) {
|
|
161547
|
+
return { content: [{ type: "text", text: workflowToText(workflow) }] };
|
|
161245
161548
|
}
|
|
161246
161549
|
if (topic === "tools") {
|
|
161247
161550
|
const lines = TOOL_CATALOG.map((t2) => `${t2.name} [${t2.category}]: ${t2.description}`);
|
|
161248
161551
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
161249
161552
|
}
|
|
161250
161553
|
if (topic === "workflows") {
|
|
161251
|
-
const lines =
|
|
161554
|
+
const lines = WORKFLOWS.map(workflowToText).join("\n\n");
|
|
161252
161555
|
return { content: [{ type: "text", text: lines }] };
|
|
161253
161556
|
}
|
|
161254
161557
|
const tool = TOOL_CATALOG.find((t2) => t2.name === topic);
|
|
@@ -161258,8 +161561,9 @@ ${tool.description}
|
|
|
161258
161561
|
|
|
161259
161562
|
\uC790\uC138\uD55C \uD30C\uB77C\uBBF8\uD130\uB294 \uC774 \uD234\uC744 \uC9C1\uC811 \uD638\uCD9C\uD558\uC5EC \uD655\uC778\uD558\uC138\uC694.` }] };
|
|
161260
161563
|
}
|
|
161564
|
+
const wfIds = WORKFLOWS.map((w2) => w2.id).join(", ");
|
|
161261
161565
|
return { content: [{ type: "text", text: `\uC54C \uC218 \uC5C6\uB294 \uD1A0\uD53D: "${topic}"
|
|
161262
|
-
\uC0AC\uC6A9 \uAC00\uB2A5: tools, workflows,
|
|
161566
|
+
\uC0AC\uC6A9 \uAC00\uB2A5: tools, workflows, ${wfIds}, \uB610\uB294 \uD234 \uC774\uB984` }] };
|
|
161263
161567
|
});
|
|
161264
161568
|
};
|
|
161265
161569
|
|
|
@@ -161747,8 +162051,8 @@ var registerDocValidationTools = (ctx2) => {
|
|
|
161747
162051
|
};
|
|
161748
162052
|
|
|
161749
162053
|
// src/tools/init.ts
|
|
161750
|
-
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "fs";
|
|
161751
|
-
import { join as
|
|
162054
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
|
|
162055
|
+
import { join as join3 } from "path";
|
|
161752
162056
|
var registerInitTools = ({ server: server2 }) => {
|
|
161753
162057
|
server2.tool(
|
|
161754
162058
|
"jira_init_project",
|
|
@@ -161758,11 +162062,11 @@ var registerInitTools = ({ server: server2 }) => {
|
|
|
161758
162062
|
},
|
|
161759
162063
|
async ({ project_key }) => {
|
|
161760
162064
|
const cwd = process.cwd();
|
|
161761
|
-
const claudeMdPath =
|
|
162065
|
+
const claudeMdPath = join3(cwd, "CLAUDE.md");
|
|
161762
162066
|
const line = `\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 Jira key\uB294 ${project_key}\uC785\uB2C8\uB2E4.`;
|
|
161763
162067
|
try {
|
|
161764
162068
|
let content = "";
|
|
161765
|
-
if (
|
|
162069
|
+
if (existsSync2(claudeMdPath)) {
|
|
161766
162070
|
content = readFileSync2(claudeMdPath, "utf-8");
|
|
161767
162071
|
if (content.includes(line)) {
|
|
161768
162072
|
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 +162093,7 @@ var registerInitTools = ({ server: server2 }) => {
|
|
|
161789
162093
|
|
|
161790
162094
|
// src/tools/doc-render.ts
|
|
161791
162095
|
import { readFileSync as readFileSync3 } from "fs";
|
|
161792
|
-
import { fileURLToPath } from "url";
|
|
162096
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
161793
162097
|
import path from "path";
|
|
161794
162098
|
|
|
161795
162099
|
// src/utils/doc-render.ts
|
|
@@ -161854,7 +162158,7 @@ var TEMPLATE_VERSION = "17d0c4e";
|
|
|
161854
162158
|
|
|
161855
162159
|
// src/tools/doc-render.ts
|
|
161856
162160
|
init_adf();
|
|
161857
|
-
var __dirname2 = path.dirname(
|
|
162161
|
+
var __dirname2 = path.dirname(fileURLToPath2(import.meta.url));
|
|
161858
162162
|
var TEMPLATE_DIR = path.resolve(__dirname2, "../vendor/dev-docs-templates/templates");
|
|
161859
162163
|
var registerDocRenderTools = (ctx2) => {
|
|
161860
162164
|
const { server: server2, jira: jira2 } = ctx2;
|
|
@@ -161949,7 +162253,7 @@ import { execFileSync } from "child_process";
|
|
|
161949
162253
|
// src/utils/markdownToPdf.ts
|
|
161950
162254
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
161951
162255
|
import { tmpdir } from "os";
|
|
161952
|
-
import { join as
|
|
162256
|
+
import { join as join5 } from "path";
|
|
161953
162257
|
import { randomUUID } from "crypto";
|
|
161954
162258
|
|
|
161955
162259
|
// node_modules/pdfkit/js/pdfkit.es.js
|
|
@@ -163841,12 +164145,12 @@ function $e71565f2ce09cb6b$export$69a3209f1a06c04d(target, key, descriptor) {
|
|
|
163841
164145
|
let fn = descriptor.value;
|
|
163842
164146
|
return {
|
|
163843
164147
|
get() {
|
|
163844
|
-
let
|
|
164148
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
163845
164149
|
function memoized(...args) {
|
|
163846
164150
|
let key2 = args.length > 0 ? args[0] : "value";
|
|
163847
|
-
if (
|
|
164151
|
+
if (cache2.has(key2)) return cache2.get(key2);
|
|
163848
164152
|
let result = fn.apply(this, args);
|
|
163849
|
-
|
|
164153
|
+
cache2.set(key2, result);
|
|
163850
164154
|
return result;
|
|
163851
164155
|
}
|
|
163852
164156
|
Object.defineProperty(this, key, {
|
|
@@ -170517,8 +170821,8 @@ var $55f71433a605c87d$export$2e2bcd8739ae039 = class {
|
|
|
170517
170821
|
}
|
|
170518
170822
|
if (count === 1) {
|
|
170519
170823
|
let result = input.map((g3) => g3.id);
|
|
170520
|
-
let
|
|
170521
|
-
if (
|
|
170824
|
+
let cache2 = this.inputCache[found];
|
|
170825
|
+
if (cache2) cache2.push(result);
|
|
170522
170826
|
else this.inputCache[found] = [
|
|
170523
170827
|
result
|
|
170524
170828
|
];
|
|
@@ -182989,14 +183293,14 @@ var SubsetMixin = {
|
|
|
182989
183293
|
var ROW_FIELDS = ["height", "minHeight", "maxHeight"];
|
|
182990
183294
|
var COLUMN_FIELDS = ["width", "minWidth", "maxWidth"];
|
|
182991
183295
|
function memoize(fn, maxSize) {
|
|
182992
|
-
const
|
|
183296
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
182993
183297
|
return function(...args) {
|
|
182994
183298
|
const key = args[0];
|
|
182995
|
-
if (!
|
|
182996
|
-
|
|
182997
|
-
if (
|
|
183299
|
+
if (!cache2.has(key)) {
|
|
183300
|
+
cache2.set(key, fn(...args));
|
|
183301
|
+
if (cache2.size > maxSize) cache2.delete(cache2.keys().next());
|
|
182998
183302
|
}
|
|
182999
|
-
return
|
|
183303
|
+
return cache2.get(key);
|
|
183000
183304
|
};
|
|
183001
183305
|
}
|
|
183002
183306
|
function isObject2(item) {
|
|
@@ -184000,23 +184304,23 @@ PDFDocument.LineWrapper = LineWrapper;
|
|
|
184000
184304
|
init_marked_esm();
|
|
184001
184305
|
|
|
184002
184306
|
// src/utils/pdf-fonts.ts
|
|
184003
|
-
import { existsSync as
|
|
184004
|
-
import { join as
|
|
184005
|
-
import { fileURLToPath as
|
|
184307
|
+
import { existsSync as existsSync3 } from "fs";
|
|
184308
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
184309
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
184006
184310
|
var BUNDLED_FONT_FAMILY = "BodyFont";
|
|
184007
184311
|
var BUNDLED_FONT_FAMILY_BOLD = "BodyFont-Bold";
|
|
184008
184312
|
var DEFAULT_FAMILY = "BodyFont";
|
|
184009
184313
|
function bundledFontPaths() {
|
|
184010
|
-
const here = typeof __dirname !== "undefined" ? __dirname :
|
|
184011
|
-
const rootFromSrc =
|
|
184012
|
-
const candidates = [
|
|
184314
|
+
const here = typeof __dirname !== "undefined" ? __dirname : dirname2(fileURLToPath3(import.meta.url));
|
|
184315
|
+
const rootFromSrc = join4(here, "..", "..");
|
|
184316
|
+
const candidates = [join4(here, "fonts"), join4(rootFromSrc, "dist", "fonts")];
|
|
184013
184317
|
const fontsDir = candidates.find(
|
|
184014
|
-
(d2) =>
|
|
184318
|
+
(d2) => existsSync3(join4(d2, "Pretendard-Regular.ttf")) && existsSync3(join4(d2, "Pretendard-Bold.ttf"))
|
|
184015
184319
|
);
|
|
184016
184320
|
const dir = fontsDir || candidates[0];
|
|
184017
184321
|
return {
|
|
184018
|
-
regular:
|
|
184019
|
-
bold:
|
|
184322
|
+
regular: join4(dir, "Pretendard-Regular.ttf"),
|
|
184323
|
+
bold: join4(dir, "Pretendard-Bold.ttf")
|
|
184020
184324
|
};
|
|
184021
184325
|
}
|
|
184022
184326
|
function resolveFonts(opts) {
|
|
@@ -184029,7 +184333,7 @@ function resolveFonts(opts) {
|
|
|
184029
184333
|
};
|
|
184030
184334
|
}
|
|
184031
184335
|
const paths = bundledFontPaths();
|
|
184032
|
-
if (
|
|
184336
|
+
if (existsSync3(paths.regular) && existsSync3(paths.bold)) {
|
|
184033
184337
|
return {
|
|
184034
184338
|
regularFamily: BUNDLED_FONT_FAMILY,
|
|
184035
184339
|
boldFamily: BUNDLED_FONT_FAMILY_BOLD,
|
|
@@ -184051,6 +184355,21 @@ var FRONTMATTER_RE2 = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
|
|
|
184051
184355
|
function stripFrontmatter2(md) {
|
|
184052
184356
|
return md.replace(FRONTMATTER_RE2, "");
|
|
184053
184357
|
}
|
|
184358
|
+
function lexAndExtractPlantUml(body) {
|
|
184359
|
+
const tokens = g.lexer(stripFrontmatter2(body ?? ""));
|
|
184360
|
+
const pumlRegistry = /* @__PURE__ */ new Map();
|
|
184361
|
+
let counter = 0;
|
|
184362
|
+
for (const tok of tokens) {
|
|
184363
|
+
if (tok?.type !== "code") continue;
|
|
184364
|
+
const lang = String(tok.lang ?? "").trim().toLowerCase();
|
|
184365
|
+
if (lang === "plantuml" || lang === "puml" || lang === "plantuml-markdown") {
|
|
184366
|
+
const id = `PUML_${counter++}`;
|
|
184367
|
+
pumlRegistry.set(id, String(tok.text ?? ""));
|
|
184368
|
+
tok._pumlId = id;
|
|
184369
|
+
}
|
|
184370
|
+
}
|
|
184371
|
+
return { tokens, pumlRegistry };
|
|
184372
|
+
}
|
|
184054
184373
|
var PAGE_SIZE_DEFAULT = "A4";
|
|
184055
184374
|
var MARGIN_DEFAULT = 56;
|
|
184056
184375
|
async function markdownToPdf(md, opts = {}) {
|
|
@@ -184064,7 +184383,9 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184064
184383
|
pageSize = PAGE_SIZE_DEFAULT,
|
|
184065
184384
|
margin = {},
|
|
184066
184385
|
language = "en",
|
|
184067
|
-
collectWarnings = false
|
|
184386
|
+
collectWarnings = false,
|
|
184387
|
+
renderPlantUml: renderPUML = true,
|
|
184388
|
+
diagramDpi = 96
|
|
184068
184389
|
} = opts;
|
|
184069
184390
|
const top = margin.top ?? MARGIN_DEFAULT;
|
|
184070
184391
|
const bottom = margin.bottom ?? MARGIN_DEFAULT;
|
|
@@ -184121,10 +184442,22 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184121
184442
|
doc.fillColor("#000");
|
|
184122
184443
|
doc.addPage();
|
|
184123
184444
|
}
|
|
184124
|
-
const
|
|
184125
|
-
const
|
|
184445
|
+
const { tokens, pumlRegistry } = lexAndExtractPlantUml(md ?? "");
|
|
184446
|
+
const pumlImages = /* @__PURE__ */ new Map();
|
|
184447
|
+
if (renderPUML && pumlRegistry.size > 0) {
|
|
184448
|
+
await Promise.all(
|
|
184449
|
+
[...pumlRegistry].map(async ([id, source]) => {
|
|
184450
|
+
try {
|
|
184451
|
+
const diag = await renderPlantUml(source, { format: "png", dpi: diagramDpi });
|
|
184452
|
+
pumlImages.set(id, diag.buffer);
|
|
184453
|
+
} catch (err) {
|
|
184454
|
+
console.error(`[markdownToPdf] plantuml render failed for ${id}: ${err?.message ?? err}`);
|
|
184455
|
+
}
|
|
184456
|
+
})
|
|
184457
|
+
);
|
|
184458
|
+
}
|
|
184126
184459
|
for (const tok of tokens) {
|
|
184127
|
-
renderToken(doc, tok, fonts);
|
|
184460
|
+
renderToken(doc, tok, fonts, pumlImages);
|
|
184128
184461
|
}
|
|
184129
184462
|
if (tokens.length === 0) {
|
|
184130
184463
|
doc.fontSize(11).fillColor("#000").text("");
|
|
@@ -184177,9 +184510,9 @@ async function markdownToPdf(md, opts = {}) {
|
|
|
184177
184510
|
doc.restore();
|
|
184178
184511
|
}
|
|
184179
184512
|
const chunks = [];
|
|
184180
|
-
const ended = new Promise((
|
|
184513
|
+
const ended = new Promise((resolve2, reject) => {
|
|
184181
184514
|
doc.on("data", (c) => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c)));
|
|
184182
|
-
doc.on("end", () =>
|
|
184515
|
+
doc.on("end", () => resolve2());
|
|
184183
184516
|
doc.on("error", (err) => reject(err));
|
|
184184
184517
|
});
|
|
184185
184518
|
doc.end();
|
|
@@ -184220,7 +184553,7 @@ function lineHeightOf(doc) {
|
|
|
184220
184553
|
const size = doc._fontSize ?? 11;
|
|
184221
184554
|
return size * 1.2;
|
|
184222
184555
|
}
|
|
184223
|
-
function renderToken(doc, tok, fonts) {
|
|
184556
|
+
function renderToken(doc, tok, fonts, pumlImages) {
|
|
184224
184557
|
if (!tok || typeof tok !== "object") return;
|
|
184225
184558
|
switch (tok.type) {
|
|
184226
184559
|
case "heading":
|
|
@@ -184230,13 +184563,24 @@ function renderToken(doc, tok, fonts) {
|
|
|
184230
184563
|
renderParagraph(doc, tok, fonts);
|
|
184231
184564
|
return;
|
|
184232
184565
|
case "code":
|
|
184566
|
+
if (tok._pumlId) {
|
|
184567
|
+
const buf = pumlImages.get(tok._pumlId);
|
|
184568
|
+
if (buf) {
|
|
184569
|
+
try {
|
|
184570
|
+
renderPlantUmlImage(doc, buf);
|
|
184571
|
+
return;
|
|
184572
|
+
} catch (err) {
|
|
184573
|
+
console.error(`[markdownToPdf] image() failed for ${tok._pumlId}: ${err?.message ?? err}`);
|
|
184574
|
+
}
|
|
184575
|
+
}
|
|
184576
|
+
}
|
|
184233
184577
|
renderCodeBlock(doc, tok);
|
|
184234
184578
|
return;
|
|
184235
184579
|
case "blockquote":
|
|
184236
184580
|
renderBlockquote(doc, tok, fonts);
|
|
184237
184581
|
return;
|
|
184238
184582
|
case "list":
|
|
184239
|
-
renderList(doc, tok, fonts, 0);
|
|
184583
|
+
renderList(doc, tok, fonts, 0, pumlImages);
|
|
184240
184584
|
return;
|
|
184241
184585
|
case "table":
|
|
184242
184586
|
renderTable(doc, tok, fonts);
|
|
@@ -184253,6 +184597,13 @@ function renderToken(doc, tok, fonts) {
|
|
|
184253
184597
|
}
|
|
184254
184598
|
}
|
|
184255
184599
|
}
|
|
184600
|
+
function renderPlantUmlImage(doc, buf) {
|
|
184601
|
+
const marginL = doc.page.margins.left;
|
|
184602
|
+
const marginR = doc.page.margins.right;
|
|
184603
|
+
const availableWidth = doc.page.width - marginL - marginR;
|
|
184604
|
+
doc.y += SPACE2.CODE_BEFORE;
|
|
184605
|
+
doc.image(buf, { fit: [availableWidth, 200], align: "center" });
|
|
184606
|
+
}
|
|
184256
184607
|
function renderHeading(doc, tok, fonts) {
|
|
184257
184608
|
const level = Math.min(Math.max(Number(tok.depth) || 1, 1), 6);
|
|
184258
184609
|
const size = HEADING_SIZES[level - 1];
|
|
@@ -184369,7 +184720,7 @@ function extractInlineText(node) {
|
|
|
184369
184720
|
if (Array.isArray(node.tokens)) return node.tokens.map(extractInlineText).join("");
|
|
184370
184721
|
return "";
|
|
184371
184722
|
}
|
|
184372
|
-
function renderList(doc, tok, fonts, depth) {
|
|
184723
|
+
function renderList(doc, tok, fonts, depth, pumlImages) {
|
|
184373
184724
|
const items = tok.items ?? [];
|
|
184374
184725
|
const ordered = !!tok.ordered;
|
|
184375
184726
|
const marginL = doc.page.margins.left;
|
|
@@ -184409,9 +184760,9 @@ function renderList(doc, tok, fonts, depth) {
|
|
|
184409
184760
|
} else if (sub?.type === "list") {
|
|
184410
184761
|
doc.x = marginL + indent + 12;
|
|
184411
184762
|
doc.y = doc.y + SPACE2.LIST_ITEM_BEFORE;
|
|
184412
|
-
renderList(doc, sub, fonts, depth + 1);
|
|
184763
|
+
renderList(doc, sub, fonts, depth + 1, pumlImages);
|
|
184413
184764
|
} else {
|
|
184414
|
-
renderToken(doc, sub, fonts);
|
|
184765
|
+
renderToken(doc, sub, fonts, pumlImages);
|
|
184415
184766
|
}
|
|
184416
184767
|
}
|
|
184417
184768
|
if (!drewAnything && item.text) {
|
|
@@ -184512,7 +184863,7 @@ function renderHr(doc) {
|
|
|
184512
184863
|
doc.y = y2 + SPACE2.HR_AFTER;
|
|
184513
184864
|
}
|
|
184514
184865
|
function writePdfToTempFile(buffer) {
|
|
184515
|
-
const path3 =
|
|
184866
|
+
const path3 = join5(tmpdir(), `${randomUUID()}.pdf`);
|
|
184516
184867
|
writeFileSync3(path3, buffer);
|
|
184517
184868
|
return path3;
|
|
184518
184869
|
}
|
|
@@ -184564,9 +184915,11 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184564
184915
|
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
184916
|
font_family_name: external_exports.string().optional().describe('pdfkit registerFont \uC774\uB984 (\uAE30\uBCF8 "BodyFont")'),
|
|
184566
184917
|
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)")
|
|
184918
|
+
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)"),
|
|
184919
|
+
render_plantuml: external_exports.boolean().optional().default(true).describe("Render ```plantuml fences to PNG and embed in PDF. Default true."),
|
|
184920
|
+
diagram_dpi: external_exports.number().optional().default(96).describe("PlantUML rendering DPI. Default 96.")
|
|
184568
184921
|
},
|
|
184569
|
-
async ({ markdown, markdown_file, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode }) => {
|
|
184922
|
+
async ({ markdown, markdown_file, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode, render_plantuml, diagram_dpi }) => {
|
|
184570
184923
|
if (!markdown && !markdown_file) {
|
|
184571
184924
|
throw new Error("Either markdown or markdown_file must be provided");
|
|
184572
184925
|
}
|
|
@@ -184591,6 +184944,8 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184591
184944
|
...font_path !== void 0 ? { fontPath: font_path } : {},
|
|
184592
184945
|
...font_family_name !== void 0 ? { fontFamilyName: font_family_name } : {},
|
|
184593
184946
|
pageSize: page_size,
|
|
184947
|
+
renderPlantUml: render_plantuml,
|
|
184948
|
+
diagramDpi: diagram_dpi,
|
|
184594
184949
|
collectWarnings: true
|
|
184595
184950
|
});
|
|
184596
184951
|
const buffer = result.buffer;
|
|
@@ -184685,7 +185040,9 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184685
185040
|
author: external_exports.string().optional().describe("PDF /Author \uBA54\uD0C0"),
|
|
184686
185041
|
font_path: external_exports.string().optional().describe("\uD3F0\uD2B8 \uD30C\uC77C \uC808\uB300 \uACBD\uB85C"),
|
|
184687
185042
|
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")
|
|
185043
|
+
page_size: external_exports.enum(["A4", "LETTER", "LEGAL"]).optional().default("A4").describe("\uD398\uC774\uC9C0 \uD06C\uAE30"),
|
|
185044
|
+
render_plantuml: external_exports.boolean().optional().default(true).describe("Render ```plantuml fences to PNG and embed in PDF. Default true."),
|
|
185045
|
+
diagram_dpi: external_exports.number().optional().default(96).describe("PlantUML rendering DPI. Default 96.")
|
|
184689
185046
|
},
|
|
184690
185047
|
async ({
|
|
184691
185048
|
issue_key,
|
|
@@ -184699,7 +185056,9 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184699
185056
|
author,
|
|
184700
185057
|
font_path,
|
|
184701
185058
|
font_family_name,
|
|
184702
|
-
page_size
|
|
185059
|
+
page_size,
|
|
185060
|
+
render_plantuml,
|
|
185061
|
+
diagram_dpi
|
|
184703
185062
|
}) => {
|
|
184704
185063
|
if (!markdown && !markdown_file) {
|
|
184705
185064
|
throw new Error("Either markdown or markdown_file must be provided");
|
|
@@ -184725,6 +185084,8 @@ var registerJiraAttachTools = (ctx2) => {
|
|
|
184725
185084
|
...font_path !== void 0 ? { fontPath: font_path } : {},
|
|
184726
185085
|
...font_family_name !== void 0 ? { fontFamilyName: font_family_name } : {},
|
|
184727
185086
|
pageSize: page_size,
|
|
185087
|
+
renderPlantUml: render_plantuml,
|
|
185088
|
+
diagramDpi: diagram_dpi,
|
|
184728
185089
|
collectWarnings: true
|
|
184729
185090
|
});
|
|
184730
185091
|
const buffer = result.buffer;
|
|
@@ -185121,9 +185482,9 @@ var registerExpertTools = (ctx2) => {
|
|
|
185121
185482
|
|
|
185122
185483
|
// src/tools/review-criteria.ts
|
|
185123
185484
|
import { readFileSync as readFileSync5 } from "fs";
|
|
185124
|
-
import { fileURLToPath as
|
|
185485
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
185125
185486
|
import path2 from "path";
|
|
185126
|
-
var __dirname3 = path2.dirname(
|
|
185487
|
+
var __dirname3 = path2.dirname(fileURLToPath4(import.meta.url));
|
|
185127
185488
|
var CRITERIA_PATH = path2.resolve(__dirname3, "../data/review-criteria.md");
|
|
185128
185489
|
var registerReviewCriteriaTools = (ctx2) => {
|
|
185129
185490
|
ctx2.server.tool(
|
|
@@ -185170,7 +185531,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
|
|
|
185170
185531
|
var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
|
|
185171
185532
|
var server = new McpServer({
|
|
185172
185533
|
name: "jira-confluence",
|
|
185173
|
-
version: "0.1.
|
|
185534
|
+
version: "0.1.28"
|
|
185174
185535
|
});
|
|
185175
185536
|
var ctx = { server, jira, confluence, risk, xray };
|
|
185176
185537
|
registerJiraCrudTools(ctx);
|