kordoc 4.2.9 → 4.3.0

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.
Files changed (166) hide show
  1. package/README.md +922 -885
  2. package/dist/{-ECUCTQTR.js → -DYHT3HWH.js} +28 -20
  3. package/dist/{chunk-J2RZ444H.js → chunk-3FFPHTXD.js} +1 -1
  4. package/dist/chunk-3FFPHTXD.js.map +1 -0
  5. package/dist/{chunk-27Z4PUZZ.js → chunk-4DBCUF3C.js} +38 -7
  6. package/dist/chunk-4DBCUF3C.js.map +1 -0
  7. package/dist/{chunk-5RPYBC2Q.js → chunk-6GBLFQMA.js} +1 -1
  8. package/dist/chunk-6GBLFQMA.js.map +1 -0
  9. package/dist/{chunk-VEHC4EJL.js → chunk-6RAYTNQT.js} +5 -5
  10. package/dist/chunk-6RAYTNQT.js.map +1 -0
  11. package/dist/{chunk-GEPINOL6.js → chunk-6XPXIG57.js} +2 -2
  12. package/dist/chunk-6XPXIG57.js.map +1 -0
  13. package/dist/{chunk-7ZARSBQ3.js → chunk-7MFO4TKP.js} +4 -3
  14. package/dist/chunk-7MFO4TKP.js.map +1 -0
  15. package/dist/{chunk-PATPZTH7.cjs → chunk-AL34DGS5.cjs} +6 -6
  16. package/dist/chunk-AL34DGS5.cjs.map +1 -0
  17. package/dist/{chunk-LXE7OR6N.js → chunk-ARXNKC5D.js} +3 -3
  18. package/dist/chunk-ARXNKC5D.js.map +1 -0
  19. package/dist/{chunk-6GM2QLM3.cjs → chunk-AUOEZKJE.cjs} +21 -21
  20. package/dist/chunk-AUOEZKJE.cjs.map +1 -0
  21. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  22. package/dist/{chunk-3TSTZGCJ.js → chunk-DRQUAYNT.js} +4 -3
  23. package/dist/chunk-DRQUAYNT.js.map +1 -0
  24. package/dist/{chunk-G3DMDTZI.js → chunk-DRZUJ2RK.js} +1511 -1135
  25. package/dist/chunk-DRZUJ2RK.js.map +1 -0
  26. package/dist/{chunk-NIISBGSR.js → chunk-EFVAY5VE.js} +71 -29
  27. package/dist/chunk-EFVAY5VE.js.map +1 -0
  28. package/dist/{chunk-3PLF5UIS.js → chunk-EZHW3RNQ.js} +37 -6
  29. package/dist/chunk-EZHW3RNQ.js.map +1 -0
  30. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  31. package/dist/{chunk-MHMVFI2N.js → chunk-GSMPTZC7.js} +4 -4
  32. package/dist/chunk-GSMPTZC7.js.map +1 -0
  33. package/dist/{chunk-GZ7W64QU.cjs → chunk-JFV7QT5T.cjs} +4 -3
  34. package/dist/chunk-JFV7QT5T.cjs.map +1 -0
  35. package/dist/{chunk-4ZWKFDUC.cjs → chunk-LPQWKQQQ.cjs} +44 -13
  36. package/dist/chunk-LPQWKQQQ.cjs.map +1 -0
  37. package/dist/{chunk-H7OWEYH2.cjs → chunk-MGGU3ZRK.cjs} +1 -1
  38. package/dist/chunk-MGGU3ZRK.cjs.map +1 -0
  39. package/dist/chunk-MOL7MDBG.js +0 -0
  40. package/dist/{chunk-XU4VWOKL.js → chunk-NMWXBJ5B.js} +4 -3
  41. package/dist/chunk-NMWXBJ5B.js.map +1 -0
  42. package/dist/{chunk-DZIXKL7E.js → chunk-O5EK52TG.js} +1 -1
  43. package/dist/chunk-O5EK52TG.js.map +1 -0
  44. package/dist/{chunk-KTPZYXN2.js → chunk-SPKBIFSK.js} +2 -2
  45. package/dist/chunk-SPKBIFSK.js.map +1 -0
  46. package/dist/{chunk-STYN45MS.js → chunk-US4WFSIQ.js} +4 -4
  47. package/dist/chunk-US4WFSIQ.js.map +1 -0
  48. package/dist/{chunk-WTT2KJOM.js → chunk-VXMLENCV.js} +14 -10
  49. package/dist/chunk-VXMLENCV.js.map +1 -0
  50. package/dist/{chunk-7FCNOKOR.js → chunk-W34QSJFF.js} +1 -1
  51. package/dist/chunk-W34QSJFF.js.map +1 -0
  52. package/dist/{chunk-YR4PF56B.js → chunk-WFOQFJI4.js} +2 -2
  53. package/dist/chunk-WFOQFJI4.js.map +1 -0
  54. package/dist/{chunk-NNDVFNMJ.js → chunk-YNJDNP44.js} +1 -1
  55. package/dist/chunk-YNJDNP44.js.map +1 -0
  56. package/dist/{chunk-LM7C6HI2.js → chunk-ZSL6MQVE.js} +1 -1
  57. package/dist/chunk-ZSL6MQVE.js.map +1 -0
  58. package/dist/chunks-Q7T4SQGW.js +10 -0
  59. package/dist/cli.js +75 -39
  60. package/dist/cli.js.map +1 -1
  61. package/dist/{formula-SXC6LRRC.js → formula-7ZPC54JO.js} +2 -2
  62. package/dist/formula-7ZPC54JO.js.map +1 -0
  63. package/dist/{formula-KSNAEBZ2.js → formula-EQRHSMYW.js} +2 -2
  64. package/dist/formula-EQRHSMYW.js.map +1 -0
  65. package/dist/{formula-SB3NHDUM.cjs → formula-IWV5IJ3Y.cjs} +8 -8
  66. package/dist/formula-IWV5IJ3Y.cjs.map +1 -0
  67. package/dist/{image-ocr-PS7XCV6K.js → image-ocr-G2LYTEUH.js} +8 -6
  68. package/dist/image-ocr-G2LYTEUH.js.map +1 -0
  69. package/dist/{image-ocr-KZTNJ62U.js → image-ocr-R44RYDBU.js} +10 -8
  70. package/dist/image-ocr-R44RYDBU.js.map +1 -0
  71. package/dist/{image-ocr-J5656BEE.cjs → image-ocr-XEJFXH6M.cjs} +13 -11
  72. package/dist/image-ocr-XEJFXH6M.cjs.map +1 -0
  73. package/dist/index.cjs +1993 -1845
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.cts +75 -4
  76. package/dist/index.d.ts +75 -4
  77. package/dist/index.js +2128 -1980
  78. package/dist/index.js.map +1 -1
  79. package/dist/mcp.js +123 -78
  80. package/dist/mcp.js.map +1 -1
  81. package/dist/{models-KA4GLQK5.js → models-6VMAVZR6.js} +3 -3
  82. package/dist/page-range-737B4EZW.js +0 -0
  83. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  84. package/dist/{parser-A34NAYKA.js → parser-2G245MMN.js} +6 -6
  85. package/dist/parser-2G245MMN.js.map +1 -0
  86. package/dist/{parser-WNFWMBSL.js → parser-W3POOYQQ.js} +8 -8
  87. package/dist/parser-W3POOYQQ.js.map +1 -0
  88. package/dist/{parser-CSYU3CAW.cjs → parser-W3ZGQUCQ.cjs} +25 -25
  89. package/dist/parser-W3ZGQUCQ.cjs.map +1 -0
  90. package/dist/pdf-ocr-3GDTJSHF.js +15 -0
  91. package/dist/pdf-ocr-N7IU23UV.cjs +13 -0
  92. package/dist/pdf-ocr-N7IU23UV.cjs.map +1 -0
  93. package/dist/pdf-ocr-U7MEGNBZ.js +12 -0
  94. package/dist/{profile-io-43MF52H6.js → profile-io-72R3B7KO.js} +3 -3
  95. package/dist/{rasterize-OG7KXBJS.js → rasterize-GNJQVURE.js} +2 -2
  96. package/dist/rasterize-GNJQVURE.js.map +1 -0
  97. package/dist/{redact-7ILEAUTS.js → redact-W5K3ILQH.js} +2 -2
  98. package/dist/render-6OW6U4L4.js +10 -0
  99. package/dist/seal-GTNLVBJX.js +10 -0
  100. package/dist/{setup-GUQT5ELJ.js → setup-I4I75QJU.js} +1 -1
  101. package/dist/setup-I4I75QJU.js.map +1 -0
  102. package/dist/{watch-SOHQMZN2.js → watch-2ADAJLIJ.js} +12 -14
  103. package/dist/watch-2ADAJLIJ.js.map +1 -0
  104. package/package.json +101 -98
  105. package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
  106. package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +9 -0
  107. package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
  108. package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +25 -0
  109. package/dist/chunk-27Z4PUZZ.js.map +0 -1
  110. package/dist/chunk-3PLF5UIS.js.map +0 -1
  111. package/dist/chunk-3TSTZGCJ.js.map +0 -1
  112. package/dist/chunk-4ZWKFDUC.cjs.map +0 -1
  113. package/dist/chunk-5RPYBC2Q.js.map +0 -1
  114. package/dist/chunk-6GM2QLM3.cjs.map +0 -1
  115. package/dist/chunk-7FCNOKOR.js.map +0 -1
  116. package/dist/chunk-7ZARSBQ3.js.map +0 -1
  117. package/dist/chunk-DZIXKL7E.js.map +0 -1
  118. package/dist/chunk-G3DMDTZI.js.map +0 -1
  119. package/dist/chunk-GEPINOL6.js.map +0 -1
  120. package/dist/chunk-GZ7W64QU.cjs.map +0 -1
  121. package/dist/chunk-H7OWEYH2.cjs.map +0 -1
  122. package/dist/chunk-J2RZ444H.js.map +0 -1
  123. package/dist/chunk-KTPZYXN2.js.map +0 -1
  124. package/dist/chunk-LM7C6HI2.js.map +0 -1
  125. package/dist/chunk-LXE7OR6N.js.map +0 -1
  126. package/dist/chunk-MHMVFI2N.js.map +0 -1
  127. package/dist/chunk-NIISBGSR.js.map +0 -1
  128. package/dist/chunk-NNDVFNMJ.js.map +0 -1
  129. package/dist/chunk-PATPZTH7.cjs.map +0 -1
  130. package/dist/chunk-STYN45MS.js.map +0 -1
  131. package/dist/chunk-TCJRGFYY.js +0 -280
  132. package/dist/chunk-TCJRGFYY.js.map +0 -1
  133. package/dist/chunk-VEHC4EJL.js.map +0 -1
  134. package/dist/chunk-WTT2KJOM.js.map +0 -1
  135. package/dist/chunk-XU4VWOKL.js.map +0 -1
  136. package/dist/chunk-YR4PF56B.js.map +0 -1
  137. package/dist/chunks-VFIMYK36.js +0 -10
  138. package/dist/detect-FX2ZHKZP.js +0 -26
  139. package/dist/formula-KSNAEBZ2.js.map +0 -1
  140. package/dist/formula-SB3NHDUM.cjs.map +0 -1
  141. package/dist/formula-SXC6LRRC.js.map +0 -1
  142. package/dist/image-ocr-J5656BEE.cjs.map +0 -1
  143. package/dist/image-ocr-KZTNJ62U.js.map +0 -1
  144. package/dist/image-ocr-PS7XCV6K.js.map +0 -1
  145. package/dist/parser-A34NAYKA.js.map +0 -1
  146. package/dist/parser-CSYU3CAW.cjs.map +0 -1
  147. package/dist/parser-WNFWMBSL.js.map +0 -1
  148. package/dist/pdf-ocr-KBMWPG2L.js +0 -12
  149. package/dist/pdf-ocr-NPZG67FN.js +0 -15
  150. package/dist/pdf-ocr-O44DAGTY.cjs +0 -13
  151. package/dist/pdf-ocr-O44DAGTY.cjs.map +0 -1
  152. package/dist/rasterize-OG7KXBJS.js.map +0 -1
  153. package/dist/render-336CJHAS.js +0 -10
  154. package/dist/seal-TM2XCE2R.js +0 -10
  155. package/dist/seal-TM2XCE2R.js.map +0 -1
  156. package/dist/setup-GUQT5ELJ.js.map +0 -1
  157. package/dist/watch-SOHQMZN2.js.map +0 -1
  158. /package/dist/{-ECUCTQTR.js.map → -DYHT3HWH.js.map} +0 -0
  159. /package/dist/{chunks-VFIMYK36.js.map → chunks-Q7T4SQGW.js.map} +0 -0
  160. /package/dist/{detect-FX2ZHKZP.js.map → models-6VMAVZR6.js.map} +0 -0
  161. /package/dist/{models-KA4GLQK5.js.map → pdf-ocr-3GDTJSHF.js.map} +0 -0
  162. /package/dist/{pdf-ocr-KBMWPG2L.js.map → pdf-ocr-U7MEGNBZ.js.map} +0 -0
  163. /package/dist/{pdf-ocr-NPZG67FN.js.map → profile-io-72R3B7KO.js.map} +0 -0
  164. /package/dist/{profile-io-43MF52H6.js.map → redact-W5K3ILQH.js.map} +0 -0
  165. /package/dist/{redact-7ILEAUTS.js.map → render-6OW6U4L4.js.map} +0 -0
  166. /package/dist/{render-336CJHAS.js.map → seal-GTNLVBJX.js.map} +0 -0
package/dist/mcp.js CHANGED
@@ -14,10 +14,14 @@ import {
14
14
  SIZE_KEYS,
15
15
  SIZE_PT_RANGE,
16
16
  buildGongmunOptions
17
- } from "./chunk-5RPYBC2Q.js";
17
+ } from "./chunk-6GBLFQMA.js";
18
18
  import {
19
+ BUILTIN_TEMPLATES,
19
20
  PRESET_ALIAS,
20
21
  compare,
22
+ detectFormat,
23
+ detectOle2Format,
24
+ detectZipFormat,
21
25
  extractFormFields,
22
26
  extractHwp5MetadataOnly,
23
27
  extractHwpxMetadataOnly,
@@ -30,36 +34,35 @@ import {
30
34
  parse,
31
35
  patchHwp,
32
36
  patchHwpx,
37
+ readBuiltinTemplate,
38
+ resolveBuiltinTemplate,
33
39
  unknownFontWarnings
34
- } from "./chunk-G3DMDTZI.js";
35
- import "./chunk-7FCNOKOR.js";
36
- import "./chunk-LM7C6HI2.js";
37
- import {
38
- detectFormat,
39
- detectZipFormat
40
- } from "./chunk-TCJRGFYY.js";
40
+ } from "./chunk-DRZUJ2RK.js";
41
+ import "./chunk-W34QSJFF.js";
42
+ import "./chunk-ZSL6MQVE.js";
41
43
  import "./chunk-MOL7MDBG.js";
42
- import "./chunk-XU4VWOKL.js";
43
- import "./chunk-DZIXKL7E.js";
44
- import "./chunk-KTPZYXN2.js";
44
+ import "./chunk-NMWXBJ5B.js";
45
+ import "./chunk-O5EK52TG.js";
46
+ import "./chunk-SPKBIFSK.js";
45
47
  import {
46
48
  blocksToMarkdown
47
- } from "./chunk-MHMVFI2N.js";
48
- import "./chunk-WTT2KJOM.js";
49
- import "./chunk-NIISBGSR.js";
49
+ } from "./chunk-GSMPTZC7.js";
50
+ import "./chunk-VXMLENCV.js";
51
+ import "./chunk-EFVAY5VE.js";
50
52
  import {
51
53
  KordocError,
52
54
  VERSION,
53
55
  classifyError,
54
56
  sanitizeError,
55
57
  toArrayBuffer
56
- } from "./chunk-3TSTZGCJ.js";
58
+ } from "./chunk-DRQUAYNT.js";
57
59
 
58
60
  // src/mcp.ts
59
61
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
60
62
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
61
63
  import { z } from "zod";
62
- import { readFileSync, writeFileSync, realpathSync, openSync, readSync, closeSync, statSync, mkdirSync, existsSync } from "fs";
64
+ import { realpathSync, openSync, readSync, closeSync, existsSync } from "fs";
65
+ import { readFile, writeFile, mkdir, stat } from "fs/promises";
63
66
  import { pathToFileURL } from "url";
64
67
  import { resolve, isAbsolute, extname, dirname, basename } from "path";
65
68
  var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".hwp", ".hwpx", ".hml", ".pdf", ".xls", ".xlsx", ".docx"]);
@@ -124,11 +127,11 @@ function capResponseText(text, maxChars = MAX_RESPONSE_CHARS) {
124
127
  \u2026 [\uC751\uB2F5\uC774 ${maxChars.toLocaleString()}\uC790 \uC0C1\uD55C\uC744 \uB118\uC5B4 \uC808\uB2E8\uB428 (\uC804\uCCB4 ${text.length.toLocaleString()}\uC790) \u2014 parse_pages\uB85C \uD398\uC774\uC9C0 \uBC94\uC704\uB97C \uB098\uB220 \uC77D\uC73C\uC138\uC694]`;
125
128
  }
126
129
  var MAX_METADATA_FILE_SIZE = 50 * 1024 * 1024;
127
- function readValidatedFile(filePath, maxSize = MAX_FILE_SIZE, allowedExts = ALLOWED_EXTENSIONS) {
130
+ async function readValidatedFile(filePath, maxSize = MAX_FILE_SIZE, allowedExts = ALLOWED_EXTENSIONS) {
128
131
  const resolved = safePath(filePath, allowedExts);
129
132
  let fileSize;
130
133
  try {
131
- fileSize = statSync(resolved).size;
134
+ fileSize = (await stat(resolved)).size;
132
135
  } catch (err) {
133
136
  throw new KordocError(`\uD30C\uC77C \uC0C1\uD0DC \uC77D\uAE30 \uC2E4\uD328 [${err?.code ?? "UNKNOWN"}]: ${resolved}`);
134
137
  }
@@ -137,7 +140,7 @@ function readValidatedFile(filePath, maxSize = MAX_FILE_SIZE, allowedExts = ALLO
137
140
  }
138
141
  let raw;
139
142
  try {
140
- raw = readFileSync(resolved);
143
+ raw = await readFile(resolved);
141
144
  } catch (err) {
142
145
  throw new KordocError(`\uD30C\uC77C \uC77D\uAE30 \uC2E4\uD328 [${err?.code ?? "UNKNOWN"}]: ${resolved}`);
143
146
  }
@@ -162,11 +165,16 @@ server.tool(
162
165
  "\uD55C\uAD6D \uBB38\uC11C \uD30C\uC77C(HWP, HWPX, PDF, XLSX, DOCX)\uACFC \uC774\uBBF8\uC9C0(PNG/JPG/WebP)\uB97C \uB9C8\uD06C\uB2E4\uC6B4\uC73C\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. \uD30C\uC77C \uACBD\uB85C\uB97C \uC785\uB825\uD558\uBA74 \uD3EC\uB9F7\uC744 \uC790\uB3D9 \uAC10\uC9C0\uD558\uC5EC \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uC774\uBBF8\uC9C0\uB294 OCR(\uB0B4\uC7A5 PP-OCRv5)\uC774 \uC790\uB3D9 \uC801\uC6A9\uB418\uACE0 \uD45C \uAD18\uC120\uB3C4 \uBCF5\uC6D0\uB429\uB2C8\uB2E4.",
163
166
  {
164
167
  file_path: z.string().min(1).describe("\uD30C\uC2F1\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP)"),
165
- ocr: z.boolean().optional().describe("\uC2A4\uCE94/\uC774\uBBF8\uC9C0 PDF \uD14D\uC2A4\uD2B8 OCR (\uB0B4\uC7A5 PP-OCRv5 korean, \uCCAB \uC0AC\uC6A9 \uC2DC ~18MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC). \uD14D\uC2A4\uD2B8\uCE35\uC774 \uC5C6\uAC70\uB098 \uAE68\uC9C4 \uD398\uC774\uC9C0\uB9CC \uC778\uC2DD\uD558\uACE0 \uC815\uC0C1 \uD398\uC774\uC9C0\uB294 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4. parse \uACB0\uACFC\uC5D0 NEEDS_OCR \uACBD\uACE0\uAC00 \uC788\uC73C\uBA74 \uC774 \uC635\uC158\uC73C\uB85C \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694")
168
+ ocr: z.union([z.boolean(), z.literal("force")]).optional().describe('\uC2A4\uCE94/\uC774\uBBF8\uC9C0 PDF \uD14D\uC2A4\uD2B8 OCR (\uB0B4\uC7A5 PP-OCRv5 korean, \uCCAB \uC0AC\uC6A9 \uC2DC ~18MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC). true=\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC5C6\uAC70\uB098 \uAE68\uC9C4 \uD398\uC774\uC9C0\uB9CC \uC778\uC2DD\uD558\uACE0 \uC815\uC0C1 \uD398\uC774\uC9C0\uB294 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4. "force"=\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC788\uC5B4\uB3C4 \uBB34\uC2DC\uD558\uACE0 \uC804 \uD398\uC774\uC9C0 \uAC15\uC81C \uC7AC\uC778\uC2DD. parse \uACB0\uACFC\uC5D0 NEEDS_OCR \uACBD\uACE0\uAC00 \uC788\uC73C\uBA74 \uC774 \uC635\uC158\uC73C\uB85C \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694'),
169
+ remove_header_footer: z.boolean().optional().describe("PDF \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC790\uB3D9 \uC81C\uAC70 (\uAE30\uBCF8 true \u2014 false\uB85C \uB044\uAE30, CLI --no-header-footer \uB300\uC751)"),
170
+ formula_ocr: z.boolean().optional().describe("PDF \uC218\uC2DD OCR \uD65C\uC131\uD654 (MFD+MFR ONNX, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~155MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC, CLI --formula-ocr \uB300\uC751)"),
171
+ dedupe_running_headers: z.boolean().optional().describe("HWP5 \uB808\uC774\uC544\uC6C3 \uD45C \uD398\uC774\uC9C0 \uBC18\uBCF5 \uB7EC\uB2DD \uD5E4\uB354 \uC911\uBCF5 \uC81C\uAC70 (\uAE30\uBCF8 off \u2014 \uBD99\uC784\uBCC4 \uC7AC\uBC88\uD638 \uC624\uC0AD\uC81C \uC8FC\uC758, CLI --dedupe-headers \uB300\uC751)"),
172
+ keep_trailing_empty_cols: z.boolean().optional().describe("\uD45C \uC624\uB978\uCABD \uB05D \uBE48 \uC5F4(\uC11C\uC2DD \uC785\uB825\uB780) \uBCF4\uC874 (#47, \uAE30\uBCF8 off: \uD6C4\uD589 \uBE48 \uC5F4 \uD2B8\uB9BC, CLI --keep-empty-cols \uB300\uC751)"),
173
+ keep_empty_paragraphs: z.boolean().optional().describe("\uBE48 \uBB38\uB2E8 \uBCF4\uC874 \u2014 \uBCF8\uBB38\uC740 \uBE48 paragraph \uBE14\uB85D, \uD45C \uC140\uC740 \uBE48 \uC904 (#57, \uAE30\uBCF8 off, CLI --keep-empty-paragraphs \uB300\uC751)")
166
174
  },
167
- async ({ file_path, ocr }) => {
175
+ async ({ file_path, ocr, remove_header_footer, formula_ocr, dedupe_running_headers, keep_trailing_empty_cols, keep_empty_paragraphs }) => {
168
176
  try {
169
- const { buffer, resolved } = readValidatedFile(file_path);
177
+ const { buffer, resolved } = await readValidatedFile(file_path);
170
178
  const format = detectFormat(buffer);
171
179
  if (format === "unknown") {
172
180
  return {
@@ -174,7 +182,15 @@ server.tool(
174
182
  isError: true
175
183
  };
176
184
  }
177
- const result = await parse(buffer, { filePath: resolved, ...ocr ? { ocr: true } : {} });
185
+ const result = await parse(buffer, {
186
+ filePath: resolved,
187
+ ...ocr !== void 0 ? { ocr } : {},
188
+ ...remove_header_footer !== void 0 ? { removeHeaderFooter: remove_header_footer } : {},
189
+ ...formula_ocr ? { formulaOcr: true } : {},
190
+ ...dedupe_running_headers ? { dedupeRunningHeaders: true } : {},
191
+ ...keep_trailing_empty_cols ? { keepTrailingEmptyCols: true } : {},
192
+ ...keep_empty_paragraphs ? { keepEmptyParagraphs: true } : {}
193
+ });
178
194
  if (!result.success) {
179
195
  return {
180
196
  content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328 (${result.fileType}): ${result.error}` }],
@@ -218,7 +234,7 @@ ${markdown}`);
218
234
  );
219
235
  server.tool(
220
236
  "detect_format",
221
- "\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, pdf, xlsx, docx, unknown).",
237
+ "\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, hwp3, hwpml, pdf, xls, xlsx, docx, unknown).",
222
238
  {
223
239
  file_path: z.string().min(1).describe("\uAC10\uC9C0\uD560 \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
224
240
  },
@@ -227,8 +243,12 @@ server.tool(
227
243
  const resolved = safePath(file_path);
228
244
  let format = detectFormatFromHeader(resolved);
229
245
  if (format === "hwpx") {
230
- const { buffer } = readValidatedFile(file_path);
246
+ const { buffer } = await readValidatedFile(file_path);
231
247
  format = await detectZipFormat(buffer);
248
+ } else if (format === "hwp") {
249
+ const { buffer } = await readValidatedFile(file_path);
250
+ const ole2Format = detectOle2Format(buffer);
251
+ if (ole2Format !== "unknown") format = ole2Format;
232
252
  }
233
253
  return {
234
254
  content: [{ type: "text", text: `${file_path}: ${format}` }]
@@ -257,13 +277,14 @@ server.tool(
257
277
  isError: true
258
278
  };
259
279
  }
260
- const { buffer } = readValidatedFile(file_path, MAX_METADATA_FILE_SIZE);
280
+ const { buffer } = await readValidatedFile(file_path, MAX_METADATA_FILE_SIZE);
261
281
  let metadata;
262
282
  let effectiveFormat = format;
263
283
  if (format === "hwpx") {
264
- const { detectZipFormat: detectZipFormat2 } = await import("./detect-FX2ZHKZP.js");
265
- const zipFormat = await detectZipFormat2(buffer);
284
+ const zipFormat = await detectZipFormat(buffer);
266
285
  if (zipFormat === "xlsx" || zipFormat === "docx") effectiveFormat = zipFormat;
286
+ } else if (format === "hwp") {
287
+ if (detectOle2Format(buffer) === "xls") effectiveFormat = "xls";
267
288
  }
268
289
  switch (effectiveFormat) {
269
290
  case "hwp":
@@ -274,7 +295,7 @@ server.tool(
274
295
  break;
275
296
  case "pdf":
276
297
  try {
277
- const { extractPdfMetadataOnly } = await import("./parser-WNFWMBSL.js");
298
+ const { extractPdfMetadataOnly } = await import("./parser-W3POOYQQ.js");
278
299
  metadata = await extractPdfMetadataOnly(buffer);
279
300
  } catch {
280
301
  metadata = void 0;
@@ -282,12 +303,16 @@ server.tool(
282
303
  break;
283
304
  case "hwp3":
284
305
  case "hwpml":
306
+ case "xls":
285
307
  case "xlsx":
286
308
  case "docx": {
287
309
  const result = await parse(buffer);
288
310
  metadata = result.success ? result.metadata : void 0;
289
311
  break;
290
312
  }
313
+ default:
314
+ metadata = void 0;
315
+ break;
291
316
  }
292
317
  return {
293
318
  content: [{ type: "text", text: JSON.stringify({ format, ...metadata }, null, 2) }]
@@ -309,7 +334,8 @@ server.tool(
309
334
  },
310
335
  async ({ file_path, pages }) => {
311
336
  try {
312
- const { buffer } = readValidatedFile(file_path);
337
+ const resolved = safePath(file_path);
338
+ const { buffer } = await readValidatedFile(file_path);
313
339
  const format = detectFormat(buffer);
314
340
  if (format === "unknown") {
315
341
  return {
@@ -317,7 +343,7 @@ server.tool(
317
343
  isError: true
318
344
  };
319
345
  }
320
- const result = await parse(buffer, { pages });
346
+ const result = await parse(buffer, { pages, filePath: resolved });
321
347
  if (!result.success) {
322
348
  return {
323
349
  content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328 (${result.fileType}): ${result.error}` }],
@@ -351,7 +377,7 @@ server.tool(
351
377
  },
352
378
  async ({ file_path, table_index }) => {
353
379
  try {
354
- const { buffer } = readValidatedFile(file_path);
380
+ const { buffer } = await readValidatedFile(file_path);
355
381
  const format = detectFormat(buffer);
356
382
  if (format === "unknown") {
357
383
  return {
@@ -403,8 +429,8 @@ server.tool(
403
429
  },
404
430
  async ({ file_path_a, file_path_b }) => {
405
431
  try {
406
- const { buffer: bufA } = readValidatedFile(file_path_a);
407
- const { buffer: bufB } = readValidatedFile(file_path_b);
432
+ const { buffer: bufA } = await readValidatedFile(file_path_a);
433
+ const { buffer: bufB } = await readValidatedFile(file_path_b);
408
434
  const result = await compare(bufA, bufB);
409
435
  const { stats, diffs } = result;
410
436
  const lines = [
@@ -437,7 +463,7 @@ server.tool(
437
463
  },
438
464
  async ({ file_path }) => {
439
465
  try {
440
- const { buffer } = readValidatedFile(file_path);
466
+ const { buffer } = await readValidatedFile(file_path);
441
467
  const result = await parse(buffer, { keepTrailingEmptyCols: true });
442
468
  if (!result.success) {
443
469
  return {
@@ -467,9 +493,10 @@ function buildFillInputs(fields, formats) {
467
493
  }
468
494
  server.tool(
469
495
  "fill_form",
470
- "\uD55C\uAD6D \uC11C\uC2DD \uBB38\uC11C\uC758 \uBE48\uCE78\uC744 \uCC44\uC6CC\uC11C \uC0C8 \uBB38\uC11C\uB85C \uCD9C\uB825\uD569\uB2C8\uB2E4. hwpx-preserve\uB97C \uC0AC\uC6A9\uD558\uBA74 \uC6D0\uBCF8 \uC11C\uC2DD(\uD14C\uB450\uB9AC, \uD3F0\uD2B8, \uBCD1\uD569 \uB4F1)\uC744 100% \uC720\uC9C0\uD569\uB2C8\uB2E4.",
496
+ "\uD55C\uAD6D \uC11C\uC2DD \uBB38\uC11C\uC758 \uBE48\uCE78\uC744 \uCC44\uC6CC\uC11C \uC0C8 \uBB38\uC11C\uB85C \uCD9C\uB825\uD569\uB2C8\uB2E4. hwpx-preserve\uB97C \uC0AC\uC6A9\uD558\uBA74 \uC6D0\uBCF8 \uC11C\uC2DD(\uD14C\uB450\uB9AC, \uD3F0\uD2B8, \uBCD1\uD569 \uB4F1)\uC744 100% \uC720\uC9C0\uD569\uB2C8\uB2E4. HWPX \uB204\uB984\uD2C0(CLICK_HERE) \uD544\uB4DC\uB294 \uC774\uB984\uC73C\uB85C \uC815\uD655 \uB9E4\uCE6D\uB418\uC5B4 \uC6B0\uC120 \uCC44\uC6CC\uC9D1\uB2C8\uB2E4. file_path \uB300\uC2E0 template\uC73C\uB85C \uB0B4\uC7A5 \uC815\uBD80 \uD45C\uC900 \uAE30\uC548\uBB38 \uC11C\uC2DD\uC744 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 gian(\uC77C\uBC18\uAE30\uC548\uBB38, \uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD: \uD589\uC815\uAE30\uAD00\uBA85\xB7\uC218\uC2E0\uC790\xB7\uACBD\uC720\xB7\uC81C\uBAA9\xB7\uBCF8\uBB38\xB7\uBD99\uC784\xB7\uBC1C\uC2E0\uBA85\uC758\xB7\uAE30\uC548\uC790\xB7\uAC80\uD1A0\uC790\xB7\uACB0\uC7AC\uAD8C\uC790 \uB4F1 23\uD544\uB4DC) / gian-simple(\uAC04\uC774\uAE30\uC548\uBB38, \uBCC4\uC9C0 \uC81C2\uD638\uC11C\uC2DD: \uB0B4\uBD80\uACB0\uC7AC\uC6A9 13\uD544\uB4DC).",
471
497
  {
472
- file_path: z.string().min(1).describe("\uC11C\uC2DD \uD15C\uD50C\uB9BF \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX)"),
498
+ file_path: z.string().min(1).optional().describe("\uC11C\uC2DD \uD15C\uD50C\uB9BF \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX). template \uC0AC\uC6A9 \uC2DC \uC0DD\uB7B5"),
499
+ template: z.enum(["gian", "gian-simple", "\uC77C\uBC18\uAE30\uC548\uBB38", "\uAC04\uC774\uAE30\uC548\uBB38"]).optional().describe("\uB0B4\uC7A5 \uC815\uBD80 \uD45C\uC900 \uC11C\uC2DD \uC774\uB984 \u2014 file_path \uB300\uC2E0 \uC0AC\uC6A9. gian=\uC77C\uBC18\uAE30\uC548\uBB38(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD), gian-simple=\uAC04\uC774\uAE30\uC548\uBB38(\uBCC4\uC9C0 \uC81C2\uD638\uC11C\uC2DD)"),
473
500
  fields: z.record(z.string(), z.string()).describe('\uCC44\uC6B8 \uD544\uB4DC \uB9F5 (\uB77C\uBCA8 \u2192 \uAC12). \uC608: {"\uC131\uBA85": "\uD64D\uAE38\uB3D9", "\uC804\uD654\uBC88\uD638": "010-1234-5678"}'),
474
501
  formats: z.record(z.string(), z.string()).optional().describe("\uD544\uB4DC\uBCC4 \uAC12 \uC11C\uC2DD (\uB77C\uBCA8 \u2192 \uD3EC\uB9F7). \uC815\uC900\uAC12 \uD558\uB098\uB85C \uC11C\uC2DD\uB9C8\uB2E4 \uB2E4\uB978 \uBAA8\uC591\uC744 \uCC44\uC6B8 \uB54C: date:yy.mm.dd / phone:hyphen\xB7dot\xB7digits / rrn:hyphen\xB7masked / mask:###-## / \uC790\uC720 \uD328\uD134(yyyy\uB144 m\uC6D4 d\uC77C, ###-####-####)"),
475
502
  require_unique: z.boolean().optional().describe("\uD55C \uD0A4\uAC00 \uC11C\uC2DD\uC758 2\uACF3 \uC774\uC0C1\uC5D0 \uB9E4\uCE6D\uB418\uBA74 \uCC44\uC6B0\uC9C0 \uC54A\uACE0 \uAC70\uBD80 \u2014 \uBC18\uBCF5 \uB77C\uBCA8 \uC591\uC2DD\uC5D0\uC11C \uB0A8\uC758 \uBE14\uB85D \uC624\uC5FC \uBC29\uC9C0 (\uBC30\uC5F4 \uAC12\uC740 \uC608\uC678)"),
@@ -477,11 +504,28 @@ server.tool(
477
504
  output_format: z.enum(["markdown", "hwpx", "hwpx-preserve"]).default("hwpx-preserve").describe("\uCD9C\uB825 \uD3EC\uB9F7: hwpx-preserve (\uC6D0\uBCF8 \uC2A4\uD0C0\uC77C \uBCF4\uC874, HWPX \uC804\uC6A9), hwpx (\uC0C8 HWPX \uC0DD\uC131), markdown"),
478
505
  output_path: z.string().optional().describe("\uCD9C\uB825 \uD30C\uC77C \uC800\uC7A5 \uACBD\uB85C (\uC120\uD0DD). \uC9C0\uC815 \uC2DC \uD30C\uC77C\uB85C \uC800\uC7A5, \uBBF8\uC9C0\uC815 \uC2DC \uD14D\uC2A4\uD2B8\uB85C \uBC18\uD658")
479
506
  },
480
- async ({ file_path, fields, formats, require_unique, mask_values, output_format, output_path }) => {
507
+ async ({ file_path, template, fields, formats, require_unique, mask_values, output_format, output_path }) => {
481
508
  try {
482
509
  const outExts = output_format === "markdown" ? /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]) : /* @__PURE__ */ new Set([".hwpx"]);
483
510
  const outPath = output_path ? safeOutputPath(output_path, outExts) : void 0;
484
- const { buffer } = readValidatedFile(file_path);
511
+ let buffer;
512
+ if (template) {
513
+ const t = resolveBuiltinTemplate(template);
514
+ if (!t) {
515
+ return {
516
+ content: [{ type: "text", text: `\uC54C \uC218 \uC5C6\uB294 \uB0B4\uC7A5 \uD15C\uD50C\uB9BF: ${template} (\uC0AC\uC6A9 \uAC00\uB2A5: ${BUILTIN_TEMPLATES.map((x) => `${x.id}(${x.aliases[0]})`).join(", ")})` }],
517
+ isError: true
518
+ };
519
+ }
520
+ buffer = readBuiltinTemplate(t);
521
+ } else if (file_path) {
522
+ buffer = (await readValidatedFile(file_path)).buffer;
523
+ } else {
524
+ return {
525
+ content: [{ type: "text", text: "file_path \uB610\uB294 template \uC911 \uD558\uB098\uB97C \uC9C0\uC815\uD574\uC8FC\uC138\uC694" }],
526
+ isError: true
527
+ };
528
+ }
485
529
  if (output_format === "hwpx-preserve") {
486
530
  const format = detectFormat(buffer);
487
531
  let isHwpx = format === "hwpx";
@@ -513,8 +557,8 @@ server.tool(
513
557
  ].filter(Boolean).join(" | ");
514
558
  const filledList = hwpxResult.filled.map((f) => ` - ${f.label}: ${mask_values ? `[${[...f.value].length}\uC790]` : f.value}`).join("\n");
515
559
  if (outPath) {
516
- mkdirSync(dirname(outPath), { recursive: true });
517
- writeFileSync(outPath, Buffer.from(hwpxResult.buffer));
560
+ await mkdir(dirname(outPath), { recursive: true });
561
+ await writeFile(outPath, Buffer.from(hwpxResult.buffer));
518
562
  return {
519
563
  content: [{ type: "text", text: `[${summary2}]
520
564
 
@@ -560,8 +604,8 @@ ${filledList}
560
604
  if (output_format === "hwpx") {
561
605
  const hwpxBuffer = await markdownToHwpx(markdown);
562
606
  if (outPath) {
563
- mkdirSync(dirname(outPath), { recursive: true });
564
- writeFileSync(outPath, Buffer.from(hwpxBuffer));
607
+ await mkdir(dirname(outPath), { recursive: true });
608
+ await writeFile(outPath, Buffer.from(hwpxBuffer));
565
609
  return {
566
610
  content: [{ type: "text", text: `[${summary}]
567
611
 
@@ -577,8 +621,8 @@ ${previewMd}` }]
577
621
  };
578
622
  }
579
623
  if (outPath) {
580
- mkdirSync(dirname(outPath), { recursive: true });
581
- writeFileSync(outPath, markdown, "utf-8");
624
+ await mkdir(dirname(outPath), { recursive: true });
625
+ await writeFile(outPath, markdown, "utf-8");
582
626
  return {
583
627
  content: [{ type: "text", text: `[${summary}]
584
628
 
@@ -617,7 +661,7 @@ server.tool(
617
661
  async ({ file_path, image_path, anchor, occurrence, size_mm, mode, dx_mm, dy_mm, output_path }) => {
618
662
  try {
619
663
  const outPath = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx"]));
620
- const { buffer } = readValidatedFile(file_path);
664
+ const { buffer } = await readValidatedFile(file_path);
621
665
  const format = detectFormat(buffer);
622
666
  if (format !== "hwpx") {
623
667
  return {
@@ -626,12 +670,13 @@ server.tool(
626
670
  };
627
671
  }
628
672
  const imgResolved = safePath(image_path, IMAGE_EXTENSIONS);
629
- if (statSync(imgResolved).size > 500 * 1024 * 1024) {
630
- return { content: [{ type: "text", text: `\uB3C4\uC7A5 \uC774\uBBF8\uC9C0\uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${(statSync(imgResolved).size / 1024 / 1024).toFixed(0)}MB) \u2014 500MB \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.` }], isError: true };
673
+ const imgSize = (await stat(imgResolved)).size;
674
+ if (imgSize > 500 * 1024 * 1024) {
675
+ return { content: [{ type: "text", text: `\uB3C4\uC7A5 \uC774\uBBF8\uC9C0\uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${(imgSize / 1024 / 1024).toFixed(0)}MB) \u2014 500MB \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.` }], isError: true };
631
676
  }
632
- const image = new Uint8Array(readFileSync(imgResolved));
677
+ const image = new Uint8Array(await readFile(imgResolved));
633
678
  const ext = extname(imgResolved).slice(1).toLowerCase();
634
- const { placeSealHwpx } = await import("./seal-TM2XCE2R.js");
679
+ const { placeSealHwpx } = await import("./seal-GTNLVBJX.js");
635
680
  const result = await placeSealHwpx(buffer, [{
636
681
  anchor,
637
682
  occurrence,
@@ -642,8 +687,8 @@ server.tool(
642
687
  dxMm: dx_mm,
643
688
  dyMm: dy_mm
644
689
  }]);
645
- mkdirSync(dirname(outPath), { recursive: true });
646
- writeFileSync(outPath, Buffer.from(result.buffer));
690
+ await mkdir(dirname(outPath), { recursive: true });
691
+ await writeFile(outPath, Buffer.from(result.buffer));
647
692
  const p0 = result.placed[0];
648
693
  const warnLines = (p0.warnings ?? []).map((w) => `
649
694
  \u26A0\uFE0F ${w}`).join("");
@@ -674,7 +719,7 @@ server.tool(
674
719
  async ({ file_path, edited_markdown, output_path }) => {
675
720
  try {
676
721
  const out = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
677
- const { buffer } = readValidatedFile(file_path);
722
+ const { buffer } = await readValidatedFile(file_path);
678
723
  const format = detectFormat(buffer);
679
724
  let isHwpx = format === "hwpx";
680
725
  if (isHwpx) {
@@ -695,8 +740,8 @@ server.tool(
695
740
  isError: true
696
741
  };
697
742
  }
698
- mkdirSync(dirname(out), { recursive: true });
699
- writeFileSync(out, Buffer.from(result.data));
743
+ await mkdir(dirname(out), { recursive: true });
744
+ await writeFile(out, Buffer.from(result.data));
700
745
  const v = result.verification?.stats;
701
746
  const lossless = v ? v.modified === 0 && v.added === 0 && v.removed === 0 : void 0;
702
747
  const lines = [
@@ -732,24 +777,24 @@ server.tool(
732
777
  return { content: [{ type: "text", text: 'format: "svg"\uB294 output_path(.svg)\uAC00 \uD544\uC218\uC785\uB2C8\uB2E4 \u2014 SVG \uC6D0\uBB38\uC740 \uCEE4\uC11C \uC751\uB2F5\uC5D0 \uC9C1\uC811 \uB2F4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.' }], isError: true };
733
778
  }
734
779
  const outPath = output_path ? safeOutputPath(output_path, /* @__PURE__ */ new Set([format === "png" ? ".png" : ".svg"])) : void 0;
735
- const { buffer } = readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx"]));
736
- const { renderHwpxToSvg } = await import("./render-336CJHAS.js");
780
+ const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx"]));
781
+ const { renderHwpxToSvg } = await import("./render-6OW6U4L4.js");
737
782
  const result = await renderHwpxToSvg(buffer, { highlights, reflow: true, reflowMode: reflow_mode });
738
783
  const summary = [
739
784
  `\uB80C\uB354 \uC644\uB8CC: ${result.pageCount}\uD398\uC774\uC9C0, ${Math.round(result.width)}x${Math.round(result.height)}pt (\uD14D\uC2A4\uD2B8 ${result.stats.texts}\xB7\uC774\uBBF8\uC9C0 ${result.stats.images}\xB7\uD45C ${result.stats.tables})`,
740
785
  ...result.warnings.map((w) => `\u26A0\uFE0F ${w}`)
741
786
  ];
742
787
  if (format === "svg") {
743
- mkdirSync(dirname(outPath), { recursive: true });
744
- writeFileSync(outPath, result.svg, "utf-8");
788
+ await mkdir(dirname(outPath), { recursive: true });
789
+ await writeFile(outPath, result.svg, "utf-8");
745
790
  summary.push(`\uC800\uC7A5: ${outPath}`);
746
791
  return { content: [{ type: "text", text: summary.join("\n") }] };
747
792
  }
748
- const { rasterizeSvg } = await import("./rasterize-OG7KXBJS.js");
793
+ const { rasterizeSvg } = await import("./rasterize-GNJQVURE.js");
749
794
  const raster = await rasterizeSvg(result.svg, result.width, result.height);
750
795
  if (outPath) {
751
- mkdirSync(dirname(outPath), { recursive: true });
752
- writeFileSync(outPath, raster.png);
796
+ await mkdir(dirname(outPath), { recursive: true });
797
+ await writeFile(outPath, raster.png);
753
798
  summary.push(`\uC800\uC7A5: ${outPath}`);
754
799
  }
755
800
  summary.push(`\uC774\uBBF8\uC9C0 ${raster.widthPx}x${raster.heightPx}px \u2014 \uC798\uB9BC\xB7\uACB9\uCE68\xB7\uBE48\uCE78\xB7\uD398\uC774\uC9C0 \uB118\uCE68\uC774 \uBCF4\uC774\uBA74 \uC6D0\uC778 \uD14D\uC2A4\uD2B8\uB97C \uC218\uC815\uD574 \uB2E4\uC2DC \uC0DD\uC131/\uD328\uCE58\uD558\uC138\uC694.`);
@@ -779,7 +824,7 @@ server.tool(
779
824
  },
780
825
  async ({ file_path, rules, mask_char, output_path, dry_run }) => {
781
826
  try {
782
- const { buffer } = readValidatedFile(file_path);
827
+ const { buffer } = await readValidatedFile(file_path);
783
828
  const format = detectFormat(buffer);
784
829
  const patchable = format === "hwpx" || format === "hwp";
785
830
  if (!dry_run && !output_path) {
@@ -790,7 +835,7 @@ server.tool(
790
835
  if (!parsed.success) {
791
836
  return { content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}` }], isError: true };
792
837
  }
793
- const { redactMarkdown } = await import("./redact-7ILEAUTS.js");
838
+ const { redactMarkdown } = await import("./redact-W5K3ILQH.js");
794
839
  const r = redactMarkdown(parsed.markdown, { rules, maskChar: mask_char });
795
840
  const byRule = /* @__PURE__ */ new Map();
796
841
  for (const h of r.hits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1);
@@ -805,8 +850,8 @@ server.tool(
805
850
  if (!result.success || !result.data) {
806
851
  return { content: [{ type: "text", text: `\uB9C8\uC2A4\uD0B9 \uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}` }], isError: true };
807
852
  }
808
- mkdirSync(dirname(outPath), { recursive: true });
809
- writeFileSync(outPath, Buffer.from(result.data));
853
+ await mkdir(dirname(outPath), { recursive: true });
854
+ await writeFile(outPath, Buffer.from(result.data));
810
855
  lines.push(`\uC800\uC7A5: ${outPath} (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874)`);
811
856
  if (result.skipped.length > 0) {
812
857
  lines.push(`\u26A0\uFE0F \uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74 \u2014 \uD574\uB2F9 \uC704\uCE58\uB294 \uC6D0\uBB38\uC774 \uB0A8\uC544 \uC788\uC73C\uB2C8 \uBC18\uB4DC\uC2DC \uC218\uB3D9 \uD655\uC778:`);
@@ -814,8 +859,8 @@ server.tool(
814
859
  }
815
860
  lines.push("render_document\uB85C \uB9C8\uC2A4\uD0B9 \uACB0\uACFC\uB97C \uB208\uC73C\uB85C \uD655\uC778\uD558\uC138\uC694.");
816
861
  } else {
817
- mkdirSync(dirname(outPath), { recursive: true });
818
- writeFileSync(outPath, r.text, "utf-8");
862
+ await mkdir(dirname(outPath), { recursive: true });
863
+ await writeFile(outPath, r.text, "utf-8");
819
864
  lines.push(`\uC800\uC7A5: ${outPath} (${format}\uB294 \uC11C\uC2DD \uBCF4\uC874 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4)`);
820
865
  }
821
866
  } else if (!dry_run) {
@@ -838,12 +883,12 @@ server.tool(
838
883
  },
839
884
  async ({ file_path, granularity, include_table_cells }) => {
840
885
  try {
841
- const { buffer } = readValidatedFile(file_path);
886
+ const { buffer } = await readValidatedFile(file_path);
842
887
  const parsed = await parse(buffer, { filePath: file_path });
843
888
  if (!parsed.success) {
844
889
  return { content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}` }], isError: true };
845
890
  }
846
- const { blocksToChunks } = await import("./chunks-VFIMYK36.js");
891
+ const { blocksToChunks } = await import("./chunks-Q7T4SQGW.js");
847
892
  const chunks = blocksToChunks(parsed.blocks, { granularity, includeTableCells: include_table_cells });
848
893
  return { content: [{ type: "text", text: capResponseText(JSON.stringify(chunks, null, 2)) }] };
849
894
  } catch (err) {
@@ -861,11 +906,11 @@ server.tool(
861
906
  async ({ hwpx_path, output_path }) => {
862
907
  try {
863
908
  const out = safeOutputPath(output_path, PROFILE_EXTENSIONS);
864
- const { buffer } = readValidatedFile(hwpx_path);
865
- const { hwpxToProfile } = await import("./-ECUCTQTR.js");
909
+ const { buffer } = await readValidatedFile(hwpx_path);
910
+ const { hwpxToProfile } = await import("./-DYHT3HWH.js");
866
911
  const profile = await hwpxToProfile(buffer);
867
- mkdirSync(dirname(out), { recursive: true });
868
- writeFileSync(out, JSON.stringify(profile, null, 2));
912
+ await mkdir(dirname(out), { recursive: true });
913
+ await writeFile(out, JSON.stringify(profile, null, 2));
869
914
  return {
870
915
  content: [{ type: "text", text: `\uC11C\uC2DD \uD504\uB85C\uD544 \uCD94\uCD9C \uC644\uB8CC: \uD45C ${profile.tables.length}\uAC1C \u2192 ${out}
871
916
  (generate_document\uC758 profile_path\uB85C \uC0AC\uC6A9)` }]
@@ -945,13 +990,13 @@ server.tool(
945
990
  }
946
991
  let profile;
947
992
  if (profile_path) {
948
- const { parseFormatProfileJson } = await import("./profile-io-43MF52H6.js");
949
- profile = parseFormatProfileJson(readFileSync(safePath(profile_path, PROFILE_EXTENSIONS), "utf-8"));
993
+ const { parseFormatProfileJson } = await import("./profile-io-72R3B7KO.js");
994
+ profile = parseFormatProfileJson(await readFile(safePath(profile_path, PROFILE_EXTENSIONS), "utf-8"));
950
995
  }
951
996
  const out = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx"]));
952
997
  const buf = await markdownToHwpx(markdown, gongmun || profile ? { ...gongmun ? { gongmun } : {}, ...profile ? { profile } : {} } : void 0);
953
- mkdirSync(dirname(out), { recursive: true });
954
- writeFileSync(out, Buffer.from(buf));
998
+ await mkdir(dirname(out), { recursive: true });
999
+ await writeFile(out, Buffer.from(buf));
955
1000
  const mode = gongmun ? `\uACF5\uBB38\uC11C:${gongmun.preset}` : "\uBC94\uC6A9";
956
1001
  const tableCount = (markdown.match(/^\s*\|.*\|\s*$/gm) || []).length > 0 ? `, \uD45C \uD3EC\uD568` : "";
957
1002
  const fontWarns = gongmun?.fonts ? unknownFontWarnings(gongmun.fonts) : [];