@neobiotechlabs/neobiotech-dev-agent 0.1.15 → 0.1.17

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/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
+ import { fileURLToPath as __f2p } from "node:url";
4
+ import { dirname as __dn } from "node:path";
3
5
  const require = createRequire(import.meta.url);
6
+ const __filename = __f2p(import.meta.url);
7
+ const __dirname = __dn(__filename);
4
8
  var __create = Object.create;
5
9
  var __defProp = Object.defineProperty;
6
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -3236,8 +3240,8 @@ var require_utils = __commonJS({
3236
3240
  }
3237
3241
  return ind;
3238
3242
  }
3239
- function removeDotSegments(path2) {
3240
- let input = path2;
3243
+ function removeDotSegments(path3) {
3244
+ let input = path3;
3241
3245
  const output = [];
3242
3246
  let nextSlash = -1;
3243
3247
  let len = 0;
@@ -3489,8 +3493,8 @@ var require_schemes = __commonJS({
3489
3493
  wsComponent.secure = void 0;
3490
3494
  }
3491
3495
  if (wsComponent.resourceName) {
3492
- const [path2, query] = wsComponent.resourceName.split("?");
3493
- wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3496
+ const [path3, query] = wsComponent.resourceName.split("?");
3497
+ wsComponent.path = path3 && path3 !== "/" ? path3 : void 0;
3494
3498
  wsComponent.query = query;
3495
3499
  wsComponent.resourceName = void 0;
3496
3500
  }
@@ -3776,6 +3780,7 @@ var require_fast_uri = __commonJS({
3776
3780
  return uriTokens.join("");
3777
3781
  }
3778
3782
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
3783
+ var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
3779
3784
  function getParseError(parsed, matches) {
3780
3785
  if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
3781
3786
  return 'URI path must start with "/" when authority is present.';
@@ -3805,6 +3810,11 @@ var require_fast_uri = __commonJS({
3805
3810
  uri = "//" + uri;
3806
3811
  }
3807
3812
  }
3813
+ const authorityMatch = uri.match(AUTHORITY_PREFIX);
3814
+ if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
3815
+ parsed.error = "URI authority must not contain a literal backslash.";
3816
+ malformedAuthorityOrPort = true;
3817
+ }
3808
3818
  const matches = uri.match(URI_PARSE);
3809
3819
  if (matches) {
3810
3820
  parsed.scheme = matches[1];
@@ -14950,8 +14960,8 @@ var init_jira_client = __esm({
14950
14960
  "Authorization": this.authHeader
14951
14961
  };
14952
14962
  }
14953
- async request(path2, options = {}) {
14954
- const resp = await fetch(`${this.baseUrl}/rest/api/3${path2}`, {
14963
+ async request(path3, options = {}) {
14964
+ const resp = await fetch(`${this.baseUrl}/rest/api/3${path3}`, {
14955
14965
  method: options.method || "GET",
14956
14966
  headers: this.headers(),
14957
14967
  body: options.body ? JSON.stringify(options.body) : void 0
@@ -15441,25 +15451,25 @@ var require_utils2 = __commonJS({
15441
15451
  }
15442
15452
  mkdirSync2(folder);
15443
15453
  };
15444
- Utils.prototype.writeFileTo = function(path2, content, overwrite, attr) {
15454
+ Utils.prototype.writeFileTo = function(path3, content, overwrite, attr) {
15445
15455
  const self2 = this;
15446
- if (self2.fs.existsSync(path2)) {
15456
+ if (self2.fs.existsSync(path3)) {
15447
15457
  if (!overwrite) return false;
15448
- var stat2 = self2.fs.statSync(path2);
15458
+ var stat2 = self2.fs.statSync(path3);
15449
15459
  if (stat2.isDirectory()) {
15450
15460
  return false;
15451
15461
  }
15452
15462
  }
15453
- var folder = pth.dirname(path2);
15463
+ var folder = pth.dirname(path3);
15454
15464
  if (!self2.fs.existsSync(folder)) {
15455
15465
  self2.makeDir(folder);
15456
15466
  }
15457
15467
  var fd;
15458
15468
  try {
15459
- fd = self2.fs.openSync(path2, "w", 438);
15469
+ fd = self2.fs.openSync(path3, "w", 438);
15460
15470
  } catch (e2) {
15461
- self2.fs.chmodSync(path2, 438);
15462
- fd = self2.fs.openSync(path2, "w", 438);
15471
+ self2.fs.chmodSync(path3, 438);
15472
+ fd = self2.fs.openSync(path3, "w", 438);
15463
15473
  }
15464
15474
  if (fd) {
15465
15475
  try {
@@ -15468,31 +15478,31 @@ var require_utils2 = __commonJS({
15468
15478
  self2.fs.closeSync(fd);
15469
15479
  }
15470
15480
  }
15471
- self2.fs.chmodSync(path2, attr || 438);
15481
+ self2.fs.chmodSync(path3, attr || 438);
15472
15482
  return true;
15473
15483
  };
15474
- Utils.prototype.writeFileToAsync = function(path2, content, overwrite, attr, callback) {
15484
+ Utils.prototype.writeFileToAsync = function(path3, content, overwrite, attr, callback) {
15475
15485
  if (typeof attr === "function") {
15476
15486
  callback = attr;
15477
15487
  attr = void 0;
15478
15488
  }
15479
15489
  const self2 = this;
15480
- self2.fs.exists(path2, function(exist) {
15490
+ self2.fs.exists(path3, function(exist) {
15481
15491
  if (exist && !overwrite) return callback(false);
15482
- self2.fs.stat(path2, function(err, stat2) {
15492
+ self2.fs.stat(path3, function(err, stat2) {
15483
15493
  if (exist && stat2.isDirectory()) {
15484
15494
  return callback(false);
15485
15495
  }
15486
- var folder = pth.dirname(path2);
15496
+ var folder = pth.dirname(path3);
15487
15497
  self2.fs.exists(folder, function(exists) {
15488
15498
  if (!exists) self2.makeDir(folder);
15489
- self2.fs.open(path2, "w", 438, function(err2, fd) {
15499
+ self2.fs.open(path3, "w", 438, function(err2, fd) {
15490
15500
  if (err2) {
15491
- self2.fs.chmod(path2, 438, function() {
15492
- self2.fs.open(path2, "w", 438, function(err3, fd2) {
15501
+ self2.fs.chmod(path3, 438, function() {
15502
+ self2.fs.open(path3, "w", 438, function(err3, fd2) {
15493
15503
  self2.fs.write(fd2, content, 0, content.length, 0, function() {
15494
15504
  self2.fs.close(fd2, function() {
15495
- self2.fs.chmod(path2, attr || 438, function() {
15505
+ self2.fs.chmod(path3, attr || 438, function() {
15496
15506
  callback(true);
15497
15507
  });
15498
15508
  });
@@ -15502,13 +15512,13 @@ var require_utils2 = __commonJS({
15502
15512
  } else if (fd) {
15503
15513
  self2.fs.write(fd, content, 0, content.length, 0, function() {
15504
15514
  self2.fs.close(fd, function() {
15505
- self2.fs.chmod(path2, attr || 438, function() {
15515
+ self2.fs.chmod(path3, attr || 438, function() {
15506
15516
  callback(true);
15507
15517
  });
15508
15518
  });
15509
15519
  });
15510
15520
  } else {
15511
- self2.fs.chmod(path2, attr || 438, function() {
15521
+ self2.fs.chmod(path3, attr || 438, function() {
15512
15522
  callback(true);
15513
15523
  });
15514
15524
  }
@@ -15517,7 +15527,7 @@ var require_utils2 = __commonJS({
15517
15527
  });
15518
15528
  });
15519
15529
  };
15520
- Utils.prototype.findFiles = function(path2) {
15530
+ Utils.prototype.findFiles = function(path3) {
15521
15531
  const self2 = this;
15522
15532
  function findSync(dir, pattern2, recursive) {
15523
15533
  if (typeof pattern2 === "boolean") {
@@ -15526,16 +15536,16 @@ var require_utils2 = __commonJS({
15526
15536
  }
15527
15537
  let files = [];
15528
15538
  self2.fs.readdirSync(dir).forEach(function(file) {
15529
- const path3 = pth.join(dir, file);
15530
- const stat2 = self2.fs.statSync(path3);
15531
- if (!pattern2 || pattern2.test(path3)) {
15532
- files.push(pth.normalize(path3) + (stat2.isDirectory() ? self2.sep : ""));
15539
+ const path4 = pth.join(dir, file);
15540
+ const stat2 = self2.fs.statSync(path4);
15541
+ if (!pattern2 || pattern2.test(path4)) {
15542
+ files.push(pth.normalize(path4) + (stat2.isDirectory() ? self2.sep : ""));
15533
15543
  }
15534
- if (stat2.isDirectory() && recursive) files = files.concat(findSync(path3, pattern2, recursive));
15544
+ if (stat2.isDirectory() && recursive) files = files.concat(findSync(path4, pattern2, recursive));
15535
15545
  });
15536
15546
  return files;
15537
15547
  }
15538
- return findSync(path2, void 0, true);
15548
+ return findSync(path3, void 0, true);
15539
15549
  };
15540
15550
  Utils.prototype.findFilesAsync = function(dir, cb) {
15541
15551
  const self2 = this;
@@ -15590,14 +15600,14 @@ var require_utils2 = __commonJS({
15590
15600
  return "UNSUPPORTED (" + method + ")";
15591
15601
  }
15592
15602
  };
15593
- Utils.canonical = function(path2) {
15594
- if (!path2) return "";
15595
- const safeSuffix = pth.posix.normalize("/" + path2.split("\\").join("/"));
15603
+ Utils.canonical = function(path3) {
15604
+ if (!path3) return "";
15605
+ const safeSuffix = pth.posix.normalize("/" + path3.split("\\").join("/"));
15596
15606
  return pth.join(".", safeSuffix);
15597
15607
  };
15598
- Utils.zipnamefix = function(path2) {
15599
- if (!path2) return "";
15600
- const safeSuffix = pth.posix.normalize("/" + path2.split("\\").join("/"));
15608
+ Utils.zipnamefix = function(path3) {
15609
+ if (!path3) return "";
15610
+ const safeSuffix = pth.posix.normalize("/" + path3.split("\\").join("/"));
15601
15611
  return pth.posix.join(".", safeSuffix);
15602
15612
  };
15603
15613
  Utils.findLast = function(arr, callback) {
@@ -15614,9 +15624,9 @@ var require_utils2 = __commonJS({
15614
15624
  prefix = pth.resolve(pth.normalize(prefix));
15615
15625
  var parts = name.split("/");
15616
15626
  for (var i2 = 0, l3 = parts.length; i2 < l3; i2++) {
15617
- var path2 = pth.normalize(pth.join(prefix, parts.slice(i2, l3).join(pth.sep)));
15618
- if (path2 === prefix || path2.startsWith(prefix + pth.sep)) {
15619
- return path2;
15627
+ var path3 = pth.normalize(pth.join(prefix, parts.slice(i2, l3).join(pth.sep)));
15628
+ if (path3 === prefix || path3.startsWith(prefix + pth.sep)) {
15629
+ return path3;
15620
15630
  }
15621
15631
  }
15622
15632
  return pth.normalize(pth.join(prefix, pth.basename(name)));
@@ -15663,8 +15673,8 @@ var require_fattr = __commonJS({
15663
15673
  "node_modules/adm-zip/util/fattr.js"(exports, module) {
15664
15674
  "use strict";
15665
15675
  var pth = __require("path");
15666
- module.exports = function(path2, { fs: fs4 }) {
15667
- var _path = path2 || "", _obj = newAttr(), _stat = null;
15676
+ module.exports = function(path3, { fs: fs4 }) {
15677
+ var _path = path3 || "", _obj = newAttr(), _stat = null;
15668
15678
  function newAttr() {
15669
15679
  return {
15670
15680
  directory: false,
@@ -17096,8 +17106,8 @@ var require_adm_zip = __commonJS({
17096
17106
  return null;
17097
17107
  }
17098
17108
  function fixPath(zipPath) {
17099
- const { join: join4, normalize, sep } = pth.posix;
17100
- return join4(pth.isAbsolute(zipPath) ? "/" : ".", normalize(sep + zipPath.split("\\").join(sep) + sep));
17109
+ const { join: join5, normalize, sep } = pth.posix;
17110
+ return join5(pth.isAbsolute(zipPath) ? "/" : ".", normalize(sep + zipPath.split("\\").join(sep) + sep));
17101
17111
  }
17102
17112
  function filenameFilter(filterfn) {
17103
17113
  if (filterfn instanceof RegExp) {
@@ -145766,8 +145776,8 @@ function getErrorMap() {
145766
145776
 
145767
145777
  // node_modules/zod/v3/helpers/parseUtil.js
145768
145778
  var makeIssue = (params) => {
145769
- const { data, path: path2, errorMaps, issueData } = params;
145770
- const fullPath = [...path2, ...issueData.path || []];
145779
+ const { data, path: path3, errorMaps, issueData } = params;
145780
+ const fullPath = [...path3, ...issueData.path || []];
145771
145781
  const fullIssue = {
145772
145782
  ...issueData,
145773
145783
  path: fullPath
@@ -145883,11 +145893,11 @@ var errorUtil;
145883
145893
 
145884
145894
  // node_modules/zod/v3/types.js
145885
145895
  var ParseInputLazyPath = class {
145886
- constructor(parent, value, path2, key) {
145896
+ constructor(parent, value, path3, key) {
145887
145897
  this._cachedPath = [];
145888
145898
  this.parent = parent;
145889
145899
  this.data = value;
145890
- this._path = path2;
145900
+ this._path = path3;
145891
145901
  this._key = key;
145892
145902
  }
145893
145903
  get path() {
@@ -149524,10 +149534,10 @@ function assignProp(target, prop, value) {
149524
149534
  configurable: true
149525
149535
  });
149526
149536
  }
149527
- function getElementAtPath(obj, path2) {
149528
- if (!path2)
149537
+ function getElementAtPath(obj, path3) {
149538
+ if (!path3)
149529
149539
  return obj;
149530
- return path2.reduce((acc, key) => acc?.[key], obj);
149540
+ return path3.reduce((acc, key) => acc?.[key], obj);
149531
149541
  }
149532
149542
  function promiseAllObject(promisesObj) {
149533
149543
  const keys = Object.keys(promisesObj);
@@ -149847,11 +149857,11 @@ function aborted(x3, startIndex = 0) {
149847
149857
  }
149848
149858
  return false;
149849
149859
  }
149850
- function prefixIssues(path2, issues) {
149860
+ function prefixIssues(path3, issues) {
149851
149861
  return issues.map((iss) => {
149852
149862
  var _a;
149853
149863
  (_a = iss).path ?? (_a.path = []);
149854
- iss.path.unshift(path2);
149864
+ iss.path.unshift(path3);
149855
149865
  return iss;
149856
149866
  });
149857
149867
  }
@@ -159935,6 +159945,7 @@ var registerJiraCrudTools = (ctx2) => {
159935
159945
 
159936
159946
  // src/tools/confluence.ts
159937
159947
  init_markdown();
159948
+ import { readFileSync } from "fs";
159938
159949
  var STORAGE_BODY_WARN_BYTES = 2 * 1024 * 1024;
159939
159950
  var registerConfluenceTools = (ctx2) => {
159940
159951
  const { server: server2, confluence: confluence2 } = ctx2;
@@ -159990,11 +160001,28 @@ var registerConfluenceTools = (ctx2) => {
159990
160001
  server2.tool("confluence_publish_doc", "Publish a markdown document as a Confluence page. Markdown is converted to native Confluence storage format (headings/lists/tables/inline marks + code fences \u2192 code macro; YAML frontmatter auto-stripped). Create a new page, or update an existing one when page_id is provided (version auto-incremented). Use to publish doc_render output to Confluence after human review.", {
159991
160002
  space_key: external_exports.string().describe("Confluence space key (e.g. PROJ). Required even in update mode (returned for reference)."),
159992
160003
  title: external_exports.string().describe("Page title"),
159993
- markdown: external_exports.string().describe("Document content in markdown. Headings (#), bullet/ordered lists, GFM tables, fenced code blocks, and inline marks (**bold**/*italic*/`code`) are supported."),
160004
+ 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."),
160005
+ 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."),
159994
160006
  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."),
159995
160007
  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.")
159996
- }, async ({ space_key, title, markdown, parent_page_id, page_id }) => {
159997
- const body = markdownToStorageFormat(markdown);
160008
+ }, async ({ space_key, title, markdown, markdown_file, parent_page_id, page_id }) => {
160009
+ if (!markdown && !markdown_file) {
160010
+ throw new Error("Either markdown or markdown_file must be provided");
160011
+ }
160012
+ if (markdown && markdown_file) {
160013
+ throw new Error("Provide either markdown or markdown_file, not both");
160014
+ }
160015
+ let md;
160016
+ if (markdown_file) {
160017
+ try {
160018
+ md = readFileSync(markdown_file, "utf8");
160019
+ } catch (err) {
160020
+ throw new Error(`Failed to read markdown_file "${markdown_file}": ${err?.message ?? err}`);
160021
+ }
160022
+ } else {
160023
+ md = markdown;
160024
+ }
160025
+ const body = markdownToStorageFormat(md);
159998
160026
  const bodyBytes = Buffer.byteLength(body, "utf8");
159999
160027
  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;
160000
160028
  if (warning) console.error(`[confluence_publish_doc] ${warning}`);
@@ -160022,6 +160050,8 @@ var registerConfluenceTools = (ctx2) => {
160022
160050
  space_key,
160023
160051
  version: result?.version?.number,
160024
160052
  url,
160053
+ input_chars: md.length,
160054
+ input_source: markdown_file ?? "inline",
160025
160055
  body_chars: body.length,
160026
160056
  body_bytes: bodyBytes,
160027
160057
  ...warning ? { warning } : {}
@@ -160512,7 +160542,7 @@ var PA_DOCUMENTS = [
160512
160542
  "[Classification]",
160513
160543
  "[SW Development Plan]",
160514
160544
  "[Risk Management Plan]",
160515
- "[Security Maintenance Plan]",
160545
+ "[Security Management Plan]",
160516
160546
  "[Configuration Management Plan]"
160517
160547
  ];
160518
160548
  var EA_DOCUMENTS = [
@@ -160717,7 +160747,7 @@ var TOOL_CATALOG = [
160717
160747
  { name: "jira_init_project", description: "\uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354\uC5D0 Jira \uD504\uB85C\uC81D\uD2B8 \uD0A4 \uCD08\uAE30 \uC124\uC815 (CLAUDE.md \uC5C5\uB370\uC774\uD2B8)", category: "\uCD08\uAE30 \uC124\uC815" },
160718
160748
  { name: "help", description: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uB3C4\uAD6C \uCE74\uD0C8\uB85C\uADF8\uC640 \uC6CC\uD06C\uD50C\uB85C\uC6B0 \uAC00\uC774\uB4DC \uC870\uD68C (topic \uC9C0\uC815 \uAC00\uB2A5)", category: "\uB3C4\uC6C0\uB9D0" },
160719
160749
  // 문서 첨부 — 마크다운 → PDF 변환 + Jira 첨부
160720
- { name: "markdown_to_pdf", description: "\uB9C8\uD06C\uB2E4\uC6B4 \u2192 PDF \uBCC0\uD658 (\uC2DC\uC2A4\uD15C \uD3F0\uD2B8 \uC790\uB3D9 \uAC10\uC9C0, \uD45C\uC9C0/\uBA38\uB9AC\uB9D0\xB7\uAF2C\uB9AC\uB9D0 \uC635\uC158)", category: "\uBB38\uC11C \uCCA8\uBD80" },
160750
+ { name: "markdown_to_pdf", description: "\uB9C8\uD06C\uB2E4\uC6B4 \u2192 PDF \uBCC0\uD658 (\uBC88\uB4E4 Pretendard Regular+Bold, \uD45C\uC9C0/\uBA38\uB9AC\uB9D0\xB7\uAF2C\uB9AC\uB9D0 \uC635\uC158)", category: "\uBB38\uC11C \uCCA8\uBD80" },
160721
160751
  { name: "jira_attach_file", description: "Jira \uC774\uC288\uC5D0 \uD30C\uC77C \uCCA8\uBD80 (file_path \uB610\uB294 base64 \uC785\uB825, 50MB \uCD08\uACFC \uC2DC warning, 100MB \uCD08\uACFC \uC2DC hard limit)", category: "\uBB38\uC11C \uCCA8\uBD80" },
160722
160752
  { name: "jira_attach_pdf_from_markdown", description: "\uB9C8\uD06C\uB2E4\uC6B4 \u2192 PDF \u2192 Jira \uCCA8\uBD80 \uC6D0\uC0F7 (description \uBBF8\uC218\uC815, summary \uCF54\uBA58\uD2B8 \uC635\uC158)", category: "\uBB38\uC11C \uCCA8\uBD80" },
160723
160753
  {
@@ -160729,6 +160759,12 @@ var TOOL_CATALOG = [
160729
160759
  name: "expert_get_cybersecurity_checklist",
160730
160760
  description: "[\uC804\uBB38\uAC00\xB7\uBCF4\uC548] Cybersecurity Reviewer \uAC80\uC0AC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uBC18\uD658 (IEC 81001-5-1 / FDA 2023 / AAMI TIR57-SW96). phase: design|implementation|verification|postmarket",
160731
160761
  category: "MDR \uC804\uBB38\uAC00"
160762
+ },
160763
+ // 문서 리뷰 soft verdict 평가 기준 (layer ② 데이터)
160764
+ {
160765
+ name: "review_get_criteria",
160766
+ description: "[\uBB38\uC11C \uB9AC\uBDF0\xB7soft verdict] document-content-reviewer\xB7requirement-coverage-tracker \uD3C9\uAC00 \uAE30\uC900(\uB808\uC774\uC5B4 \u2461) \uBC18\uD658. generic \uAE30\uBCF8 \u2014 consumer cwd\uC758 data/review-criteria.md(\uC624\uBC84\uB77C\uC774\uB4DC)\uAC00 \uC788\uC73C\uBA74 subagent\uAC00 \uCD94\uAC00 Read\uB85C \uBCF4\uC644.",
160767
+ category: "\uBB38\uC11C \uB9AC\uBDF0"
160732
160768
  }
160733
160769
  ];
160734
160770
  var WORKFLOWS = {
@@ -160741,7 +160777,7 @@ var WORKFLOWS = {
160741
160777
  "4. [Classification] \u2192 \uBD84\uB958 \uD2F0\uCF13 (MDR Class \uD310\uC815)",
160742
160778
  "5. [SW Development Plan] \u2192 \uAC1C\uBC1C \uACC4\uD68D\uC11C \uC791\uC131",
160743
160779
  "6. [Risk Management Plan] \u2192 \uB9AC\uC2A4\uD06C \uAD00\uB9AC \uACC4\uD68D\uC11C \uC791\uC131",
160744
- "7. [Security Maintenance Plan] \u2192 \uBCF4\uC548 \uC720\uC9C0\uBCF4\uC218 \uACC4\uD68D\uC11C",
160780
+ "7. [Security Management Plan] \u2192 \uBCF4\uC548 \uAD00\uB9AC \uACC4\uD68D\uC11C (IEC 81001-5-1)",
160745
160781
  "8. [Configuration Management Plan] \u2192 \uD615\uC0C1 \uAD00\uB9AC \uACC4\uD68D\uC11C",
160746
160782
  "",
160747
160783
  "\uC0AC\uC6A9\uC131 \uACF5\uD559 (IEC 62366-1)\uB3C4 PA \uB2E8\uACC4\uC5D0\uC11C \uC2DC\uC791:",
@@ -161351,7 +161387,7 @@ var registerDocValidationTools = (ctx2) => {
161351
161387
  };
161352
161388
 
161353
161389
  // src/tools/init.ts
161354
- import { readFileSync, writeFileSync as writeFileSync2, existsSync } from "fs";
161390
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "fs";
161355
161391
  import { join as join2 } from "path";
161356
161392
  var registerInitTools = ({ server: server2 }) => {
161357
161393
  server2.tool(
@@ -161367,7 +161403,7 @@ var registerInitTools = ({ server: server2 }) => {
161367
161403
  try {
161368
161404
  let content = "";
161369
161405
  if (existsSync(claudeMdPath)) {
161370
- content = readFileSync(claudeMdPath, "utf-8");
161406
+ content = readFileSync2(claudeMdPath, "utf-8");
161371
161407
  if (content.includes(line)) {
161372
161408
  return { content: [{ type: "text", text: `\uC774\uBBF8 CLAUDE.md\uC5D0 ${project_key} \uD504\uB85C\uC81D\uD2B8 \uC124\uC815\uC774 \uC788\uC2B5\uB2C8\uB2E4.` }] };
161373
161409
  }
@@ -161392,7 +161428,7 @@ var registerInitTools = ({ server: server2 }) => {
161392
161428
  };
161393
161429
 
161394
161430
  // src/tools/doc-render.ts
161395
- import { readFileSync as readFileSync2 } from "fs";
161431
+ import { readFileSync as readFileSync3 } from "fs";
161396
161432
  import { fileURLToPath } from "url";
161397
161433
  import path from "path";
161398
161434
 
@@ -161441,6 +161477,8 @@ var TEMPLATE_PATHS = {
161441
161477
  risk_management_plan: { path: "mdr_docs/PA/risk-management-plan.md", mode: "freeform", domain: "mdr", gate: "PA" },
161442
161478
  mdr_classification_document: { path: "mdr_docs/PA/mdr-classification-document.md", mode: "freeform", domain: "mdr", gate: "PA" },
161443
161479
  software_development_maintenance_plan: { path: "mdr_docs/PA/software-development-maintenance-plan.md", mode: "freeform", domain: "mdr", gate: "PA" },
161480
+ configuration_management_plan: { path: "mdr_docs/PA/configuration-management-plan.md", mode: "freeform", domain: "mdr", gate: "PA" },
161481
+ security_management_plan: { path: "mdr_docs/PA/security-management-plan.md", mode: "freeform", domain: "mdr", gate: "PA" },
161444
161482
  // mdr_docs — EA gate (IEC 62304 Evolutionary Assessment 산출물)
161445
161483
  software_requirements_list: { path: "mdr_docs/EA/software-requirements-list.md", mode: "freeform", domain: "mdr", gate: "EA" },
161446
161484
  software_architecture_description: { path: "mdr_docs/EA/software-architecture-description.md", mode: "freeform", domain: "mdr", gate: "EA" },
@@ -161451,7 +161489,7 @@ var TEMPLATE_PATHS = {
161451
161489
  list_of_hazard_related_use_scenarios: { path: "mdr_docs/EA/list-of-hazard-related-use-scenarios.md", mode: "freeform", domain: "mdr", gate: "EA" }
161452
161490
  };
161453
161491
  var TEMPLATE_NAMES = Object.keys(TEMPLATE_PATHS);
161454
- var TEMPLATE_VERSION = "4dc0c46";
161492
+ var TEMPLATE_VERSION = "8482033";
161455
161493
 
161456
161494
  // src/tools/doc-render.ts
161457
161495
  init_adf();
@@ -161463,7 +161501,7 @@ var registerDocRenderTools = (ctx2) => {
161463
161501
  "doc_render",
161464
161502
  "dev_docs(PRD/Spec/Plan/Tasks)\xB7mdr_docs(PA/EA gate \uBB38\uC11C \uC804\uCCB4) \uD15C\uD50C\uB9BF\uC744 \uBAA8\uB4DC \uAE30\uBC18 \uACB0\uC815\uC801 \uB80C\uB354(freeform). \uD2F0\uCF13 \uBA54\uD0C0({TICKET_ID}/{DATE} \uB4F1)\uB9CC \uCE58\uD658\uD558\uACE0, \uC790\uC720 \uD14D\uC2A4\uD2B8/\uAEBE\uC1E0 placeholder/AI \uC9C0\uCE68/\uBE48 \uB370\uC774\uD130 \uD45C\uB294 consumer\uAC00 \uCC44\uC6B0\uB3C4\uB85D \uBC18\uD658. (\uB808\uC774\uC5B4 \u2461 \u2014 LLM \uD638\uCD9C \uC5C6\uC74C)",
161465
161503
  {
161466
- template: external_exports.enum(TEMPLATE_NAMES).describe("\uB80C\uB354\uD560 \uD15C\uD50C\uB9BF \u2014 dev: prd|spec|plan|tasks / PA gate: intended_use|system_requirements_spec|risk_management_plan|mdr_classification_document|software_development_maintenance_plan / EA gate: software_requirements_list|software_architecture_description|risk_table_fmea|soup_list|usability_evaluation_plan|clinical_evaluation_plan|list_of_hazard_related_use_scenarios"),
161504
+ template: external_exports.enum(TEMPLATE_NAMES).describe("\uB80C\uB354\uD560 \uD15C\uD50C\uB9BF \u2014 dev: prd|spec|plan|tasks / PA gate: intended_use|system_requirements_spec|risk_management_plan|mdr_classification_document|software_development_maintenance_plan|configuration_management_plan|security_management_plan / EA gate: software_requirements_list|software_architecture_description|risk_table_fmea|soup_list|usability_evaluation_plan|clinical_evaluation_plan|list_of_hazard_related_use_scenarios"),
161467
161505
  ticket_key: external_exports.string().describe("Jira \uD2F0\uCF13 \uD0A4 (\uC608: ER-123). description/\uBA54\uD0C0 fetch\uC5D0 \uC0AC\uC6A9"),
161468
161506
  feature_slug: external_exports.string().optional().describe("{FEATURE_SLUG} \uCE58\uD658\uC6A9 (\uC608: add-login). \uBBF8\uC81C\uACF5 \uC2DC placeholder\uB85C \uB0A8\uC74C")
161469
161507
  },
@@ -161492,7 +161530,7 @@ var registerDocRenderTools = (ctx2) => {
161492
161530
  throw new Error(`template '${template}' (mode=${entry.mode}) \uB80C\uB354\uB294 \uC544\uC9C1 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uD604\uC7AC freeform\uB9CC \uAD6C\uD604\uB428.`);
161493
161531
  }
161494
161532
  const templatePath = path.join(TEMPLATE_DIR, entry.path);
161495
- const templateBody = readFileSync2(templatePath, "utf8");
161533
+ const templateBody = readFileSync3(templatePath, "utf8");
161496
161534
  const date3 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
161497
161535
  const { rendered, unresolved } = renderTemplate({
161498
161536
  template: templateBody,
@@ -161548,9 +161586,9 @@ import { readFileSync as readFileSync4 } from "fs";
161548
161586
  import { execFileSync } from "child_process";
161549
161587
 
161550
161588
  // src/utils/markdownToPdf.ts
161551
- import { existsSync as existsSync2, writeFileSync as writeFileSync3 } from "fs";
161589
+ import { writeFileSync as writeFileSync3 } from "fs";
161552
161590
  import { tmpdir } from "os";
161553
- import { join as join3 } from "path";
161591
+ import { join as join4 } from "path";
161554
161592
  import { randomUUID } from "crypto";
161555
161593
 
161556
161594
  // node_modules/pdfkit/js/pdfkit.es.js
@@ -172855,16 +172893,16 @@ var $f43aec954cdfdf21$export$2e2bcd8739ae039 = class _$f43aec954cdfdf21$export$2
172855
172893
  * @return {Path}
172856
172894
  */
172857
172895
  mapPoints(fn) {
172858
- let path2 = new _$f43aec954cdfdf21$export$2e2bcd8739ae039();
172896
+ let path3 = new _$f43aec954cdfdf21$export$2e2bcd8739ae039();
172859
172897
  for (let c of this.commands) {
172860
172898
  let args = [];
172861
172899
  for (let i2 = 0; i2 < c.args.length; i2 += 2) {
172862
172900
  let [x3, y2] = fn(c.args[i2], c.args[i2 + 1]);
172863
172901
  args.push(x3, y2);
172864
172902
  }
172865
- path2[c.command](...args);
172903
+ path3[c.command](...args);
172866
172904
  }
172867
- return path2;
172905
+ return path3;
172868
172906
  }
172869
172907
  /**
172870
172908
  * Transforms the path by the given matrix.
@@ -173557,7 +173595,7 @@ var $69aac16029968692$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173557
173595
  // Converts contours to a Path object that can be rendered
173558
173596
  _getPath() {
173559
173597
  let contours = this._getContours();
173560
- let path2 = new (0, $f43aec954cdfdf21$export$2e2bcd8739ae039)();
173598
+ let path3 = new (0, $f43aec954cdfdf21$export$2e2bcd8739ae039)();
173561
173599
  for (let i2 = 0; i2 < contours.length; i2++) {
173562
173600
  let contour = contours[i2];
173563
173601
  let firstPt = contour[0];
@@ -173573,26 +173611,26 @@ var $69aac16029968692$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173573
173611
  firstPt = new $69aac16029968692$export$baf26146a414f24a(false, false, (firstPt.x + lastPt.x) / 2, (firstPt.y + lastPt.y) / 2);
173574
173612
  var curvePt = firstPt;
173575
173613
  }
173576
- path2.moveTo(firstPt.x, firstPt.y);
173614
+ path3.moveTo(firstPt.x, firstPt.y);
173577
173615
  for (let j2 = start; j2 < contour.length; j2++) {
173578
173616
  let pt = contour[j2];
173579
173617
  let prevPt = j2 === 0 ? firstPt : contour[j2 - 1];
173580
- if (prevPt.onCurve && pt.onCurve) path2.lineTo(pt.x, pt.y);
173618
+ if (prevPt.onCurve && pt.onCurve) path3.lineTo(pt.x, pt.y);
173581
173619
  else if (prevPt.onCurve && !pt.onCurve) var curvePt = pt;
173582
173620
  else if (!prevPt.onCurve && !pt.onCurve) {
173583
173621
  let midX = (prevPt.x + pt.x) / 2;
173584
173622
  let midY = (prevPt.y + pt.y) / 2;
173585
- path2.quadraticCurveTo(prevPt.x, prevPt.y, midX, midY);
173623
+ path3.quadraticCurveTo(prevPt.x, prevPt.y, midX, midY);
173586
173624
  var curvePt = pt;
173587
173625
  } else if (!prevPt.onCurve && pt.onCurve) {
173588
- path2.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y);
173626
+ path3.quadraticCurveTo(curvePt.x, curvePt.y, pt.x, pt.y);
173589
173627
  var curvePt = null;
173590
173628
  } else throw new Error("Unknown TTF path state");
173591
173629
  }
173592
- if (curvePt) path2.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y);
173593
- path2.closePath();
173630
+ if (curvePt) path3.quadraticCurveTo(curvePt.x, curvePt.y, firstPt.x, firstPt.y);
173631
+ path3.closePath();
173594
173632
  }
173595
- return path2;
173633
+ return path3;
173596
173634
  }
173597
173635
  constructor(...args) {
173598
173636
  super(...args);
@@ -173615,7 +173653,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173615
173653
  let str = cff.topDict.CharStrings[this.id];
173616
173654
  let end = str.offset + str.length;
173617
173655
  stream2.pos = str.offset;
173618
- let path2 = new (0, $f43aec954cdfdf21$export$2e2bcd8739ae039)();
173656
+ let path3 = new (0, $f43aec954cdfdf21$export$2e2bcd8739ae039)();
173619
173657
  let stack = [];
173620
173658
  let trans = [];
173621
173659
  let width = null;
@@ -173643,8 +173681,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173643
173681
  return stack.length = 0;
173644
173682
  }
173645
173683
  function moveTo(x4, y3) {
173646
- if (open) path2.closePath();
173647
- path2.moveTo(x4, y3);
173684
+ if (open) path3.closePath();
173685
+ path3.moveTo(x4, y3);
173648
173686
  open = true;
173649
173687
  }
173650
173688
  let parse4 = function() {
@@ -173671,7 +173709,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173671
173709
  while (stack.length >= 2) {
173672
173710
  x3 += stack.shift();
173673
173711
  y2 += stack.shift();
173674
- path2.lineTo(x3, y2);
173712
+ path3.lineTo(x3, y2);
173675
173713
  }
173676
173714
  break;
173677
173715
  case 6:
@@ -173680,7 +173718,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173680
173718
  while (stack.length >= 1) {
173681
173719
  if (phase) x3 += stack.shift();
173682
173720
  else y2 += stack.shift();
173683
- path2.lineTo(x3, y2);
173721
+ path3.lineTo(x3, y2);
173684
173722
  phase = !phase;
173685
173723
  }
173686
173724
  break;
@@ -173692,7 +173730,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173692
173730
  c2y = c1y + stack.shift();
173693
173731
  x3 = c2x + stack.shift();
173694
173732
  y2 = c2y + stack.shift();
173695
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173733
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173696
173734
  }
173697
173735
  break;
173698
173736
  case 10:
@@ -173716,7 +173754,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173716
173754
  if (cff.version >= 2) break;
173717
173755
  if (stack.length > 0) checkWidth();
173718
173756
  if (open) {
173719
- path2.closePath();
173757
+ path3.closePath();
173720
173758
  open = false;
173721
173759
  }
173722
173760
  break;
@@ -173764,17 +173802,17 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173764
173802
  c2y = c1y + stack.shift();
173765
173803
  x3 = c2x + stack.shift();
173766
173804
  y2 = c2y + stack.shift();
173767
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173805
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173768
173806
  }
173769
173807
  x3 += stack.shift();
173770
173808
  y2 += stack.shift();
173771
- path2.lineTo(x3, y2);
173809
+ path3.lineTo(x3, y2);
173772
173810
  break;
173773
173811
  case 25:
173774
173812
  while (stack.length >= 8) {
173775
173813
  x3 += stack.shift();
173776
173814
  y2 += stack.shift();
173777
- path2.lineTo(x3, y2);
173815
+ path3.lineTo(x3, y2);
173778
173816
  }
173779
173817
  c1x = x3 + stack.shift();
173780
173818
  c1y = y2 + stack.shift();
@@ -173782,7 +173820,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173782
173820
  c2y = c1y + stack.shift();
173783
173821
  x3 = c2x + stack.shift();
173784
173822
  y2 = c2y + stack.shift();
173785
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173823
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173786
173824
  break;
173787
173825
  case 26:
173788
173826
  if (stack.length % 2) x3 += stack.shift();
@@ -173793,7 +173831,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173793
173831
  c2y = c1y + stack.shift();
173794
173832
  x3 = c2x;
173795
173833
  y2 = c2y + stack.shift();
173796
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173834
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173797
173835
  }
173798
173836
  break;
173799
173837
  case 27:
@@ -173805,7 +173843,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173805
173843
  c2y = c1y + stack.shift();
173806
173844
  x3 = c2x + stack.shift();
173807
173845
  y2 = c2y;
173808
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173846
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173809
173847
  }
173810
173848
  break;
173811
173849
  case 28:
@@ -173844,7 +173882,7 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173844
173882
  x3 = c2x + stack.shift();
173845
173883
  y2 = c2y + (stack.length === 1 ? stack.shift() : 0);
173846
173884
  }
173847
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173885
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, x3, y2);
173848
173886
  phase = !phase;
173849
173887
  }
173850
173888
  break;
@@ -173970,8 +174008,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173970
174008
  c6y = c5y;
173971
174009
  x3 = c6x;
173972
174010
  y2 = c6y;
173973
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);
173974
- path2.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);
174011
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);
174012
+ path3.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);
173975
174013
  break;
173976
174014
  case 35:
173977
174015
  pts = [];
@@ -173980,8 +174018,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173980
174018
  y2 += stack.shift();
173981
174019
  pts.push(x3, y2);
173982
174020
  }
173983
- path2.bezierCurveTo(...pts.slice(0, 6));
173984
- path2.bezierCurveTo(...pts.slice(6));
174021
+ path3.bezierCurveTo(...pts.slice(0, 6));
174022
+ path3.bezierCurveTo(...pts.slice(6));
173985
174023
  stack.shift();
173986
174024
  break;
173987
174025
  case 36:
@@ -173999,8 +174037,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
173999
174037
  c6y = c5y;
174000
174038
  x3 = c6x;
174001
174039
  y2 = c6y;
174002
- path2.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);
174003
- path2.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);
174040
+ path3.bezierCurveTo(c1x, c1y, c2x, c2y, c3x, c3y);
174041
+ path3.bezierCurveTo(c4x, c4y, c5x, c5y, c6x, c6y);
174004
174042
  break;
174005
174043
  case 37:
174006
174044
  let startx = x3;
@@ -174019,8 +174057,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
174019
174057
  y2 += stack.shift();
174020
174058
  }
174021
174059
  pts.push(x3, y2);
174022
- path2.bezierCurveTo(...pts.slice(0, 6));
174023
- path2.bezierCurveTo(...pts.slice(6));
174060
+ path3.bezierCurveTo(...pts.slice(0, 6));
174061
+ path3.bezierCurveTo(...pts.slice(6));
174024
174062
  break;
174025
174063
  default:
174026
174064
  throw new Error(`Unknown op: 12 ${op}`);
@@ -174040,8 +174078,8 @@ var $62cc5109c6101893$export$2e2bcd8739ae039 = class extends (0, $f92906be28e617
174040
174078
  }
174041
174079
  };
174042
174080
  parse4();
174043
- if (open) path2.closePath();
174044
- return path2;
174081
+ if (open) path3.closePath();
174082
+ return path3;
174045
174083
  }
174046
174084
  constructor(...args) {
174047
174085
  super(...args);
@@ -174501,7 +174539,7 @@ var $807e58506be70005$var$Glyf = new Struct({
174501
174539
  yPoints: new ArrayT($807e58506be70005$var$Point, 0)
174502
174540
  });
174503
174541
  var $807e58506be70005$export$2e2bcd8739ae039 = class {
174504
- encodeSimple(path2, instructions = []) {
174542
+ encodeSimple(path3, instructions = []) {
174505
174543
  let endPtsOfContours = [];
174506
174544
  let xPoints = [];
174507
174545
  let yPoints = [];
@@ -174509,14 +174547,14 @@ var $807e58506be70005$export$2e2bcd8739ae039 = class {
174509
174547
  let same = 0;
174510
174548
  let lastX = 0, lastY = 0, lastFlag = 0;
174511
174549
  let pointCount = 0;
174512
- for (let i2 = 0; i2 < path2.commands.length; i2++) {
174513
- let c = path2.commands[i2];
174550
+ for (let i2 = 0; i2 < path3.commands.length; i2++) {
174551
+ let c = path3.commands[i2];
174514
174552
  for (let j2 = 0; j2 < c.args.length; j2 += 2) {
174515
174553
  let x3 = c.args[j2];
174516
174554
  let y2 = c.args[j2 + 1];
174517
174555
  let flag = 0;
174518
174556
  if (c.command === "quadraticCurveTo" && j2 === 2) {
174519
- let next = path2.commands[i2 + 1];
174557
+ let next = path3.commands[i2 + 1];
174520
174558
  if (next && next.command === "quadraticCurveTo") {
174521
174559
  let midX = (lastX + next.args[0]) / 2;
174522
174560
  let midY = (lastY + next.args[1]) / 2;
@@ -174543,8 +174581,8 @@ var $807e58506be70005$export$2e2bcd8739ae039 = class {
174543
174581
  }
174544
174582
  if (c.command === "closePath") endPtsOfContours.push(pointCount - 1);
174545
174583
  }
174546
- if (path2.commands.length > 1 && path2.commands[path2.commands.length - 1].command !== "closePath") endPtsOfContours.push(pointCount - 1);
174547
- let bbox = path2.bbox;
174584
+ if (path3.commands.length > 1 && path3.commands[path3.commands.length - 1].command !== "closePath") endPtsOfContours.push(pointCount - 1);
174585
+ let bbox = path3.bbox;
174548
174586
  let glyf = {
174549
174587
  numberOfContours: endPtsOfContours.length,
174550
174588
  xMin: bbox.minX,
@@ -174651,7 +174689,7 @@ var $001d739428a71d5a$export$2e2bcd8739ae039 = class extends (0, $5cc7476da92df3
174651
174689
  for (let gid of this.glyphs) {
174652
174690
  this.charstrings.push(this.cff.getCharString(gid));
174653
174691
  let glyph = this.font.getGlyph(gid);
174654
- let path2 = glyph.path;
174692
+ let path3 = glyph.path;
174655
174693
  for (let subr in glyph._usedGsubrs) gsubrs[subr] = true;
174656
174694
  }
174657
174695
  this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);
@@ -174689,7 +174727,7 @@ var $001d739428a71d5a$export$2e2bcd8739ae039 = class extends (0, $5cc7476da92df3
174689
174727
  used_fds[fd] = true;
174690
174728
  topDict.FDSelect.fds.push(fd_select[fd]);
174691
174729
  let glyph = this.font.getGlyph(gid);
174692
- let path2 = glyph.path;
174730
+ let path3 = glyph.path;
174693
174731
  for (let subr in glyph._usedSubrs) used_subrs[fd_select[fd]][subr] = true;
174694
174732
  }
174695
174733
  for (let i2 = 0; i2 < topDict.FDArray.length; i2++) {
@@ -174706,7 +174744,7 @@ var $001d739428a71d5a$export$2e2bcd8739ae039 = class extends (0, $5cc7476da92df3
174706
174744
  let used_subrs = {};
174707
174745
  for (let gid of this.glyphs) {
174708
174746
  let glyph = this.font.getGlyph(gid);
174709
- let path2 = glyph.path;
174747
+ let path3 = glyph.path;
174710
174748
  for (let subr in glyph._usedSubrs) used_subrs[subr] = true;
174711
174749
  }
174712
174750
  let privateDict = Object.assign({}, this.cff.topDict.Private);
@@ -177014,17 +177052,17 @@ $557adaaeb0c7885f$exports = $557adaaeb0c7885f$var$LineBreaker;
177014
177052
  import fs2 from "fs";
177015
177053
  import zlib2 from "zlib";
177016
177054
  var PNG = class _PNG {
177017
- static decode(path2, fn) {
177055
+ static decode(path3, fn) {
177018
177056
  {
177019
- return fs2.readFile(path2, function(err, file) {
177057
+ return fs2.readFile(path3, function(err, file) {
177020
177058
  const png = new _PNG(file);
177021
177059
  return png.decode((pixels) => fn(pixels));
177022
177060
  });
177023
177061
  }
177024
177062
  }
177025
- static load(path2) {
177063
+ static load(path3) {
177026
177064
  {
177027
- const file = fs2.readFileSync(path2);
177065
+ const file = fs2.readFileSync(path3);
177028
177066
  return new _PNG(file);
177029
177067
  }
177030
177068
  }
@@ -178892,15 +178930,15 @@ var readNumber = function(string3, cursor) {
178892
178930
  }
178893
178931
  return [i2 - 1, number4];
178894
178932
  };
178895
- var parse3 = function(path2) {
178933
+ var parse3 = function(path3) {
178896
178934
  const pathData = [];
178897
178935
  let command = null;
178898
178936
  let args = [];
178899
178937
  let argsCount = 0;
178900
178938
  let canHaveComma = false;
178901
178939
  let hadComma = false;
178902
- for (let i2 = 0; i2 < path2.length; i2 += 1) {
178903
- const c = path2.charAt(i2);
178940
+ for (let i2 = 0; i2 < path3.length; i2 += 1) {
178941
+ const c = path3.charAt(i2);
178904
178942
  if (isWsp(c)) {
178905
178943
  continue;
178906
178944
  }
@@ -178945,11 +178983,11 @@ var parse3 = function(path2) {
178945
178983
  const position = args.length;
178946
178984
  if (position === 0 || position === 1) {
178947
178985
  if (c !== "+" && c !== "-") {
178948
- [newCursor, number4] = readNumber(path2, i2);
178986
+ [newCursor, number4] = readNumber(path3, i2);
178949
178987
  }
178950
178988
  }
178951
178989
  if (position === 2 || position === 5 || position === 6) {
178952
- [newCursor, number4] = readNumber(path2, i2);
178990
+ [newCursor, number4] = readNumber(path3, i2);
178953
178991
  }
178954
178992
  if (position === 3 || position === 4) {
178955
178993
  if (c === "0") {
@@ -178960,7 +178998,7 @@ var parse3 = function(path2) {
178960
178998
  }
178961
178999
  }
178962
179000
  } else {
178963
- [newCursor, number4] = readNumber(path2, i2);
179001
+ [newCursor, number4] = readNumber(path3, i2);
178964
179002
  }
178965
179003
  if (number4 == null) {
178966
179004
  return pathData;
@@ -179216,8 +179254,8 @@ var segmentToBezier = function(cx2, cy2, th0, th1, rx, ry, sin_th, cos_th) {
179216
179254
  return [a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x22 + a01 * y2, a10 * x22 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3];
179217
179255
  };
179218
179256
  var SVGPath = class {
179219
- static apply(doc, path2) {
179220
- const commands = parse3(path2);
179257
+ static apply(doc, path3) {
179258
+ const commands = parse3(path3);
179221
179259
  apply(commands, doc);
179222
179260
  }
179223
179261
  };
@@ -179402,8 +179440,8 @@ var VectorMixin = {
179402
179440
  }
179403
179441
  return this.closePath();
179404
179442
  },
179405
- path(path2) {
179406
- SVGPath.apply(this, path2);
179443
+ path(path3) {
179444
+ SVGPath.apply(this, path3);
179407
179445
  return this;
179408
179446
  },
179409
179447
  _windingRule(rule) {
@@ -183599,45 +183637,59 @@ PDFDocument.LineWrapper = LineWrapper;
183599
183637
 
183600
183638
  // src/utils/markdownToPdf.ts
183601
183639
  init_marked_esm();
183602
- var FRONTMATTER_RE2 = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
183603
- function stripFrontmatter2(md) {
183604
- return md.replace(FRONTMATTER_RE2, "");
183640
+
183641
+ // src/utils/pdf-fonts.ts
183642
+ import { existsSync as existsSync2 } from "fs";
183643
+ import { join as join3, dirname } from "path";
183644
+ import { fileURLToPath as fileURLToPath2 } from "url";
183645
+ var BUNDLED_FONT_FAMILY = "BodyFont";
183646
+ var BUNDLED_FONT_FAMILY_BOLD = "BodyFont-Bold";
183647
+ var DEFAULT_FAMILY = "BodyFont";
183648
+ function bundledFontPaths() {
183649
+ const here = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath2(import.meta.url));
183650
+ const rootFromSrc = join3(here, "..", "..");
183651
+ const candidates = [join3(here, "fonts"), join3(rootFromSrc, "dist", "fonts")];
183652
+ const fontsDir = candidates.find(
183653
+ (d2) => existsSync2(join3(d2, "Pretendard-Regular.ttf")) && existsSync2(join3(d2, "Pretendard-Bold.ttf"))
183654
+ );
183655
+ const dir = fontsDir || candidates[0];
183656
+ return {
183657
+ regular: join3(dir, "Pretendard-Regular.ttf"),
183658
+ bold: join3(dir, "Pretendard-Bold.ttf")
183659
+ };
183605
183660
  }
183606
- function getCandidates() {
183607
- if (process.platform === "win32") {
183608
- const winDir = process.env.WINDIR || process.env.SystemRoot || "C:\\Windows";
183609
- const fontsDir = join3(winDir, "Fonts");
183610
- return [
183611
- { path: join3(fontsDir, "malgun.ttf"), family: "MalgunGothic", isCjk: true, source: "malgun-gothic" },
183612
- { path: join3(fontsDir, "msgothic.ttc"), family: "MSGothic", isCjk: true, source: "msgothic" },
183613
- { path: join3(fontsDir, "YuGothM.ttc"), family: "YuGothic", isCjk: true, source: "yu-gothic" },
183614
- { path: join3(fontsDir, "arial.ttf"), family: "Arial", isCjk: false, source: "arial" }
183615
- ];
183661
+ function resolveFonts(opts) {
183662
+ const familyName = opts.fontFamilyName || DEFAULT_FAMILY;
183663
+ if (opts.fontPath) {
183664
+ return {
183665
+ regularFamily: familyName,
183666
+ boldFamily: familyName,
183667
+ regularPath: opts.fontPath
183668
+ };
183616
183669
  }
183617
- if (process.platform === "darwin") {
183618
- return [
183619
- { path: "/System/Library/Fonts/AppleSDGothicNeo.ttc", family: "AppleSDGothicNeo", isCjk: true, source: "apple-sd-gothic" },
183620
- { path: "/System/Library/Fonts/PingFang.ttc", family: "PingFang", isCjk: true, source: "pingfang" },
183621
- { path: "/System/Library/Fonts/Helvetica.ttc", family: "Helvetica", isCjk: false, source: "helvetica" }
183622
- ];
183670
+ const paths = bundledFontPaths();
183671
+ if (existsSync2(paths.regular) && existsSync2(paths.bold)) {
183672
+ return {
183673
+ regularFamily: BUNDLED_FONT_FAMILY,
183674
+ boldFamily: BUNDLED_FONT_FAMILY_BOLD,
183675
+ regularPath: paths.regular,
183676
+ boldPath: paths.bold
183677
+ };
183623
183678
  }
183624
- return [
183625
- { path: "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", family: "NotoSansCJK", isCjk: true, source: "noto-cjk" },
183626
- { path: "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.otf", family: "NotoSansCJK", isCjk: true, source: "noto-cjk" },
183627
- { path: "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc", family: "NotoSansCJK", isCjk: true, source: "noto-cjk" },
183628
- { path: "/usr/share/fonts/truetype/nanum/NanumGothic.ttf", family: "NanumGothic", isCjk: true, source: "nanum-gothic" },
183629
- { path: "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", family: "DejaVuSans", isCjk: false, source: "dejavu" }
183630
- ];
183679
+ const warning = `[pdf-fonts] Bundled Pretendard font not found at ${paths.regular}. Falling back to pdfkit default (Helvetica). CJK characters will render as missing glyphs. Run \`npm run build\` to copy fonts.`;
183680
+ console.error(warning);
183681
+ return {
183682
+ regularFamily: "Helvetica",
183683
+ boldFamily: "Helvetica",
183684
+ warning
183685
+ };
183631
183686
  }
183632
- function detectSystemFont() {
183633
- for (const c of getCandidates()) {
183634
- if (existsSync2(c.path)) {
183635
- return { fontPath: c.path, familyName: c.family, isCjk: c.isCjk, source: c.source };
183636
- }
183637
- }
183638
- return null;
183687
+
183688
+ // src/utils/markdownToPdf.ts
183689
+ var FRONTMATTER_RE2 = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
183690
+ function stripFrontmatter2(md) {
183691
+ return md.replace(FRONTMATTER_RE2, "");
183639
183692
  }
183640
- var FONT_FAMILY_DEFAULT = "BodyFont";
183641
183693
  var PAGE_SIZE_DEFAULT = "A4";
183642
183694
  var MARGIN_DEFAULT = 56;
183643
183695
  async function markdownToPdf(md, opts = {}) {
@@ -183647,7 +183699,7 @@ async function markdownToPdf(md, opts = {}) {
183647
183699
  includeCover = false,
183648
183700
  author = "jira-mcp-server",
183649
183701
  fontPath,
183650
- fontFamilyName = FONT_FAMILY_DEFAULT,
183702
+ fontFamilyName,
183651
183703
  pageSize = PAGE_SIZE_DEFAULT,
183652
183704
  margin = {},
183653
183705
  language = "en",
@@ -183659,19 +183711,8 @@ async function markdownToPdf(md, opts = {}) {
183659
183711
  const right = margin.right ?? MARGIN_DEFAULT;
183660
183712
  const resolvedTitle = title || sourceRef || "Document";
183661
183713
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
183662
- let fontFamily = fontFamilyName;
183663
- let fontWarning;
183664
- if (fontPath) {
183665
- fontFamily = fontFamilyName;
183666
- } else {
183667
- const detected = detectSystemFont();
183668
- if (detected) {
183669
- fontFamily = detected.familyName;
183670
- } else {
183671
- fontWarning = `[markdownToPdf] No CJK-capable system font detected; using pdfkit default (Helvetica). CJK characters will render as missing glyphs. Pass fontPath to override.`;
183672
- console.error(fontWarning);
183673
- }
183674
- }
183714
+ const resolved = resolveFonts({ fontPath, fontFamilyName });
183715
+ let fontWarning = resolved.warning;
183675
183716
  const doc = new PDFDocument({
183676
183717
  info: { Title: resolvedTitle, Author: author, CreationDate: /* @__PURE__ */ new Date() },
183677
183718
  size: pageSize,
@@ -183680,35 +183721,29 @@ async function markdownToPdf(md, opts = {}) {
183680
183721
  // 머리말/꼬리말 후 페이지 사후 그리기 + bufferedPageRange() 사용
183681
183722
  });
183682
183723
  void language;
183683
- if (fontPath) {
183724
+ if (resolved.regularPath) {
183684
183725
  try {
183685
- doc.registerFont(fontFamilyName, fontPath);
183686
- doc.font(fontFamilyName);
183687
- fontFamily = fontFamilyName;
183726
+ doc.registerFont(resolved.regularFamily, resolved.regularPath);
183727
+ doc.font(resolved.regularFamily);
183688
183728
  } catch (err) {
183689
- fontWarning = `[markdownToPdf] Failed to register font "${fontPath}": ${err?.message ?? err}. Falling back to pdfkit default.`;
183729
+ fontWarning = `[markdownToPdf] Failed to register regular font "${resolved.regularPath}": ${err?.message ?? err}. Falling back to pdfkit default.`;
183690
183730
  console.error(fontWarning);
183691
- doc.font("Helvetica");
183692
- fontFamily = "Helvetica";
183731
+ resolved.regularFamily = "Helvetica";
183732
+ resolved.boldFamily = "Helvetica";
183693
183733
  }
183694
- } else if (fontFamily !== FONT_FAMILY_DEFAULT) {
183695
- const detected = detectSystemFont();
183696
- if (detected) {
183697
- try {
183698
- doc.registerFont(detected.familyName, detected.fontPath);
183699
- doc.font(detected.familyName);
183700
- fontFamily = detected.familyName;
183701
- } catch (err) {
183702
- fontWarning = `[markdownToPdf] Failed to register detected font "${detected.fontPath}": ${err?.message ?? err}. Falling back to pdfkit default.`;
183703
- console.error(fontWarning);
183704
- doc.font("Helvetica");
183705
- fontFamily = "Helvetica";
183706
- }
183734
+ }
183735
+ if (resolved.boldPath && resolved.boldFamily !== resolved.regularFamily) {
183736
+ try {
183737
+ doc.registerFont(resolved.boldFamily, resolved.boldPath);
183738
+ doc.font(resolved.boldFamily);
183739
+ } catch (err) {
183740
+ fontWarning = `[markdownToPdf] Failed to register bold font "${resolved.boldPath}": ${err?.message ?? err}. Bold falls back to regular.`;
183741
+ console.error(fontWarning);
183742
+ resolved.boldFamily = resolved.regularFamily;
183707
183743
  }
183708
- } else {
183709
- doc.font("Helvetica");
183710
- fontFamily = "Helvetica";
183711
183744
  }
183745
+ doc.font(resolved.regularFamily);
183746
+ const fonts = resolved;
183712
183747
  if (includeCover) {
183713
183748
  doc.moveDown(8);
183714
183749
  doc.fontSize(28).fillColor("#000").text(resolvedTitle, { align: "left" });
@@ -183728,7 +183763,7 @@ async function markdownToPdf(md, opts = {}) {
183728
183763
  const body = stripFrontmatter2(md ?? "");
183729
183764
  const tokens = g.lexer(body);
183730
183765
  for (const tok of tokens) {
183731
- renderToken(doc, tok, fontFamily);
183766
+ renderToken(doc, tok, fonts);
183732
183767
  }
183733
183768
  if (tokens.length === 0) {
183734
183769
  doc.fontSize(11).fillColor("#000").text("");
@@ -183824,26 +183859,26 @@ function lineHeightOf(doc) {
183824
183859
  const size = doc._fontSize ?? 11;
183825
183860
  return size * 1.2;
183826
183861
  }
183827
- function renderToken(doc, tok, fontFamily) {
183862
+ function renderToken(doc, tok, fonts) {
183828
183863
  if (!tok || typeof tok !== "object") return;
183829
183864
  switch (tok.type) {
183830
183865
  case "heading":
183831
- renderHeading(doc, tok, fontFamily);
183866
+ renderHeading(doc, tok, fonts);
183832
183867
  return;
183833
183868
  case "paragraph":
183834
- renderParagraph(doc, tok, fontFamily);
183869
+ renderParagraph(doc, tok, fonts);
183835
183870
  return;
183836
183871
  case "code":
183837
183872
  renderCodeBlock(doc, tok);
183838
183873
  return;
183839
183874
  case "blockquote":
183840
- renderBlockquote(doc, tok, fontFamily);
183875
+ renderBlockquote(doc, tok, fonts);
183841
183876
  return;
183842
183877
  case "list":
183843
- renderList(doc, tok, fontFamily, 0);
183878
+ renderList(doc, tok, fonts, 0);
183844
183879
  return;
183845
183880
  case "table":
183846
- renderTable(doc, tok, fontFamily);
183881
+ renderTable(doc, tok, fonts);
183847
183882
  return;
183848
183883
  case "hr":
183849
183884
  renderHr(doc);
@@ -183853,18 +183888,18 @@ function renderToken(doc, tok, fontFamily) {
183853
183888
  return;
183854
183889
  default:
183855
183890
  if (tok.text) {
183856
- doc.fontSize(BODY_FONT_SIZE).fillColor("#000").font(fontFamily).text(String(tok.text));
183891
+ doc.fontSize(BODY_FONT_SIZE).fillColor("#000").font(fonts.regularFamily).text(String(tok.text));
183857
183892
  }
183858
183893
  }
183859
183894
  }
183860
- function renderHeading(doc, tok, fontFamily) {
183895
+ function renderHeading(doc, tok, fonts) {
183861
183896
  const level = Math.min(Math.max(Number(tok.depth) || 1, 1), 6);
183862
183897
  const size = HEADING_SIZES[level - 1];
183863
183898
  const text = tok.text ?? "";
183864
183899
  const marginL = doc.page.margins.left;
183865
183900
  const marginR = doc.page.margins.right;
183866
183901
  const width = doc.page.width - marginL - marginR;
183867
- doc.fontSize(size).fillColor("#111").font(fontFamily);
183902
+ doc.fontSize(size).fillColor("#111").font(fonts.boldFamily);
183868
183903
  const before = level === 1 ? SPACE2.H1_BEFORE : level === 2 ? SPACE2.H2_BEFORE : level === 3 ? SPACE2.H3_BEFORE : SPACE2.H4_H6_BEFORE;
183869
183904
  doc.y += before;
183870
183905
  const lineHeight = lineHeightOf(doc);
@@ -183877,12 +183912,12 @@ function renderHeading(doc, tok, fontFamily) {
183877
183912
  doc.y += after;
183878
183913
  void lines;
183879
183914
  }
183880
- function renderParagraph(doc, tok, fontFamily) {
183915
+ function renderParagraph(doc, tok, fonts) {
183881
183916
  const marginL = doc.page.margins.left;
183882
183917
  const marginR = doc.page.margins.right;
183883
183918
  const width = doc.page.width - marginL - marginR;
183884
183919
  const text = inlineToPlainText(tok.tokens ?? [{ type: "text", text: tok.text ?? "" }]);
183885
- doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fontFamily);
183920
+ doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fonts.regularFamily);
183886
183921
  doc.y += SPACE2.PARAGRAPH_BEFORE;
183887
183922
  const lineHeight = lineHeightOf(doc);
183888
183923
  if (text) {
@@ -183945,13 +183980,13 @@ function renderCodeBlock(doc, tok) {
183945
183980
  doc.fillColor("#000");
183946
183981
  doc.y = boxY + blockHeight + SPACE2.CODE_AFTER;
183947
183982
  }
183948
- function renderBlockquote(doc, tok, fontFamily) {
183983
+ function renderBlockquote(doc, tok, fonts) {
183949
183984
  const marginL = doc.page.margins.left;
183950
183985
  const marginR = doc.page.margins.right;
183951
183986
  const indent = 20;
183952
183987
  const width = doc.page.width - marginL - marginR - indent;
183953
183988
  doc.y += SPACE2.BLOCKQUOTE_BEFORE;
183954
- doc.fontSize(BODY_FONT_SIZE).fillColor("#555").font(fontFamily);
183989
+ doc.fontSize(BODY_FONT_SIZE).fillColor("#555").font(fonts.regularFamily);
183955
183990
  const flat = (tok.tokens ?? []).map(extractInlineText).filter(Boolean).join(" ");
183956
183991
  if (flat) {
183957
183992
  const lineHeight = lineHeightOf(doc);
@@ -183973,7 +184008,7 @@ function extractInlineText(node) {
183973
184008
  if (Array.isArray(node.tokens)) return node.tokens.map(extractInlineText).join("");
183974
184009
  return "";
183975
184010
  }
183976
- function renderList(doc, tok, fontFamily, depth) {
184011
+ function renderList(doc, tok, fonts, depth) {
183977
184012
  const items = tok.items ?? [];
183978
184013
  const ordered = !!tok.ordered;
183979
184014
  const marginL = doc.page.margins.left;
@@ -183988,43 +184023,38 @@ function renderList(doc, tok, fontFamily, depth) {
183988
184023
  for (const item of items) {
183989
184024
  const marker = ordered ? `${counter}. ` : "\u2022 ";
183990
184025
  counter += 1;
183991
- doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fontFamily);
184026
+ doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fonts.regularFamily);
183992
184027
  const markerX = marginL + indent;
183993
184028
  doc.text(marker, markerX, doc.y, { width: markerWidth, continued: false });
183994
184029
  doc.x = markerX + markerWidth;
183995
184030
  const bodyStartY = doc.y - lineHeightOf(doc);
183996
184031
  doc.y = bodyStartY;
183997
184032
  const subs = Array.isArray(item.tokens) ? item.tokens : [];
183998
- let firstInline = true;
183999
184033
  let drewAnything = false;
184000
184034
  for (const sub of subs) {
184001
184035
  if (sub?.type === "text" && Array.isArray(sub.tokens)) {
184002
- drawInlineInBox(doc, sub.tokens, fontFamily, doc.x, bodyStartY, itemWidth - markerWidth);
184036
+ drawInlineInBox(doc, sub.tokens, fonts, doc.x, bodyStartY, itemWidth - markerWidth);
184003
184037
  drewAnything = true;
184004
- firstInline = false;
184005
184038
  } else if (sub?.type === "paragraph") {
184006
184039
  drawInlineInBox(
184007
184040
  doc,
184008
184041
  sub.tokens ?? [{ type: "text", text: sub.text ?? "" }],
184009
- fontFamily,
184042
+ fonts,
184010
184043
  doc.x,
184011
184044
  bodyStartY,
184012
184045
  itemWidth - markerWidth
184013
184046
  );
184014
184047
  drewAnything = true;
184015
- firstInline = false;
184016
184048
  } else if (sub?.type === "list") {
184017
184049
  doc.x = marginL + indent + 12;
184018
184050
  doc.y = doc.y + SPACE2.LIST_ITEM_BEFORE;
184019
- renderList(doc, sub, fontFamily, depth + 1);
184020
- firstInline = false;
184051
+ renderList(doc, sub, fonts, depth + 1);
184021
184052
  } else {
184022
- renderToken(doc, sub, fontFamily);
184023
- firstInline = false;
184053
+ renderToken(doc, sub, fonts);
184024
184054
  }
184025
184055
  }
184026
184056
  if (!drewAnything && item.text) {
184027
- doc.font(fontFamily).text(String(item.text), doc.x, doc.y, {
184057
+ doc.font(fonts.regularFamily).text(String(item.text), doc.x, doc.y, {
184028
184058
  width: itemWidth - markerWidth
184029
184059
  });
184030
184060
  doc.y += lineHeightOf(doc);
@@ -184035,9 +184065,9 @@ function renderList(doc, tok, fontFamily, depth) {
184035
184065
  }
184036
184066
  doc.y += SPACE2.LIST_AFTER;
184037
184067
  }
184038
- function drawInlineInBox(doc, tokens, fontFamily, x3, y2, width) {
184068
+ function drawInlineInBox(doc, tokens, fonts, x3, y2, width) {
184039
184069
  const text = inlineToPlainText(tokens);
184040
- doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fontFamily);
184070
+ doc.fontSize(BODY_FONT_SIZE).fillColor("#222").font(fonts.regularFamily);
184041
184071
  if (!text) return;
184042
184072
  const lineHeight = lineHeightOf(doc);
184043
184073
  const height = doc.heightOfString(text, { width });
@@ -184046,7 +184076,7 @@ function drawInlineInBox(doc, tokens, fontFamily, x3, y2, width) {
184046
184076
  doc.y += lineHeight;
184047
184077
  void lines;
184048
184078
  }
184049
- function renderTable(doc, tok, fontFamily) {
184079
+ function renderTable(doc, tok, fonts) {
184050
184080
  const header = tok.header ?? [];
184051
184081
  const rows = tok.rows ?? [];
184052
184082
  if (!header.length && !rows.length) return;
@@ -184065,7 +184095,7 @@ function renderTable(doc, tok, fontFamily) {
184065
184095
  if (totalColWidth > width) colWidth = width / colCount;
184066
184096
  const cellPadding = 4;
184067
184097
  const rowMinHeight = 14;
184068
- doc.fontSize(10).font(fontFamily).fillColor("#222");
184098
+ doc.fontSize(10).font(fonts.regularFamily).fillColor("#222");
184069
184099
  doc.y += SPACE2.TABLE_BEFORE;
184070
184100
  const drawRow = (cells, y3, isHeader) => {
184071
184101
  const texts = [];
@@ -184121,9 +184151,9 @@ function renderHr(doc) {
184121
184151
  doc.y = y2 + SPACE2.HR_AFTER;
184122
184152
  }
184123
184153
  function writePdfToTempFile(buffer) {
184124
- const path2 = join3(tmpdir(), `${randomUUID()}.pdf`);
184125
- writeFileSync3(path2, buffer);
184126
- return path2;
184154
+ const path3 = join4(tmpdir(), `${randomUUID()}.pdf`);
184155
+ writeFileSync3(path3, buffer);
184156
+ return path3;
184127
184157
  }
184128
184158
 
184129
184159
  // src/tools/jira-attach.ts
@@ -184162,20 +184192,37 @@ var registerJiraAttachTools = (ctx2) => {
184162
184192
  const { server: server2, jira: jira2 } = ctx2;
184163
184193
  server2.tool(
184164
184194
  "markdown_to_pdf",
184165
- "\uB9C8\uD06C\uB2E4\uC6B4\uC744 PDF\uB85C \uBCC0\uD658 (\uC2DC\uC2A4\uD15C \uD3F0\uD2B8 \uC790\uB3D9 \uAC10\uC9C0, \uD45C\uC9C0/\uBA38\uB9AC\uB9D0\xB7\uAF2C\uB9AC\uB9D0 \uC635\uC158). Jira \uCCA8\uBD80 \uC5C6\uC774 PDF \uACB0\uACFC\uB9CC \uBC18\uD658.",
184195
+ "\uB9C8\uD06C\uB2E4\uC6B4\uC744 PDF\uB85C \uBCC0\uD658 (\uBC88\uB4E4 Pretendard Regular+Bold, \uD45C\uC9C0/\uBA38\uB9AC\uB9D0\xB7\uAF2C\uB9AC\uB9D0 \uC635\uC158). Jira \uCCA8\uBD80 \uC5C6\uC774 PDF \uACB0\uACFC\uB9CC \uBC18\uD658.",
184166
184196
  {
184167
- markdown: external_exports.string().describe("PDF\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uBCF8\uBB38"),
184197
+ markdown: external_exports.string().optional().describe("PDF\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uBCF8\uBB38 (inline). markdown_file\uACFC \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00."),
184198
+ 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."),
184168
184199
  title: external_exports.string().optional().describe('\uBA38\uB9AC\uB9D0\xB7\uD45C\uC9C0\uC5D0 \uD45C\uC2DC\uD560 \uC81C\uBAA9 (\uAE30\uBCF8: source_ref \uB610\uB294 "Document")'),
184169
184200
  source_ref: external_exports.string().optional().describe('\uAF2C\uB9AC\uB9D0\xB7\uD45C\uC9C0 \uD478\uD130\uC5D0 \uD45C\uC2DC\uD560 \uCD9C\uCC98 (\uC608: "DYN-100 \xB7 2026-07-14")'),
184170
184201
  include_cover: external_exports.boolean().optional().default(false).describe("\uD45C\uC9C0 \uD398\uC774\uC9C0 \uD3EC\uD568 \uC5EC\uBD80 (\uAE30\uBCF8 false)"),
184171
184202
  author: external_exports.string().optional().describe('PDF /Author \uBA54\uD0C0 (\uAE30\uBCF8 "jira-mcp-server")'),
184172
- font_path: external_exports.string().optional().describe("\uD3F0\uD2B8 \uD30C\uC77C \uC808\uB300 \uACBD\uB85C (.ttf/.otf/.ttc). \uBBF8\uC9C0\uC815 \uC2DC \uC2DC\uC2A4\uD15C \uD3F0\uD2B8 \uC790\uB3D9 \uAC10\uC9C0"),
184203
+ 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)"),
184173
184204
  font_family_name: external_exports.string().optional().describe('pdfkit registerFont \uC774\uB984 (\uAE30\uBCF8 "BodyFont")'),
184174
184205
  page_size: external_exports.enum(["A4", "LETTER", "LEGAL"]).optional().default("A4").describe("\uD398\uC774\uC9C0 \uD06C\uAE30"),
184175
184206
  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)")
184176
184207
  },
184177
- async ({ markdown, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode }) => {
184178
- const result = await markdownToPdf(markdown, {
184208
+ async ({ markdown, markdown_file, title, source_ref, include_cover, author, font_path, font_family_name, page_size, output_mode }) => {
184209
+ if (!markdown && !markdown_file) {
184210
+ throw new Error("Either markdown or markdown_file must be provided");
184211
+ }
184212
+ if (markdown && markdown_file) {
184213
+ throw new Error("Provide either markdown or markdown_file, not both");
184214
+ }
184215
+ let md;
184216
+ if (markdown_file) {
184217
+ try {
184218
+ md = readFileSync4(markdown_file, "utf8");
184219
+ } catch (err) {
184220
+ throw new Error(`Failed to read markdown_file "${markdown_file}": ${err?.message ?? err}`);
184221
+ }
184222
+ } else {
184223
+ md = markdown;
184224
+ }
184225
+ const result = await markdownToPdf(md, {
184179
184226
  ...title !== void 0 ? { title } : {},
184180
184227
  ...source_ref !== void 0 ? { sourceRef: source_ref } : {},
184181
184228
  includeCover: include_cover,
@@ -184187,9 +184234,9 @@ var registerJiraAttachTools = (ctx2) => {
184187
184234
  });
184188
184235
  const buffer = result.buffer;
184189
184236
  if (output_mode === "tmpfile") {
184190
- const path2 = writePdfToTempFile(buffer);
184237
+ const path3 = writePdfToTempFile(buffer);
184191
184238
  const payload2 = {
184192
- path: path2,
184239
+ path: path3,
184193
184240
  bytes: buffer.length,
184194
184241
  encoding: "utf8"
184195
184242
  };
@@ -184266,7 +184313,8 @@ var registerJiraAttachTools = (ctx2) => {
184266
184313
  "\uB9C8\uD06C\uB2E4\uC6B4 \u2192 PDF \uBCC0\uD658 \u2192 Jira \uCCA8\uBD80 \uC6D0\uC0F7. description\uC740 \uC218\uC815\uD558\uC9C0 \uC54A\uC73C\uBA70, summary \uC635\uC158\uC774 \uC788\uC73C\uBA74 \uCF54\uBA58\uD2B8\uB85C \uAC8C\uC2DC.",
184267
184314
  {
184268
184315
  issue_key: external_exports.string().describe("Jira \uC774\uC288 \uD0A4 (\uC608: DYN-100)"),
184269
- markdown: external_exports.string().describe("PDF\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uBCF8\uBB38"),
184316
+ markdown: external_exports.string().optional().describe("PDF\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uBCF8\uBB38 (inline). markdown_file\uACFC \uB3D9\uC2DC \uC0AC\uC6A9 \uBD88\uAC00."),
184317
+ 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."),
184270
184318
  filename: external_exports.string().optional().default(DEFAULT_PDF_FILENAME).describe('\uCCA8\uBD80 \uD30C\uC77C\uBA85 (\uAE30\uBCF8 "document.pdf")'),
184271
184319
  summary: external_exports.string().optional().describe("\uCF54\uBA58\uD2B8\uB85C \uAC8C\uC2DC\uD560 \uC694\uC57D (Markdown ADF \uBCC0\uD658, description\uC740 \uBBF8\uC218\uC815)"),
184272
184320
  // pdfkit 옵션 위임 — title/source_ref/include_cover/author/font_path/font_family_name/page_size
@@ -184281,6 +184329,7 @@ var registerJiraAttachTools = (ctx2) => {
184281
184329
  async ({
184282
184330
  issue_key,
184283
184331
  markdown,
184332
+ markdown_file,
184284
184333
  filename,
184285
184334
  summary,
184286
184335
  title,
@@ -184291,7 +184340,23 @@ var registerJiraAttachTools = (ctx2) => {
184291
184340
  font_family_name,
184292
184341
  page_size
184293
184342
  }) => {
184294
- const result = await markdownToPdf(markdown, {
184343
+ if (!markdown && !markdown_file) {
184344
+ throw new Error("Either markdown or markdown_file must be provided");
184345
+ }
184346
+ if (markdown && markdown_file) {
184347
+ throw new Error("Provide either markdown or markdown_file, not both");
184348
+ }
184349
+ let md;
184350
+ if (markdown_file) {
184351
+ try {
184352
+ md = readFileSync4(markdown_file, "utf8");
184353
+ } catch (err) {
184354
+ throw new Error(`Failed to read markdown_file "${markdown_file}": ${err?.message ?? err}`);
184355
+ }
184356
+ } else {
184357
+ md = markdown;
184358
+ }
184359
+ const result = await markdownToPdf(md, {
184295
184360
  ...title !== void 0 ? { title } : {},
184296
184361
  ...source_ref !== void 0 ? { sourceRef: source_ref } : {},
184297
184362
  includeCover: include_cover,
@@ -184575,6 +184640,40 @@ var registerExpertTools = (ctx2) => {
184575
184640
  );
184576
184641
  };
184577
184642
 
184643
+ // src/tools/review-criteria.ts
184644
+ import { readFileSync as readFileSync5 } from "fs";
184645
+ import { fileURLToPath as fileURLToPath3 } from "url";
184646
+ import path2 from "path";
184647
+ var __dirname3 = path2.dirname(fileURLToPath3(import.meta.url));
184648
+ var CRITERIA_PATH = path2.resolve(__dirname3, "../data/review-criteria.md");
184649
+ var registerReviewCriteriaTools = (ctx2) => {
184650
+ ctx2.server.tool(
184651
+ "review_get_criteria",
184652
+ "[\uBB38\uC11C \uB9AC\uBDF0\xB7soft verdict] document-content-reviewer\xB7requirement-coverage-tracker\uC758 \uD3C9\uAC00 \uAE30\uC900(\uB808\uC774\uC5B4 \u2461) \uBC18\uD658. \uC758\uB8CC\uAE30\uAE30 \uD45C\uC900 \uAE30\uBC18 generic \uAE30\uBCF8 \u2014 consumer cwd\uC758 data/review-criteria.md(\uD504\uB85C\uC81D\uD2B8 \uC624\uBC84\uB77C\uC774\uB4DC)\uAC00 \uBCC4\uB3C4 \uC874\uC7AC\uD558\uBA74 subagent\uAC00 \uADF8\uAC83\uC744 \uCD94\uAC00 Read\uB85C \uBCF4\uC644. \uB9E4 \uD638\uCD9C \uC2DC \uB514\uC2A4\uD06C\uC5D0\uC11C \uC77D\uC74C(watch rebuild/installPath \uAC31\uC2E0 \uBC18\uC601).",
184653
+ {},
184654
+ async () => {
184655
+ let body;
184656
+ try {
184657
+ body = readFileSync5(CRITERIA_PATH, "utf8");
184658
+ } catch (err) {
184659
+ body = [
184660
+ "# Review Criteria \u2014 \uB85C\uB4DC \uC2E4\uD328",
184661
+ "",
184662
+ `\uACBD\uB85C: ${CRITERIA_PATH}`,
184663
+ `\uC624\uB958: ${err?.message ?? err}`,
184664
+ "",
184665
+ "plugin \uBC88\uB4E4\uC5D0 data/review-criteria.md\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
184666
+ '- package.json files \uBC30\uC5F4\uC5D0 "data" \uD3EC\uD568 \uC5EC\uBD80 \uD655\uC778.',
184667
+ "- installPath(dist/index.js \uC606)\uC5D0 data/ \uB514\uB809\uD130\uB9AC \uC874\uC7AC \uC5EC\uBD80 \uD655\uC778.",
184668
+ "",
184669
+ "\uD3C9\uAC00\uB294 \uACC4\uC18D \uAC00\uB2A5\uD558\uB098 generic \uAE30\uC900 \uC5C6\uC774 subagent\uC758 \uC77C\uBC18\uC801 LLM \uD3C9\uAC00\uB85C\uB9CC \uC9C4\uD589\uB429\uB2C8\uB2E4. findings\uC758 \uC2E0\uB8B0\uB3C4\uAC00 \uB0AE\uC544\uC9C8 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
184670
+ ].join("\n");
184671
+ }
184672
+ return { content: [{ type: "text", text: body }] };
184673
+ }
184674
+ );
184675
+ };
184676
+
184578
184677
  // src/index.ts
184579
184678
  var jiraUrl = process.env.JIRA_URL || "";
184580
184679
  var jiraEmail = process.env.JIRA_EMAIL || "";
@@ -184592,7 +184691,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
184592
184691
  var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
184593
184692
  var server = new McpServer({
184594
184693
  name: "jira-confluence",
184595
- version: "0.1.15"
184694
+ version: "0.1.17"
184596
184695
  });
184597
184696
  var ctx = { server, jira, confluence, risk, xray };
184598
184697
  registerJiraCrudTools(ctx);
@@ -184609,6 +184708,7 @@ registerInitTools(ctx);
184609
184708
  registerDocRenderTools(ctx);
184610
184709
  registerJiraAttachTools(ctx);
184611
184710
  registerExpertTools(ctx);
184711
+ registerReviewCriteriaTools(ctx);
184612
184712
  var transport = new StdioServerTransport();
184613
184713
  server.connect(transport).catch((err) => {
184614
184714
  console.error("Failed to start MCP server:", err);