kordoc 4.14.2 → 4.14.3

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 (151) hide show
  1. package/README.md +38 -5
  2. package/dist/{-AQKXLFIM.js → -7XBPXCXN.js} +13 -11
  3. package/dist/{chunk-FOJZNMMK.js → chunk-2LQGSDZ6.js} +1 -1
  4. package/dist/chunk-2LQGSDZ6.js.map +1 -0
  5. package/dist/chunk-4R67INKT.js +1002 -0
  6. package/dist/chunk-4R67INKT.js.map +1 -0
  7. package/dist/{chunk-ILU76UF3.js → chunk-4RJ5D7MT.js} +2 -2
  8. package/dist/chunk-4RJ5D7MT.js.map +1 -0
  9. package/dist/{chunk-EQZI77PP.cjs → chunk-5VVS2QIJ.cjs} +3 -3
  10. package/dist/{chunk-EQZI77PP.cjs.map → chunk-5VVS2QIJ.cjs.map} +1 -1
  11. package/dist/{chunk-3DUADAY2.js → chunk-A275ZQLX.js} +209 -87
  12. package/dist/chunk-A275ZQLX.js.map +1 -0
  13. package/dist/{chunk-EISO3POT.js → chunk-CVEERPMP.js} +788 -194
  14. package/dist/chunk-CVEERPMP.js.map +1 -0
  15. package/dist/{chunk-ZWD734EY.js → chunk-D6KQKMU3.js} +2 -2
  16. package/dist/{chunk-QOMNEWCQ.cjs → chunk-EBZUZC6F.cjs} +305 -31
  17. package/dist/chunk-EBZUZC6F.cjs.map +1 -0
  18. package/dist/{chunk-HR2XNERB.cjs → chunk-EMGF6EEV.cjs} +2 -2
  19. package/dist/{chunk-HR2XNERB.cjs.map → chunk-EMGF6EEV.cjs.map} +1 -1
  20. package/dist/{chunk-GDW4YP7K.js → chunk-FAZR34CA.js} +2 -2
  21. package/dist/{chunk-TNCKOL2O.js → chunk-GTINVM5K.js} +2 -2
  22. package/dist/{chunk-L7DMSMAG.cjs → chunk-HX4UUF7Y.cjs} +1 -1
  23. package/dist/chunk-HX4UUF7Y.cjs.map +1 -0
  24. package/dist/{chunk-UET462HB.js → chunk-I4NNYWIR.js} +2 -2
  25. package/dist/chunk-IH56ZISC.js +620 -0
  26. package/dist/chunk-IH56ZISC.js.map +1 -0
  27. package/dist/{chunk-EDNJLUSE.js → chunk-IHZEFW4L.js} +2 -2
  28. package/dist/chunk-IW2CB755.cjs +1002 -0
  29. package/dist/chunk-IW2CB755.cjs.map +1 -0
  30. package/dist/{chunk-ZWOFQRIB.js → chunk-JCVIOLBF.js} +3 -3
  31. package/dist/{chunk-JQEFP45L.js → chunk-L5EH2NVO.js} +2 -2
  32. package/dist/{chunk-247ANM72.cjs → chunk-NOAQRCV6.cjs} +219 -97
  33. package/dist/chunk-NOAQRCV6.cjs.map +1 -0
  34. package/dist/{chunk-7IAQ4HOK.js → chunk-NQCUAGLR.js} +1 -1
  35. package/dist/chunk-NQCUAGLR.js.map +1 -0
  36. package/dist/{chunk-NS55SM7A.js → chunk-O2PGQNYE.js} +2 -2
  37. package/dist/{chunk-QC5T6D4J.js → chunk-QGW7NMTX.js} +299 -25
  38. package/dist/chunk-QGW7NMTX.js.map +1 -0
  39. package/dist/{chunk-A7QC2ZVP.js → chunk-UVVEBI22.js} +209 -87
  40. package/dist/chunk-UVVEBI22.js.map +1 -0
  41. package/dist/chunk-VJHAUMCF.js +949 -0
  42. package/dist/chunk-VJHAUMCF.js.map +1 -0
  43. package/dist/{chunk-C7FQBSON.js → chunk-VNFJPTU4.js} +2 -2
  44. package/dist/{chunk-VQ5W4MYO.js → chunk-VYOGXNQ3.js} +298 -24
  45. package/dist/chunk-VYOGXNQ3.js.map +1 -0
  46. package/dist/{chunk-DOGPOY4B.js → chunk-WB5LW52Z.js} +2 -2
  47. package/dist/{chunk-TSFS5VKD.js → chunk-YGBZABI4.js} +332 -141
  48. package/dist/chunk-YGBZABI4.js.map +1 -0
  49. package/dist/chunks-I7TEMJXH.js +10 -0
  50. package/dist/cli.js +228 -97
  51. package/dist/cli.js.map +1 -1
  52. package/dist/{formula-PJJ6S3Z2.cjs → formula-CPO2TZGB.cjs} +9 -9
  53. package/dist/{formula-PJJ6S3Z2.cjs.map → formula-CPO2TZGB.cjs.map} +1 -1
  54. package/dist/{formula-5S7WWXGH.js → formula-NOIDZEBA.js} +4 -4
  55. package/dist/{formula-JGFTXWYT.js → formula-X44GV7TN.js} +3 -3
  56. package/dist/{image-ocr-WCAYXLOA.js → image-ocr-72RAR4WR.js} +34 -16
  57. package/dist/image-ocr-72RAR4WR.js.map +1 -0
  58. package/dist/{image-ocr-FLIL7MGN.js → image-ocr-R6W6A75P.js} +32 -14
  59. package/dist/image-ocr-R6W6A75P.js.map +1 -0
  60. package/dist/{image-ocr-ZTYAGV3W.cjs → image-ocr-SUGT64ZM.cjs} +36 -18
  61. package/dist/image-ocr-SUGT64ZM.cjs.map +1 -0
  62. package/dist/index.cjs +2416 -1184
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +62 -25
  65. package/dist/index.d.ts +62 -25
  66. package/dist/index.js +1853 -621
  67. package/dist/index.js.map +1 -1
  68. package/dist/mcp.js +74 -53
  69. package/dist/mcp.js.map +1 -1
  70. package/dist/{model-bundle-FSPZZ2EM.js → model-bundle-57CLEBCO.js} +5 -5
  71. package/dist/{models-CJPAQK5R.js → models-7ELIFTD7.js} +5 -5
  72. package/dist/{parser-SCUTZAIJ.js → parser-4NKAYWAX.js} +261 -241
  73. package/dist/parser-4NKAYWAX.js.map +1 -0
  74. package/dist/{parser-A4TMPJAM.js → parser-HWFQRSUQ.js} +261 -241
  75. package/dist/parser-HWFQRSUQ.js.map +1 -0
  76. package/dist/{parser-VCXE4I5A.cjs → parser-RANGXGBD.cjs} +289 -269
  77. package/dist/parser-RANGXGBD.cjs.map +1 -0
  78. package/dist/pdf-ocr-BNC34MNU.js +13 -0
  79. package/dist/pdf-ocr-QX2GB33Q.js +16 -0
  80. package/dist/pdf-ocr-VHSFACH7.cjs +14 -0
  81. package/dist/{pdf-ocr-MBZZ57LD.cjs.map → pdf-ocr-VHSFACH7.cjs.map} +1 -1
  82. package/dist/{profile-io-LBM263K7.js → profile-io-V52PL5ZO.js} +3 -3
  83. package/dist/{rasterize-46RG4ZF6.js → rasterize-ZIGLJDOG.js} +3 -3
  84. package/dist/redact-TIQEQI3M.js +18 -0
  85. package/dist/redact-doc-KXZ3TZAG.js +1216 -0
  86. package/dist/redact-doc-KXZ3TZAG.js.map +1 -0
  87. package/dist/{render-NGP5T24S.js → render-U5PE6V2E.js} +7 -7
  88. package/dist/seal-DNXJBILR.js +10 -0
  89. package/dist/{setup-AU4OCHNH.js → setup-YRDM4ODP.js} +3 -3
  90. package/dist/visual-5XWMA4EV.js +19 -0
  91. package/dist/{watch-MKPUCPXM.js → watch-5IOLBATT.js} +12 -12
  92. package/package.json +2 -2
  93. package/dist/chunk-247ANM72.cjs.map +0 -1
  94. package/dist/chunk-3DUADAY2.js.map +0 -1
  95. package/dist/chunk-422427XJ.cjs +0 -571
  96. package/dist/chunk-422427XJ.cjs.map +0 -1
  97. package/dist/chunk-7IAQ4HOK.js.map +0 -1
  98. package/dist/chunk-A7QC2ZVP.js.map +0 -1
  99. package/dist/chunk-DZIXKL7E.js +0 -145
  100. package/dist/chunk-DZIXKL7E.js.map +0 -1
  101. package/dist/chunk-EISO3POT.js.map +0 -1
  102. package/dist/chunk-EP7KOI2V.js +0 -571
  103. package/dist/chunk-EP7KOI2V.js.map +0 -1
  104. package/dist/chunk-FOJZNMMK.js.map +0 -1
  105. package/dist/chunk-ILU76UF3.js.map +0 -1
  106. package/dist/chunk-KVWV4ULP.js +0 -516
  107. package/dist/chunk-KVWV4ULP.js.map +0 -1
  108. package/dist/chunk-L7DMSMAG.cjs.map +0 -1
  109. package/dist/chunk-QC5T6D4J.js.map +0 -1
  110. package/dist/chunk-QOMNEWCQ.cjs.map +0 -1
  111. package/dist/chunk-TSFS5VKD.js.map +0 -1
  112. package/dist/chunk-VQ5W4MYO.js.map +0 -1
  113. package/dist/chunks-SX77P5CV.js +0 -10
  114. package/dist/image-ocr-FLIL7MGN.js.map +0 -1
  115. package/dist/image-ocr-WCAYXLOA.js.map +0 -1
  116. package/dist/image-ocr-ZTYAGV3W.cjs.map +0 -1
  117. package/dist/parser-A4TMPJAM.js.map +0 -1
  118. package/dist/parser-SCUTZAIJ.js.map +0 -1
  119. package/dist/parser-VCXE4I5A.cjs.map +0 -1
  120. package/dist/pdf-ocr-76SAUXMZ.js +0 -13
  121. package/dist/pdf-ocr-CPU55CVF.js +0 -16
  122. package/dist/pdf-ocr-MBZZ57LD.cjs +0 -14
  123. package/dist/redact-7ILEAUTS.js +0 -12
  124. package/dist/seal-RGUPOLXD.js +0 -10
  125. package/dist/visual-NZLYIYEM.js +0 -19
  126. /package/dist/{-AQKXLFIM.js.map → -7XBPXCXN.js.map} +0 -0
  127. /package/dist/{chunk-ZWD734EY.js.map → chunk-D6KQKMU3.js.map} +0 -0
  128. /package/dist/{chunk-GDW4YP7K.js.map → chunk-FAZR34CA.js.map} +0 -0
  129. /package/dist/{chunk-TNCKOL2O.js.map → chunk-GTINVM5K.js.map} +0 -0
  130. /package/dist/{chunk-UET462HB.js.map → chunk-I4NNYWIR.js.map} +0 -0
  131. /package/dist/{chunk-EDNJLUSE.js.map → chunk-IHZEFW4L.js.map} +0 -0
  132. /package/dist/{chunk-ZWOFQRIB.js.map → chunk-JCVIOLBF.js.map} +0 -0
  133. /package/dist/{chunk-JQEFP45L.js.map → chunk-L5EH2NVO.js.map} +0 -0
  134. /package/dist/{chunk-NS55SM7A.js.map → chunk-O2PGQNYE.js.map} +0 -0
  135. /package/dist/{chunk-C7FQBSON.js.map → chunk-VNFJPTU4.js.map} +0 -0
  136. /package/dist/{chunk-DOGPOY4B.js.map → chunk-WB5LW52Z.js.map} +0 -0
  137. /package/dist/{chunks-SX77P5CV.js.map → chunks-I7TEMJXH.js.map} +0 -0
  138. /package/dist/{formula-5S7WWXGH.js.map → formula-NOIDZEBA.js.map} +0 -0
  139. /package/dist/{formula-JGFTXWYT.js.map → formula-X44GV7TN.js.map} +0 -0
  140. /package/dist/{model-bundle-FSPZZ2EM.js.map → model-bundle-57CLEBCO.js.map} +0 -0
  141. /package/dist/{models-CJPAQK5R.js.map → models-7ELIFTD7.js.map} +0 -0
  142. /package/dist/{pdf-ocr-76SAUXMZ.js.map → pdf-ocr-BNC34MNU.js.map} +0 -0
  143. /package/dist/{pdf-ocr-CPU55CVF.js.map → pdf-ocr-QX2GB33Q.js.map} +0 -0
  144. /package/dist/{profile-io-LBM263K7.js.map → profile-io-V52PL5ZO.js.map} +0 -0
  145. /package/dist/{rasterize-46RG4ZF6.js.map → rasterize-ZIGLJDOG.js.map} +0 -0
  146. /package/dist/{redact-7ILEAUTS.js.map → redact-TIQEQI3M.js.map} +0 -0
  147. /package/dist/{render-NGP5T24S.js.map → render-U5PE6V2E.js.map} +0 -0
  148. /package/dist/{seal-RGUPOLXD.js.map → seal-DNXJBILR.js.map} +0 -0
  149. /package/dist/{setup-AU4OCHNH.js.map → setup-YRDM4ODP.js.map} +0 -0
  150. /package/dist/{visual-NZLYIYEM.js.map → visual-5XWMA4EV.js.map} +0 -0
  151. /package/dist/{watch-MKPUCPXM.js.map → watch-5IOLBATT.js.map} +0 -0
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ blocksToChunks
4
+ } from "./chunk-IHZEFW4L.js";
5
+ import "./chunk-QGW7NMTX.js";
6
+ import "./chunk-I4NNYWIR.js";
7
+ export {
8
+ blocksToChunks
9
+ };
10
+ //# sourceMappingURL=chunks-I7TEMJXH.js.map
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  parseFormatProfileJson
4
- } from "./chunk-TNCKOL2O.js";
4
+ } from "./chunk-GTINVM5K.js";
5
5
  import {
6
6
  BODY_FONTS,
7
7
  BULLET2_CHARS,
@@ -30,34 +30,34 @@ import {
30
30
  resolveBuiltinTemplate,
31
31
  unknownFontWarnings,
32
32
  usesGaejosikMunche
33
- } from "./chunk-EISO3POT.js";
34
- import "./chunk-ZWOFQRIB.js";
35
- import "./chunk-DZIXKL7E.js";
36
- import "./chunk-EDNJLUSE.js";
33
+ } from "./chunk-CVEERPMP.js";
34
+ import "./chunk-JCVIOLBF.js";
35
+ import "./chunk-IH56ZISC.js";
36
+ import "./chunk-IHZEFW4L.js";
37
37
  import {
38
38
  detectFormat,
39
39
  detectImageMime,
40
40
  detectZipFormat
41
- } from "./chunk-TSFS5VKD.js";
41
+ } from "./chunk-YGBZABI4.js";
42
42
  import "./chunk-7FCNOKOR.js";
43
- import "./chunk-7IAQ4HOK.js";
43
+ import "./chunk-NQCUAGLR.js";
44
44
  import "./chunk-MOL7MDBG.js";
45
- import "./chunk-ILU76UF3.js";
45
+ import "./chunk-4RJ5D7MT.js";
46
46
  import {
47
47
  blocksToMarkdown
48
- } from "./chunk-QC5T6D4J.js";
49
- import "./chunk-C7FQBSON.js";
48
+ } from "./chunk-QGW7NMTX.js";
49
+ import "./chunk-VNFJPTU4.js";
50
50
  import {
51
51
  KordocError,
52
52
  VERSION,
53
53
  classifyError,
54
54
  sanitizeError,
55
55
  toArrayBuffer
56
- } from "./chunk-UET462HB.js";
56
+ } from "./chunk-I4NNYWIR.js";
57
57
 
58
58
  // src/cli.ts
59
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, statSync as statSync2 } from "fs";
60
- import { basename as basename3, resolve as resolve4 } from "path";
59
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, statSync as statSync4 } from "fs";
60
+ import { basename as basename3, resolve as resolve5 } from "path";
61
61
  import { Command } from "commander";
62
62
 
63
63
  // src/cli/commands-docs.ts
@@ -72,7 +72,7 @@ function registerDocCommands(program2) {
72
72
  if (command.getOptionValueSource("format") === "default" && program2.getOptionValueSource("format") === "cli") {
73
73
  opts.format = rootOpts.format;
74
74
  }
75
- const { watchDirectory } = await import("./watch-MKPUCPXM.js");
75
+ const { watchDirectory } = await import("./watch-5IOLBATT.js");
76
76
  await watchDirectory({
77
77
  dir,
78
78
  outDir: opts.outDir,
@@ -186,8 +186,8 @@ function registerDocCommands(program2) {
186
186
  process.exit(1);
187
187
  }
188
188
  inputs = Object.fromEntries(Object.entries(values).map(([k, v]) => {
189
- const format = formatMap[k];
190
- return [k, format ? { value: v, format } : v];
189
+ const format2 = formatMap[k];
190
+ return [k, format2 ? { value: v, format: format2 } : v];
191
191
  }));
192
192
  }
193
193
  let outputFormat = opts.format;
@@ -203,8 +203,8 @@ function registerDocCommands(program2) {
203
203
  }
204
204
  }
205
205
  if (outputFormat === "hwpx-preserve") {
206
- const format = detectFormat(arrayBuffer);
207
- let isHwpx = format === "hwpx";
206
+ const format2 = detectFormat(arrayBuffer);
207
+ let isHwpx = format2 === "hwpx";
208
208
  if (isHwpx) {
209
209
  const zipFormat = await detectZipFormat(arrayBuffer);
210
210
  isHwpx = zipFormat === "hwpx";
@@ -294,7 +294,7 @@ function registerDocCommands(program2) {
294
294
  });
295
295
  program2.command("seal <file>").description('\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0\uB97C \uC575\uCEE4 \uBB38\uAD6C \uC704\uC5D0 \uBD80\uC720 \uBC30\uCE58 (\uD45C/\uD398\uC774\uC9C0 \uBD88\uD655\uC7A5) \u2014 kordoc seal \uC2E0\uCCAD\uC11C.hwpx --image \uB3C4\uC7A5.png --anchor "(\uC778)" -o \uACB0\uACFC.hwpx').requiredOption("--image <path>", "\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0 (\uD22C\uBA85 \uBC30\uACBD PNG \uAD8C\uC7A5)").option("--anchor <text>", "\uC575\uCEE4 \uBB38\uAD6C", "(\uC778)").option("-n, --occurrence <num>", "\uAC19\uC740 \uC575\uCEE4\uAC00 \uC5EC\uB7FF\uC77C \uB54C 0-based \uC120\uD0DD", "0").option("--size-mm <num>", "\uB3C4\uC7A5 \uD55C \uBCC0 \uD06C\uAE30 mm (\uAE30\uBCF8: \uC904\uB192\uC774\xD71.6, 7~18 \uD074\uB7A8\uD504)").option("--mode <mode>", "overlap(\uBB38\uAD6C \uC704 \uACB9\uCE68) | right(\uC624\uB978\uCABD \uC606) | auto", "auto").option("--dx <mm>", "x \uBBF8\uC138\uC870\uC815 mm", "0").option("--dy <mm>", "y \uBBF8\uC138\uC870\uC815 mm", "0").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.sealed.hwpx)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (file, opts) => {
296
296
  try {
297
- const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-AQKXLFIM.js");
297
+ const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-7XBPXCXN.js");
298
298
  const rootOpts = program2.opts();
299
299
  const output = opts.output ?? rootOpts.output;
300
300
  const silent = opts.silent ?? rootOpts.silent;
@@ -372,20 +372,20 @@ function registerDocCommands(program2) {
372
372
  });
373
373
  program2.command("patch <original> <edited>").description("\uC11C\uC2DD \uBCF4\uC874 \uB77C\uC6B4\uB4DC\uD2B8\uB9BD \uD328\uCE58 \u2014 \uD3B8\uC9D1\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uC6D0\uBCF8 HWPX/HWP\uC5D0 in-place \uBC18\uC601 (kordoc patch \uC6D0\uBCF8.hwpx \uD3B8\uC9D1.md -o \uCD9C\uB825.hwpx). \uBBF8\uC801\uC6A9(skip) \uD3B8\uC9D1\uC774 \uC788\uC73C\uBA74 exit 2").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uAE30\uBCF8: <\uC6D0\uBCF8>.patched.hwpx|.hwp)").option("--no-verify", "\uD328\uCE58 \uD6C4 \uC7AC\uD30C\uC2F1 \uC790\uB3D9 \uAC80\uC99D \uC0DD\uB7B5").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (original, edited, opts) => {
374
374
  try {
375
- const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-AQKXLFIM.js");
375
+ const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-7XBPXCXN.js");
376
376
  const rootOpts = program2.opts();
377
377
  const output = opts.output ?? rootOpts.output;
378
378
  const silent = opts.silent ?? rootOpts.silent;
379
379
  const originalBuf = new Uint8Array(readFileSync(resolve(original)));
380
380
  const editedMarkdown = readFileSync(resolve(edited), "utf-8");
381
- const format = detectFormat2(originalBuf.buffer);
382
- const result = format === "hwp" ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false }) : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false });
381
+ const format2 = detectFormat2(originalBuf.buffer);
382
+ const result = format2 === "hwp" ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false }) : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false });
383
383
  if (!result.success || !result.data) {
384
384
  process.stderr.write(`[kordoc] \uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}
385
385
  `);
386
386
  process.exit(1);
387
387
  }
388
- const ext = format === "hwp" ? ".hwp" : ".hwpx";
388
+ const ext = format2 === "hwp" ? ".hwp" : ".hwpx";
389
389
  const outPath = resolve(output ?? original.replace(/\.hwpx?$/i, "") + ".patched" + ext);
390
390
  mkdirSync(dirname(outPath), { recursive: true });
391
391
  writeFileSync(outPath, result.data);
@@ -413,7 +413,7 @@ function registerDocCommands(program2) {
413
413
  });
414
414
  program2.command("validate <file>").description("HWPX \uAD6C\uC870 \uAC80\uC99D \u2014 ZIP\xB7mimetype\xB7\uD544\uC218 \uD30C\uC77C\xB7XML \uC6F0\uD3FC\uB4DC\xB7secCnt\xB7manifest \uCC38\uC870 (\uD55C\uCEF4\uB3C5\uC2A4 \uAC70\uBD80 \uC694\uC778 \uC0AC\uC804 \uCC28\uB2E8)").option("--json", "\uACB0\uACFC\uB97C JSON\uC73C\uB85C stdout\uC5D0 \uCD9C\uB825").action(async (file, opts) => {
415
415
  try {
416
- const { validateHwpx } = await import("./-AQKXLFIM.js");
416
+ const { validateHwpx } = await import("./-7XBPXCXN.js");
417
417
  const buf = new Uint8Array(readFileSync(resolve(file)));
418
418
  const result = await validateHwpx(buf);
419
419
  if (opts.json) {
@@ -439,7 +439,7 @@ function registerDocCommands(program2) {
439
439
  }
440
440
 
441
441
  // src/cli/commands-generate.ts
442
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
442
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, statSync as statSync2 } from "fs";
443
443
  import { basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
444
444
  function registerGenerateCommands(program2) {
445
445
  program2.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB2E4\uC6B4 \u2192 \uACF5\uBB38\uC11C HWPX \uC0DD\uC131 \u2014 kordoc generate \uBCF4\uACE0\uC11C.md -o \uBCF4\uACE0\uC11C.hwpx --preset \uBCF4\uACE0\uC11C (markdown\uC5D0 '-' \uC9C0\uC815 \uC2DC stdin)").option("-o, --output <path>", "\uCD9C\uB825 HWPX \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.hwpx)").option("--preset <name>", "\uACF5\uBB38\uC11C \uD504\uB9AC\uC14B: \uAE30\uC548\uBB38(official)\xB7\uBCF4\uACE0\uC11C(report)\xB7\uACC4\uD68D\uC11C(plan)\xB7\uD1B5\uC9C0(notice)\xB7\uD68C\uC758\uB85D(minutes)\xB7\uAC1C\uC870\uC2DD(gaejosik \u2014 \uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uC7A5\uD5E4\uB354 \uC790\uB3D9)\xB7\uC5C5\uBB34\uBCF4\uACE0(ministry \u2014 \uC911\uC559\uBD80\uCC98 \uC5C5\uBB34\uBCF4\uACE0: \uC7A5 \uB760\xB7\uC808 \uC22B\uC790\uCE78\xB7\uC18C\uC81C\uBAA9 \uBC15\uC2A4\xB7\u2460 \uD56D\uBAA9 \uB760\xB7\uC131\uACFC \uC694\uC57D\uBC15\uC2A4\xB7\uBCC4\uCCA8 \uB760)\xB7\uBCF4\uB3C4\uC790\uB8CC(press)", "\uAE30\uC548\uBB38").option("--font <type>", "\uBCF8\uBB38 \uAE00\uAF34: myeongjo(\uD568\uCD08\uB86C\uBC14\uD0D5) \uB610\uB294 gothic(\uB9D1\uC740 \uACE0\uB515)").option("--pt <size>", "\uBCF8\uBB38 \uAE00\uC790 \uD06C\uAE30(pt)").option("--line-spacing <percent>", "\uBCF8\uBB38 \uC904\uAC04\uACA9(%)").option("--profile <path>", "\uC11C\uC2DD \uD504\uB85C\uD544 JSON (kordoc profile\uB85C \uCD94\uCD9C) \u2014 \uCC38\uC870 \uBB38\uC11C\uC758 \uD45C \uD14C\uB450\uB9AC\xB7\uC74C\uC601\xB7\uC5F4\uD3ED\xB7\uC140 \uAE00\uAF34 \uC7AC\uD604").option("--org <name>", "\uD45C\uC9C0 \uAE30\uAD00\uBA85 (\uD45C\uC9C0\uB97C \uCF1C\uB294 \uD504\uB9AC\uC14B \uACF5\uD1B5)").option("--date <date>", "\uD45C\uC9C0 \uB0A0\uC9DC (\uAE30\uBCF8 \uC624\uB298 \u2014 'YYYY. M. D.')").option("--toc", "\uBAA9\uCC28 \uD398\uC774\uC9C0 \uAC15\uC81C \uCF1C\uAE30 (\uAC1C\uC870\uC2DD \uC678 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB3C4 h2 \uBAA9\uB85D\uC73C\uB85C \uC0DD\uC131)").option("--no-toc", "\uBAA9\uCC28 \uD398\uC774\uC9C0 \uB044\uAE30 (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B \uAE30\uBCF8 \uCF1C\uC9D0)").option("--cover", "\uD45C\uC9C0 \uD398\uC774\uC9C0 \uAC15\uC81C \uCF1C\uAE30 (\uAC1C\uC870\uC2DD \uC678 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB3C4 \uCCAB h1\uC744 \uD45C\uC9C0\uB85C)").option("--no-cover", "\uD45C\uC9C0 \uD398\uC774\uC9C0 \uB044\uAE30 (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B \uAE30\uBCF8 \uCF1C\uC9D0)").option("--approval <labels>", "\uACB0\uC7AC\uB780 \uC9C1\uC704 \uB77C\uBCA8 (\uC27C\uD45C \uAD6C\uBD84, \uC608: \uB2F4\uB2F9,\uD300\uC7A5,\uACFC\uC7A5) \u2014 \uBB38\uC11C \uCD5C\uC0C1\uB2E8 \uC6B0\uCE21").option("--page-numbers", "\uCABD\uBC88\uD638 \uAC15\uC81C \uCF1C\uAE30 (\uD558\uB2E8 \uC911\uC559 '- 1 -')").option("--no-page-numbers", "\uCABD\uBC88\uD638 \uB044\uAE30 (\uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8 \uCF1C\uC9D0)").option("--end-mark", "\uBCF8\uBB38 \uB05D '\uB05D.' \uD45C\uC2DC \uAC15\uC81C \uCF1C\uAE30").option("--no-end-mark", "'\uB05D.' \uD45C\uC2DC \uB044\uAE30 (\uAE30\uC548\uBB38 \uAE30\uBCF8 \uCF1C\uC9D0)").option("--no-body-title-box", "\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4 \uB044\uAE30 (\uAC1C\uC870\uC2DD+\uD45C\uC9C0 \uAE30\uBCF8 \uCF1C\uC9D0)").option("--h2-marker <type>", "h2 \uC7A5 \uC81C\uBAA9 \uD45C\uAE30: band(\uB85C\uB9C8\uC790 \uCC44\uC6C0 \uCE78 + \uC81C\uBAA9 \uB760 \uD45C \u2014 \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8)\xB7roman(\u2160. \uD14D\uC2A4\uD2B8)\xB7number(1. \u2014 \uD1B5\uC9C0 \uAE30\uBCF8)\xB7box(\uC7A5 \uC5C6\uC774 \u25A1 \uB300\uD56D\uBAA9)\xB7none").option("--band-color <hex>", "\uB760 \uC81C\uBAA9 \uBC88\uD638\uCE78 \uCC44\uC6C0\uC0C9 #RRGGBB (\uAE30\uBCF8 #003366 \u2014 \uC2E4\uCE21 \uCD5C\uB2E4. \uAD50\uC721\uCCAD\uD615 \uBC1D\uC740 \uB760: #DFE6F7)").option("--band-text-color <hex>", "\uB760 \uC81C\uBAA9 \uBC88\uD638 \uAE00\uC790\uC0C9 #RRGGBB (\uAE30\uBCF8 #FFFFFF \u2014 \uBC1D\uC740 \uB760\uBA74 #000000)").option("--summary <text>", "\uBCF4\uACE0\uC11C \uC694\uC57D \uBC15\uC2A4 (\uC81C\uBAA9\uD45C \uC544\uB798 \uC74C\uC601 \uC0C1\uC790 \u2014 \uB9C8\uD06C\uB2E4\uC6B4 \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(>)\uC73C\uB85C\uB3C4 \uC9C0\uC815)").option("--doc-info <spec>", "\uBCF4\uACE0\uC11C \uD45C\uC9C0 \uBB38\uC11C\uC815\uBCF4\uD45C: docNum=\uC2A4\uB9C8\uD2B8\uB3C4\uC2DC\uACFC-123,date=2026. 9. 6.,disclosure=\uACF5\uAC1C,policyNo= (--cover\uC640 \uD568\uAED8)").option("--dept <name>", "\uD45C\uC9C0 \uBD80\uC11C\uBA85 (\uAE30\uAD00\uBA85 \uC544\uB798 \uAD04\uD638)").option("--cover-label <text>", "\uD45C\uC9C0 \uC6B0\uC0C1\uB2E8 \uCDE8\uAE09 \uD45C\uC2DC \u2014 '\uB300\uC678\uC8FC\uC758'\xB7'\uBE44\uACF5\uAC1C' \uBE68\uAC04 \uD14C\uB450\uB9AC \uBC15\uC2A4 (\uC5C5\uBB34\uBCF4\uACE0 \uD504\uB9AC\uC14B \uC2E4\uCE21)").option("--fonts <spec>", "\uC694\uC18C\uBCC4 \uAE00\uAF34 \uC624\uBC84\uB77C\uC774\uB4DC: body=\uB098\uB214\uBA85\uC870,heading=\uB098\uB214\uACE0\uB515,ref=\uD55C\uC591\uC911\uACE0\uB515,table=\uB9D1\uC740 \uACE0\uB515").option("--sizes <spec>", "\uAC1C\uC870\uC2DD \uC694\uC18C\uBCC4 \uD06C\uAE30(pt): dae=16,cham=13,table=12,coverTitle=30 \u2026").option("--levels <spec>", "\uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uBCC4 \uC704\uACC4 \uD0C0\uC774\uD3EC: 0=HY\uACAC\uACE0\uB515/17/bold,1=\uD55C\uCEF4\uB3CB\uC6C0/15/bold,2=\uD734\uBA3C\uBA85\uC870/14 (depth 0~7, \uC22B\uC790=pt\xB7bold\xB7plain\xB7\uAE00\uAF34\uBA85)").option("--bullet2 <char>", "2\uB2E8\uACC4 \uD56D\uBAA9\uBD80\uD638: \u3147(\uC774\uC751 \u2014 \uAE30\uC548\uBB38\xB7\uACF5\uACE0\uBB38 \uC2E4\uCE21 \uC9C0\uBC30) \uB610\uB294 \u25CB(\uC6D0 \u2014 \uBCF4\uACE0\uC11C \uC591\uC2DD)").option("--suppress-single", "\uB2E8\uC77C \uD615\uC81C \uD56D\uBAA9 \uBD80\uD638 \uC0DD\uB7B5 (\uD3B8\uB78C \uADDC\uC815 \u2014 \uAE30\uBCF8\uC740 \uD558\uB098\uC5EC\uB3C4 \uBD80\uD638 \uBD80\uC5EC)").option("--doc-head <spec>", "\uAE30\uC548\uBB38 \uB450\uBB38\uD45C: org=\uAE30\uAD00\uBA85,slogan=\uC6D0\uD6C8,to=\uC218\uC2E0\uCC98,title=\uC81C\uBAA9 (\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD\xB7\uC11C\uC6B8 \uC2E4\uACB0\uC7AC 6\uD589 \uD45C)").option("--doc-foot <spec>", "\uAE30\uC548\uBB38 \uACB0\uBB38\uD45C: sender=\uBC1C\uC2E0\uBA85\uC758,drafter=\uC8FC\uBB34\uAD00 \uD64D\uAE38\uB3D9,reviewer=\uACFC\uC7A5 \uAE40\uCCA0\uC218,approver=\uAD6D\uC7A5 \uBC15\uC601\uD76C,cooperator=\uD611\uC870\uC790,docNum=\uC2DC\uD589(\uACFC-\uBC88\uD638 (\uB0A0\uC9DC)),receive=\uC811\uC218,zip=\uC6B0\uD3B8\uBC88\uD638,address=\uC8FC\uC18C,site=\uD648\uD398\uC774\uC9C0,phone=\uC804\uD654,fax=\uC804\uC1A1,email=\uBA54\uC77C,disclosure=\uACF5\uAC1C\uAD6C\uBD84").option("--report-info <text>", "\uBCF4\uACE0\uC11C \uB2F4\uB2F9\uC790 \uD589(\uC81C\uBAA9\uD45C \uC544\uB798) / \uAE30\uC548\uBB38 \uC6B0\uC0C1\uB2E8 \uBCF4\uACE0\uC815\uBCF4 \uD589 \u2014 \uC608: '(2026. 7. 11., \uACFC\uC7A5 \uD64D\uAE38\uB3D9, \u260E02-120)'").option("--notice-head <spec>", "\uACF5\uACE0\uBB38 \uB450\uBB38\xB7\uACB0\uBB38: no=\uACF5\uACE0 \uC81C2026-1\uD638,date=2026\uB144 7\uC6D4 11\uC77C,sender=\uD589\uC815\uC548\uC804\uBD80\uC7A5\uAD00").option("--press-head <spec>", "\uBCF4\uB3C4\uC790\uB8CC \uBA38\uB9AC: release=\uBCF4\uB3C4\uC2DC\uC810,distribute=\uBC30\uD3EC\uC77C,dept=\uB2F4\uB2F9\uBD80\uC11C,manager=\uB2F4\uB2F9\uC790,phone=\uC5F0\uB77D\uCC98").option("--press-sub <items>", "\uBCF4\uB3C4\uC790\uB8CC \uBD80\uC81C (\uC138\uBBF8\uCF5C\uB860 \uAD6C\uBD84, \uC81C\uBAA9 \uC544\uB798 '- \u2026 -')").option("--plain", "\uACF5\uBB38\uC11C \uBAA8\uB4DC \uB044\uAE30 (\uBC94\uC6A9 \uB9C8\uD06C\uB2E4\uC6B4 \uBCC0\uD658)").option("--paper <size>", "\uC6A9\uC9C0: A4\xB7A3\xB7B4\xB7B5\xB7Letter \uB610\uB294 '210x297'(mm)").option("--landscape", "\uC6A9\uC9C0 \uAC00\uB85C \uBC29\uD5A5").option("--columns <n>", "\uB2E4\uB2E8 \uAC1C\uC218 (1~8)").option("--header <text>", "\uBA38\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8 (\uBAA8\uB4E0 \uCABD, \uC778\uB77C\uC778 \uB9C8\uD06C\uB2E4\uC6B4 \uD5C8\uC6A9)").option("--footer <text>", "\uAF2C\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8").option("--image-dir <dir>", "\uB9C8\uD06C\uB2E4\uC6B4 \uC774\uBBF8\uC9C0 \uCC38\uC870(![](x.png))\uB97C \uC774 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC77D\uC5B4 \uC2E4\uB370\uC774\uD130 \uC784\uBCA0\uB4DC").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (markdown, opts) => {
@@ -678,16 +678,26 @@ function registerGenerateCommands(program2) {
678
678
  process.exit(1);
679
679
  }
680
680
  });
681
- program2.command("redact <files...>").description("\uAC1C\uC778\uC815\uBCF4 \uC11C\uC2DD \uBCF4\uC874 \uB9C8\uC2A4\uD0B9 \u2014 \uC8FC\uBBFC\uBC88\uD638\xB7\uC804\uD654\xB7\uC774\uBA54\uC77C\xB7\uCE74\uB4DC\xB7\uACC4\uC88C\uB97C \uD0D0\uC9C0\uD574 HWPX/HWP\uB294 \uC6D0\uBCF8 \uC11C\uC2DD \uADF8\uB300\uB85C patch, \uADF8 \uC678 \uD3EC\uB9F7\uC740 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4 \uCD9C\uB825. \uC790\uB3D9 \uAC80\uCD9C \uBCF4\uC870 \uB3C4\uAD6C\uC774\uBBC0\uB85C \uACB0\uACFC\uB294 \uBC18\uB4DC\uC2DC \uC0AC\uB78C\uC774 \uCD5C\uC885 \uD655\uC778\uD558\uC138\uC694 (\uC774\uBBF8\uC9C0 \uC548 \uD14D\uC2A4\uD2B8\uB294 \uD0D0\uC9C0 \uBD88\uAC00)").option("--rules <csv>", "\uC801\uC6A9 \uB8F0 (\uAE30\uBCF8: rrn,phone,email,card,account \u2014 passport,driver\uB294 opt-in)").option("--mask-char <ch>", "\uB9C8\uC2A4\uD06C \uBB38\uC790 1\uAE00\uC790 (\uAE30\uBCF8: \u25CF)").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uB2E8\uC77C \uD30C\uC77C \uC2DC)").option("-d, --out-dir <dir>", "\uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC (\uB2E4\uC911 \uD30C\uC77C \uC2DC)").option("--dry-run", "\uD0D0\uC9C0 \uB9AC\uD3EC\uD2B8\uB9CC \uCD9C\uB825, \uD30C\uC77C \uBBF8\uC0DD\uC131").option("--json", "\uB9AC\uD3EC\uD2B8\uB97C JSON\uC73C\uB85C stdout \uCD9C\uB825").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (files, opts) => {
682
- const { redactMarkdown, DEFAULT_REDACT_RULES, patchHwpx, patchHwp } = await import("./-AQKXLFIM.js");
681
+ program2.command("redact <files...>").description("\uAC1C\uC778\uC815\uBCF4 \uC11C\uC2DD \uBCF4\uC874 \uB9C8\uC2A4\uD0B9 \u2014 \uC8FC\uBBFC\xB7\uC678\uAD6D\uC778\uB4F1\uB85D\uBC88\uD638\xB7\uC804\uD654\xB7\uC774\uBA54\uC77C\xB7\uCE74\uB4DC\xB7\uACC4\uC88C\xB7\uC0AC\uC5C5\uC790\uB4F1\uB85D\uBC88\uD638\xB7\uC5EC\uAD8C\xB7\uC6B4\uC804\uBA74\uD5C8\uB97C \uD0D0\uC9C0\uD574 HWPX/HWP\uB294 \uC6D0\uBCF8 \uC11C\uC2DD \uADF8\uB300\uB85C \uAC19\uC740 \uAE38\uC774\uB85C \uAC00\uB9B0 \uD30C\uC77C(\uBCF8\uBB38\xB7\uD45C\xB7\uBA38\uB9AC\uB9D0/\uAF2C\uB9AC\uB9D0\xB7\uAC01\uC8FC\xB7\uAE00\uC0C1\uC790\xB7\uBBF8\uB9AC\uBCF4\uAE30\xB7\uBA54\uD0C0\uB370\uC774\uD130 \uD3EC\uD568), \uADF8 \uC678 \uD3EC\uB9F7(PDF \uB4F1)\uC740 \uC6D0\uBCF8\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uACE0 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uB9CC \uCD9C\uB825. \uC790\uB3D9 \uAC80\uCD9C \uBCF4\uC870 \uB3C4\uAD6C\uC774\uBBC0\uB85C \uACB0\uACFC\uB294 \uBC18\uB4DC\uC2DC \uC0AC\uB78C\uC774 \uCD5C\uC885 \uD655\uC778\uD558\uC138\uC694 (\uC774\uBBF8\uC9C0 \uC18D \uAE00\uC790\uB294 \uD0D0\uC9C0 \uBD88\uAC00)").option("--rules <csv>", "\uC801\uC6A9 \uB8F0 (\uAE30\uBCF8: rrn,phone,email,card,account,brn,passport,driver \u2014 crn(\uBC95\uC778\uB4F1\uB85D\uBC88\uD638),ip\uB294 opt-in)").option("--mask-char <ch>", "\uB9C8\uC2A4\uD06C \uBB38\uC790 1\uAE00\uC790 (\uAE30\uBCF8: \u25CF)").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uB2E8\uC77C \uD30C\uC77C \uC2DC)").option("-d, --out-dir <dir>", "\uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC (\uB2E4\uC911 \uD30C\uC77C \uC2DC)").option("--dry-run", "\uD0D0\uC9C0 \uB9AC\uD3EC\uD2B8\uB9CC \uCD9C\uB825, \uD30C\uC77C \uBBF8\uC0DD\uC131").option("--json", "\uB9AC\uD3EC\uD2B8\uB97C JSON\uC73C\uB85C stdout \uCD9C\uB825").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (files, opts) => {
682
+ const { ALL_REDACT_RULES, DEFAULT_REDACT_RULES, redactText } = await import("./redact-TIQEQI3M.js");
683
+ const { redactDocument } = await import("./redact-doc-KXZ3TZAG.js");
683
684
  const rootOpts = program2.opts();
684
685
  const output = opts.output ?? rootOpts.output;
686
+ const outDir = opts.outDir ?? rootOpts.outDir;
685
687
  const silent = opts.silent ?? rootOpts.silent;
686
- const KNOWN_RULES = /* @__PURE__ */ new Set(["rrn", "phone", "email", "card", "account", "passport", "driver"]);
688
+ const KNOWN_RULES = new Set(ALL_REDACT_RULES);
687
689
  const rules = opts.rules ? String(opts.rules).split(",").map((r) => r.trim()).filter(Boolean) : [...DEFAULT_REDACT_RULES];
688
690
  const badRule = rules.find((r) => !KNOWN_RULES.has(r));
689
691
  if (badRule) {
690
692
  process.stderr.write(`[kordoc] \uC54C \uC218 \uC5C6\uB294 \uB8F0: ${badRule} (\uD5C8\uC6A9: ${[...KNOWN_RULES].join(", ")})
693
+ `);
694
+ process.exit(1);
695
+ }
696
+ const maskChar = opts.maskChar ?? "\u25CF";
697
+ try {
698
+ redactText("", { maskChar });
699
+ } catch (err) {
700
+ process.stderr.write(`[kordoc] ${sanitizeError(err)}
691
701
  `);
692
702
  process.exit(1);
693
703
  }
@@ -695,64 +705,114 @@ function registerGenerateCommands(program2) {
695
705
  process.stderr.write(`[kordoc] \u26A0\uFE0F -o/--output \uC740 \uB2E8\uC77C \uD30C\uC77C \uC804\uC6A9\uC774\uB77C \uBB34\uC2DC\uB429\uB2C8\uB2E4 \u2014 \uB2E4\uC911 \uD30C\uC77C\uC740 -d/--out-dir \uB97C \uC0AC\uC6A9\uD558\uC138\uC694
696
706
  `);
697
707
  }
708
+ const nameMask = /[*?]/.test(maskChar) ? "\u25CF" : maskChar;
709
+ const maskName = (name) => {
710
+ const probe = name.replace(/_/g, " ");
711
+ const out = [...name];
712
+ for (const h of redactText(probe, { rules, maskChar: nameMask }).hits) {
713
+ for (let k = 0; k < h.length; k++) if (h.masked[k] !== probe[h.index + k]) out[h.index + k] = nameMask;
714
+ }
715
+ return out.join("");
716
+ };
717
+ const shown = (p) => resolve2(dirname2(p), maskName(basename2(p)));
718
+ const inputs = files.map((f) => resolve2(f));
719
+ const sameFile = (a, b) => {
720
+ if (a === b) return true;
721
+ try {
722
+ const sa = statSync2(a), sb = statSync2(b);
723
+ return sa.ino === sb.ino && sa.dev === sb.dev;
724
+ } catch {
725
+ return false;
726
+ }
727
+ };
728
+ const written = /* @__PURE__ */ new Set();
729
+ const defaultOut = (absPath, ext) => {
730
+ const stem = maskName(basename2(absPath)).replace(/\.[^.]+$/, "");
731
+ const dir = resolve2(outDir ?? dirname2(absPath));
732
+ for (let n = 1; ; n++) {
733
+ const p = resolve2(dir, `${stem}${n > 1 ? `-${n}` : ""}.redacted${ext}`);
734
+ if (!written.has(p) && !inputs.some((i) => sameFile(i, p))) return p;
735
+ }
736
+ };
737
+ const MAX_LINES = 200;
698
738
  const jsonReports = [];
699
- for (const filePath of files) {
700
- const absPath = resolve2(filePath);
701
- const fileName = basename2(absPath);
739
+ for (const absPath of inputs) {
740
+ const fileName = maskName(basename2(absPath));
741
+ if (output && files.length === 1 && !opts.dryRun && sameFile(absPath, resolve2(output))) {
742
+ process.stderr.write(`[kordoc] ERROR: ${fileName} \u2014 \uCD9C\uB825 \uACBD\uB85C\uAC00 \uC785\uB825 \uD30C\uC77C\uACFC \uAC19\uC2B5\uB2C8\uB2E4. \uC6D0\uBCF8\uC744 \uB36E\uC5B4\uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 \uB2E4\uB978 -o \uACBD\uB85C\uB97C \uC9C0\uC815\uD558\uC138\uC694
743
+ `);
744
+ process.exitCode = 1;
745
+ continue;
746
+ }
702
747
  try {
703
748
  const buffer = readFileSync2(absPath);
704
- const arrayBuffer = toArrayBuffer(buffer);
705
- const format = detectFormat(arrayBuffer);
706
- const parsed = await parse(arrayBuffer, { filePath: absPath });
707
- if (!parsed.success) {
708
- process.stderr.write(`[kordoc] FAIL: ${fileName} \u2014 ${parsed.error}
709
- `);
710
- process.exitCode = 1;
711
- continue;
712
- }
713
- const r = redactMarkdown(parsed.markdown, { rules, maskChar: opts.maskChar });
749
+ const r = await redactDocument(toArrayBuffer(buffer), {
750
+ rules,
751
+ maskChar,
752
+ filePath: absPath,
753
+ dryRun: opts.dryRun
754
+ });
755
+ const listed = r.fileHits.length > 0 ? r.fileHits.map((h) => ({ rule: h.rule, masked: h.masked, at: `${h.where} @ ${h.part}` })) : r.markdownHits.map((h) => ({ rule: h.rule, masked: h.masked, at: "" }));
714
756
  const byRule = /* @__PURE__ */ new Map();
715
- for (const h of r.hits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1);
757
+ for (const h of listed) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1);
716
758
  const ruleSummary = [...byRule.entries()].map(([k, v]) => `${k} ${v}\uAC74`).join(", ") || "0\uAC74";
759
+ const failed = r.residual.length > 0 || r.unscanned.length > 0;
717
760
  let outPath = null;
718
- let patchNote = "";
719
- if (!opts.dryRun && r.hits.length > 0) {
720
- const patchable = format === "hwpx" || format === "hwp";
721
- if (patchable) {
722
- const original = new Uint8Array(arrayBuffer);
723
- const result = format === "hwp" ? await patchHwp(original, r.text) : await patchHwpx(original, r.text);
724
- if (!result.success || !result.data) {
725
- process.stderr.write(`[kordoc] \uD328\uCE58 \uC2E4\uD328: ${fileName} \u2014 ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}
726
- `);
727
- process.exitCode = 1;
728
- continue;
729
- }
730
- const ext = format === "hwp" ? ".hwp" : ".hwpx";
731
- outPath = resolve2(
732
- output && files.length === 1 ? output : resolve2(opts.outDir ?? dirname2(absPath), fileName.replace(/\.[^.]+$/, "") + ".redacted" + ext)
733
- );
734
- mkdirSync2(dirname2(outPath), { recursive: true });
735
- writeFileSync2(outPath, result.data);
736
- if (result.skipped.length > 0) {
737
- patchNote = ` (\u26A0\uFE0F \uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74 \u2014 \uD574\uB2F9 \uC704\uCE58\uB294 \uC6D0\uBB38 \uC794\uC874, \uC218\uB3D9 \uD655\uC778 \uD544\uC694)`;
738
- process.exitCode = 2;
739
- }
740
- } else {
741
- outPath = resolve2(
742
- output && files.length === 1 ? output : resolve2(opts.outDir ?? dirname2(absPath), fileName.replace(/\.[^.]+$/, "") + ".redacted.md")
743
- );
744
- mkdirSync2(dirname2(outPath), { recursive: true });
745
- writeFileSync2(outPath, r.text, "utf-8");
746
- patchNote = ` (${format}\uB294 \uC11C\uC2DD \uBCF4\uC874 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC73C\uB85C \uCD9C\uB825)`;
761
+ let note = "";
762
+ const save = r.data ? r.changed : r.markdownHits.length > 0;
763
+ if (!opts.dryRun && save) {
764
+ const ext = r.data ? r.format === "hwp" ? ".hwp" : ".hwpx" : ".md";
765
+ outPath = output && files.length === 1 ? resolve2(output) : defaultOut(absPath, ext);
766
+ mkdirSync2(dirname2(outPath), { recursive: true });
767
+ if (r.data) writeFileSync2(outPath, r.data);
768
+ else {
769
+ writeFileSync2(outPath, r.markdown, "utf-8");
770
+ note = ` (${r.format} \uC6D0\uBCF8\uC740 \uC218\uC815\uD558\uC9C0 \uC54A\uC74C \u2014 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uB9CC \uCD9C\uB825)`;
747
771
  }
772
+ written.add(outPath);
773
+ } else if (!opts.dryRun && r.data && listed.length > 0) {
774
+ note = " (\u274C \uD30C\uC77C\uC5D0\uC11C \uAC00\uB9B0 \uACF3\uC774 \uC5C6\uC5B4 \uCD9C\uB825\uD558\uC9C0 \uC54A\uC74C)";
748
775
  }
776
+ if (failed && process.exitCode !== 1) process.exitCode = 2;
749
777
  if (opts.json) {
750
- jsonReports.push({ file: absPath, format, rules, hits: r.hits, output: outPath });
778
+ jsonReports.push({
779
+ file: shown(absPath),
780
+ format: r.format,
781
+ rules,
782
+ hits: r.markdownHits,
783
+ fileHits: r.fileHits,
784
+ residual: r.residual,
785
+ unscanned: r.unscanned,
786
+ warnings: r.warnings,
787
+ output: outPath
788
+ });
751
789
  }
752
790
  if (!silent) {
753
- process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` \u2192 ${outPath}` : opts.dryRun ? " (dry-run)" : ""}${patchNote}
791
+ process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` \u2192 ${outPath}` : opts.dryRun ? " (dry-run)" : ""}${note}
792
+ `);
793
+ const grouped = /* @__PURE__ */ new Map();
794
+ for (const h of listed) {
795
+ const key = ` - [${h.rule}] ${h.masked}${h.at ? ` (${h.at})` : ""}`;
796
+ grouped.set(key, (grouped.get(key) ?? 0) + 1);
797
+ }
798
+ const lines = [...grouped].map(([line, n]) => `${line}${n > 1 ? ` \xD7${n}` : ""}`);
799
+ for (const line of lines.slice(0, MAX_LINES)) process.stderr.write(`${line}
800
+ `);
801
+ if (lines.length > MAX_LINES) process.stderr.write(` \u2026 \uC678 ${lines.length - MAX_LINES}\uC904 (\uC804\uCCB4\uB294 --json)
802
+ `);
803
+ if (r.residual.length > 0) {
804
+ process.stderr.write(`[kordoc] \u274C \uB9C8\uC2A4\uD0B9 \uD6C4 \uC7AC\uAC80\uC0AC\uC5D0\uC11C PII ${r.residual.length}\uAC74\uC774 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uCD9C\uB825 \uD30C\uC77C\uC744 \uACF5\uAC1C\uD558\uC9C0 \uB9D0\uACE0 \uC218\uB3D9 \uD655\uC778\uD558\uC138\uC694:
805
+ `);
806
+ for (const h of r.residual.slice(0, MAX_LINES)) process.stderr.write(` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})
754
807
  `);
755
- for (const h of r.hits) process.stderr.write(` - [${h.rule}] ${h.masked}
808
+ if (r.residual.length > MAX_LINES) process.stderr.write(` \u2026 \uC678 ${r.residual.length - MAX_LINES}\uAC74 (\uC804\uCCB4\uB294 --json)
809
+ `);
810
+ }
811
+ if (r.unscanned.length > 0) {
812
+ process.stderr.write(`[kordoc] \u274C \uAE00\uC790\uB97C \uAC80\uC0AC\uD558\uC9C0 \uBABB\uD55C \uACF3\uC774 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uCD9C\uB825 \uD30C\uC77C\uC744 \uACF5\uAC1C\uD558\uC9C0 \uB9D0\uACE0 \uC218\uB3D9 \uD655\uC778\uD558\uC138\uC694: ${r.unscanned.join(", ")}
813
+ `);
814
+ }
815
+ for (const w of r.warnings) process.stderr.write(`[kordoc] \u26A0\uFE0F ${w}
756
816
  `);
757
817
  }
758
818
  } catch (err) {
@@ -782,7 +842,7 @@ function registerRenderCommands(program2) {
782
842
  const absPath = resolve3(file);
783
843
  const stem = file.replace(/\.hwpx?$/i, "");
784
844
  if (fmt === "svg" && !outDir && !pages && !/\.hwp$/i.test(absPath)) {
785
- const { renderHwpxToSvg } = await import("./render-NGP5T24S.js");
845
+ const { renderHwpxToSvg } = await import("./render-U5PE6V2E.js");
786
846
  const buffer = readFileSync3(absPath);
787
847
  const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode });
788
848
  const outPath = resolve3(output ?? stem + ".svg");
@@ -796,7 +856,7 @@ function registerRenderCommands(program2) {
796
856
  }
797
857
  return;
798
858
  }
799
- const { renderDocument } = await import("./render-NGP5T24S.js");
859
+ const { renderDocument } = await import("./render-U5PE6V2E.js");
800
860
  const { scene, assets } = await renderDocument(absPath, {
801
861
  format: fmt,
802
862
  pages,
@@ -846,7 +906,7 @@ function registerRenderCommands(program2) {
846
906
  if (!outDir) throw new KordocError("--out-dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4 (crop \uC740 \uD30C\uC77C \uC5EC\uB7EC \uAC1C\uB97C \uB0C5\uB2C8\uB2E4)");
847
907
  const types = String(opts.target).split(",").map((t) => t.trim()).filter(Boolean);
848
908
  for (const t of types) if (!["table", "image", "paragraph", "shape"].includes(t)) throw new KordocError(`--target \uC720\uD615 \uC624\uB958: ${t}`);
849
- const { extractRenderedRegions } = await import("./render-NGP5T24S.js");
909
+ const { extractRenderedRegions } = await import("./render-U5PE6V2E.js");
850
910
  const regions = await extractRenderedRegions(resolve3(file), {
851
911
  types,
852
912
  format: fmt,
@@ -884,7 +944,7 @@ function registerRenderCommands(program2) {
884
944
  if (policy !== "none" && !outDir) throw new KordocError("--visual \uC740 crop \uD30C\uC77C\uC744 \uB0B4\uBBC0\uB85C --out-dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4");
885
945
  const cropFmt = String(opts.cropFormat);
886
946
  if (!["png", "jpeg"].includes(cropFmt)) throw new KordocError(`--crop-format \uC740 png|jpeg: ${cropFmt}`);
887
- const { extractTables } = await import("./visual-NZLYIYEM.js");
947
+ const { extractTables } = await import("./visual-5XWMA4EV.js");
888
948
  const tables = await extractTables(resolve3(file), { policy, format: cropFmt, paddingPt: Number(opts.padding) || 0 });
889
949
  const dir = outDir ? resolve3(outDir) : void 0;
890
950
  if (dir) mkdirSync3(dir, { recursive: true });
@@ -928,7 +988,7 @@ function registerRenderCommands(program2) {
928
988
  });
929
989
  program2.command("render-worker").description("persistent \uB80C\uB354 \uC6CC\uCEE4 \u2014 stdin NDJSON \uC694\uCCAD \u2192 \uC870\uD310 SVG \uD30C\uC77C \uCD9C\uB825 (\uD504\uB85C\uC138\uC2A4 \uC720\uC9C0, \uCF5C\uB4DC\uC2A4\uD0C0\uD2B8 \uC81C\uAC70)").action(async () => {
930
990
  const { createInterface } = await import("readline");
931
- const { renderHwpxToSvg } = await import("./render-NGP5T24S.js");
991
+ const { renderHwpxToSvg } = await import("./render-U5PE6V2E.js");
932
992
  const rl = createInterface({ input: process.stdin });
933
993
  const write = (o) => void process.stdout.write(JSON.stringify(o) + "\n");
934
994
  write({ ready: true, version: VERSION });
@@ -977,12 +1037,12 @@ function registerSystemCommands(program2) {
977
1037
  await startMcpServer();
978
1038
  });
979
1039
  program2.command("setup").description("\uB300\uD654\uD615 \uC124\uCE58 \uB9C8\uBC95\uC0AC \u2014 AI \uD074\uB77C\uC774\uC5B8\uD2B8 \uC790\uB3D9 \uB4F1\uB85D (Mac/Win/Linux)").action(async () => {
980
- const { runSetup } = await import("./setup-AU4OCHNH.js");
1040
+ const { runSetup } = await import("./setup-YRDM4ODP.js");
981
1041
  await runSetup();
982
1042
  });
983
1043
  program2.command("check-formula-models").description("PDF \uC218\uC2DD OCR \uBAA8\uB378(MFD + MFR + tokenizer, ~155MB) \uC0C1\uD0DC \uD655\uC778 \u2014 \uC5C6\uAC70\uB098 SHA \uBD88\uC77C\uCE58\uBA74 \uB2E4\uC6B4\uB85C\uB4DC").option("--status-only", "\uC0C1\uD0DC\uB9CC JSON \uC73C\uB85C \uCD9C\uB825 (\uB2E4\uC6B4\uB85C\uB4DC \uC548 \uD568)").action(async (opts) => {
984
1044
  try {
985
- const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import("./formula-5S7WWXGH.js");
1045
+ const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import("./formula-NOIDZEBA.js");
986
1046
  const dir = getFormulaModelsDir();
987
1047
  if (opts.statusOnly) {
988
1048
  const status = await getFormulaModelStatus();
@@ -1036,7 +1096,7 @@ function registerSystemCommands(program2) {
1036
1096
  });
1037
1097
  program2.command("check-ocr-models").description("\uD14D\uC2A4\uD2B8 OCR \uBAA8\uB378(PP-OCRv5 korean det+rec, ~18MB) \uC0C1\uD0DC \uD655\uC778 \u2014 \uC5C6\uAC70\uB098 SHA \uBD88\uC77C\uCE58\uBA74 \uB2E4\uC6B4\uB85C\uB4DC").option("--status-only", "\uC0C1\uD0DC\uB9CC JSON \uC73C\uB85C \uCD9C\uB825 (\uB2E4\uC6B4\uB85C\uB4DC \uC548 \uD568)").action(async (opts) => {
1038
1098
  try {
1039
- const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import("./models-CJPAQK5R.js");
1099
+ const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import("./models-7ELIFTD7.js");
1040
1100
  const dir = getOcrModelsDir();
1041
1101
  if (opts.statusOnly) {
1042
1102
  const status = await getOcrModelStatus();
@@ -1090,7 +1150,7 @@ function registerSystemCommands(program2) {
1090
1150
  });
1091
1151
  program2.command("models").description("OCR/\uC218\uC2DD \uBAA8\uB378 \uC624\uD504\uB77C\uC778 \uC0AC\uC774\uB4DC\uB85C\uB4DC \u2014 \uD3D0\uC1C4\uB9DD \uBC18\uC785\uC6A9 \uB0B4\uBCF4\uB0B4\uAE30/\uAC00\uC838\uC624\uAE30 (SHA-256 \uAC80\uC99D)").option("--status", "\uCE90\uC2DC\uC5D0 \uC124\uCE58\uB41C \uBAA8\uB378 \uC0C1\uD0DC\uB97C JSON \uC73C\uB85C \uCD9C\uB825").option("--export <dir>", "\uB85C\uCEEC \uCE90\uC2DC \u2192 \uBC88\uB4E4 \uB514\uB809\uD1A0\uB9AC\uB85C \uB0B4\uBCF4\uB0B4\uAE30 (\uC628\uB77C\uC778 PC\uC5D0\uC11C \uC2E4\uD589)").option("--import <dir>", "\uBC88\uB4E4 \uB514\uB809\uD1A0\uB9AC \u2192 \uB85C\uCEEC \uCE90\uC2DC\uB85C \uC124\uCE58 (\uB0B4\uBD80\uB9DD PC\uC5D0\uC11C \uC2E4\uD589)").action(async (opts) => {
1092
1152
  try {
1093
- const { exportModels, importModels, modelCacheStatus } = await import("./model-bundle-FSPZZ2EM.js");
1153
+ const { exportModels, importModels, modelCacheStatus } = await import("./model-bundle-57CLEBCO.js");
1094
1154
  if (opts.status) {
1095
1155
  process.stdout.write(JSON.stringify(await modelCacheStatus(), null, 2) + "\n");
1096
1156
  return;
@@ -1126,9 +1186,78 @@ function registerSystemCommands(program2) {
1126
1186
  });
1127
1187
  }
1128
1188
 
1189
+ // src/cli/commands-worker.ts
1190
+ import { readFileSync as readFileSync4, statSync as statSync3 } from "fs";
1191
+ import { resolve as resolve4 } from "path";
1192
+ import { format } from "util";
1193
+ var PARSE_WORKER_PROTOCOL = 1;
1194
+ var MAX_FILE_BYTES = 500 * 1024 * 1024;
1195
+ var bytesToBase64 = (_key, value) => value instanceof Uint8Array ? Buffer.from(value).toString("base64") : value;
1196
+ async function parseOne(req) {
1197
+ const absPath = resolve4(req.file);
1198
+ try {
1199
+ const size = statSync3(absPath).size;
1200
+ if (size > MAX_FILE_BYTES) {
1201
+ return { success: false, fileType: "unknown", error: `\uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${(size / 1024 / 1024).toFixed(1)}MB)`, code: "PARSE_ERROR" };
1202
+ }
1203
+ const options = { filePath: absPath };
1204
+ if (req.images === false) options.images = false;
1205
+ if (req.ocr === "force") options.ocr = "force";
1206
+ else if (req.ocr === "auto") options.ocr = true;
1207
+ if (req.formulaOcr) options.formulaOcr = true;
1208
+ if (req.password) options.password = req.password;
1209
+ return await parse(toArrayBuffer(readFileSync4(absPath)), options);
1210
+ } catch (err) {
1211
+ return { success: false, fileType: "unknown", error: sanitizeError(err), code: classifyError(err) };
1212
+ }
1213
+ }
1214
+ function registerWorkerCommands(program2) {
1215
+ program2.command("parse-worker").description("\uC0C1\uC8FC \uD30C\uC2F1 \uC6CC\uCEE4: stdin NDJSON \uC694\uCCAD \u2192 \uD55C \uC904 JSON \uC751\uB2F5 (\uD504\uB85C\uC138\uC2A4 \uC720\uC9C0, \uD30C\uC77C\uB9C8\uB2E4 node \uB97C \uC0C8\uB85C \uB744\uC6B0\uB294 \uBE44\uC6A9 \uC81C\uAC70)").action(async () => {
1216
+ const toStderr = (...args) => void process.stderr.write(format(...args) + "\n");
1217
+ console.log = toStderr;
1218
+ console.info = toStderr;
1219
+ console.warn = toStderr;
1220
+ console.debug = toStderr;
1221
+ const { createInterface } = await import("readline");
1222
+ const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
1223
+ const write = (o) => void process.stdout.write(JSON.stringify(o, bytesToBase64) + "\n");
1224
+ write({ ready: true, version: VERSION, protocol: PARSE_WORKER_PROTOCOL });
1225
+ for await (const line of rl) {
1226
+ const t = line.trim();
1227
+ if (!t) continue;
1228
+ let req;
1229
+ try {
1230
+ req = JSON.parse(t);
1231
+ } catch {
1232
+ write({ error: "\uC798\uBABB\uB41C JSON \uB77C\uC778" });
1233
+ continue;
1234
+ }
1235
+ if (req === null || typeof req !== "object") {
1236
+ write({ error: "JSON \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4" });
1237
+ continue;
1238
+ }
1239
+ if (req.cmd === "quit") break;
1240
+ const id = req.id;
1241
+ if (typeof req.file !== "string" || !req.file) {
1242
+ write({ id, error: "file \uD544\uC218" });
1243
+ continue;
1244
+ }
1245
+ const result = await parseOne({ ...req, file: req.file });
1246
+ try {
1247
+ write({ id, rss: process.memoryUsage.rss(), result });
1248
+ } catch (err) {
1249
+ write({ id, rss: process.memoryUsage.rss(), result: { success: false, fileType: result.fileType, error: sanitizeError(err), code: classifyError(err) } });
1250
+ }
1251
+ }
1252
+ rl.close();
1253
+ await new Promise((done) => process.stdout.write("", () => done()));
1254
+ process.exit(0);
1255
+ });
1256
+ }
1257
+
1129
1258
  // src/cli.ts
1130
1259
  var program = new Command();
1131
- program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\uACA0\uB2E4 \u2014 HWP, HWPX, PDF, XLSX, DOCX, \uC774\uBBF8\uC9C0(PNG/JPG/WebP) \u2192 Markdown").version(VERSION).argument("<files...>", "\uBCC0\uD658\uD560 \uD30C\uC77C \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP \u2014 \uC774\uBBF8\uC9C0\uB294 OCR \uC790\uB3D9 \uC801\uC6A9)").option("-o, --output <path>", "\uCD9C\uB825 \uD30C\uC77C \uACBD\uB85C (\uB2E8\uC77C \uD30C\uC77C \uC2DC)").option("-d, --out-dir <dir>", "\uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC (\uB2E4\uC911 \uD30C\uC77C \uC2DC)").option("-p, --pages <range>", "\uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: 1-3, 1,3,5) \u2014 \uD55C\uCEF4 \uC800\uC7A5\uBCF8\uC740 \uC2E4\uC81C \uD398\uC774\uC9C0, \uC870\uD310 \uCE90\uC2DC \uC5C6\uC73C\uBA74 \uC139\uC158 \uADFC\uC0AC").option("--format <type>", "\uCD9C\uB825 \uD615\uC2DD: markdown (\uAE30\uBCF8), json, chunks (RAG\uC6A9 \uAD6C\uC870 \uCCAD\uD06C JSON \u2014 \uD5E4\uB529\xB7\uAC1C\uC870\uC2DD \uC704\uACC4 breadcrumb + \uD45C \uB3C5\uB9BD \uCCAD\uD06C)", "markdown").option("--no-header-footer", "PDF \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC790\uB3D9 \uC81C\uAC70 \uB044\uAE30 (\uAE30\uBCF8: \uC81C\uAC70\uD568)").option("--no-tables", "PDF \uD45C \uAC10\uC9C0 \uB044\uAE30 \u2014 \uD14C\uB450\uB9AC \uBC15\uC2A4\uB97C \uD45C\uB85C \uC624\uC778\uD574 \uC77D\uAE30 \uC21C\uC11C\uAC00 \uB4A4\uC9D1\uD788\uB294 \uBB38\uC11C(2\uB2E8 \uC2DC\uD5D8\uC9C0 \uB4F1)\uC5D0\uC11C \uC790\uC5F0 \uC77D\uAE30\uC21C \uD14D\uC2A4\uD2B8\uB9CC \uBF51\uB294\uB2E4 (#64)").option("--formula-ocr", "PDF \uC218\uC2DD OCR \uD65C\uC131\uD654 (MFD+MFR ONNX, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~155MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC)").option("--ocr", "\uC2A4\uCE94/\uC774\uBBF8\uC9C0 PDF \uD14D\uC2A4\uD2B8 OCR (\uB0B4\uC7A5 PP-OCRv5 korean, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~18MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC \u2014 OCR \uD544\uC694 \uD398\uC774\uC9C0\uB9CC \uC778\uC2DD)").option("--ocr-force", "\uC804 \uD398\uC774\uC9C0 \uAC15\uC81C OCR (\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC788\uC5B4\uB3C4 \uBB34\uC2DC\uD558\uACE0 \uC7AC\uC778\uC2DD)").option("--dedupe-headers", "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)").option("--keep-empty-cols", "\uD45C \uC624\uB978\uCABD \uB05D \uBE48 \uC5F4(\uC11C\uC2DD \uC785\uB825\uB780) \uBCF4\uC874 (#47, \uAE30\uBCF8 off: \uD6C4\uD589 \uBE48 \uC5F4 \uD2B8\uB9BC)").option("--keep-empty-paragraphs", "\uBE48 \uBB38\uB2E8 \uBCF4\uC874 \u2014 \uBCF8\uBB38\uC740 \uBE48 paragraph \uBE14\uB85D, \uD45C \uC140\uC740 \uBE48 \uC904\uB85C (#57, \uAE30\uBCF8 off: \uBE48 \uBB38\uB2E8 \uC81C\uAC70)").option("--inline-images", "\uC774\uBBF8\uC9C0\uB97C base64 data URI \uB85C \uB9C8\uD06C\uB2E4\uC6B4\uC5D0 \uC778\uB77C\uC778 (BMP\u2192PNG \uC555\uCD95, HWP5 \uC804\uC6A9 \u2014 \uC778\uB77C\uC778\uB41C \uACBD\uC6B0\uB9CC \uD30C\uC77C \uBBF8\uC800\uC7A5, \uADF8 \uC678 \uD3EC\uB9F7\uC740 \uC800\uC7A5 \uC720\uC9C0)").option("--image-refs", "--format json \uC5D0\uC11C \uC774\uBBF8\uC9C0 \uBC14\uC774\uD2B8\uB97C \uC778\uB77C\uC778\uD558\uC9C0 \uC54A\uACE0 \uD30C\uC77C \uCC38\uC870(images/<\uD30C\uC77C\uBA85>)\uB9CC \uB0A8\uAE40 (#65 \u2014 \uC774\uBBF8\uC9C0\uAC00 \uC218\uBC31 \uC7A5\uC778 \uBB38\uC11C\uC758 \uC9C1\uB82C\uD654 \uD55C\uACC4 \uD68C\uD53C, -o/-d \uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--password <pw>", "\uC554\uD638\uB85C \uBCF4\uD638\uB41C \uBB38\uC11C\uC758 \uC5F4\uAE30 \uC554\uD638 (#59, HWPX\xB7HWP3\xB7HWP5. \uD55C\uCEF4 DRM \uBB38\uC11C\uB294 \uD574\uB2F9 \uC5C6\uC74C)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (files, opts) => {
1260
+ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\uACA0\uB2E4 \u2014 HWP, HWPX, PDF, XLSX, DOCX, \uC774\uBBF8\uC9C0(PNG/JPG/WebP) \u2192 Markdown").version(VERSION).argument("<files...>", "\uBCC0\uD658\uD560 \uD30C\uC77C \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP \u2014 \uC774\uBBF8\uC9C0\uB294 OCR \uC790\uB3D9 \uC801\uC6A9)").option("-o, --output <path>", "\uCD9C\uB825 \uD30C\uC77C \uACBD\uB85C (\uB2E8\uC77C \uD30C\uC77C \uC2DC)").option("-d, --out-dir <dir>", "\uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC (\uB2E4\uC911 \uD30C\uC77C \uC2DC)").option("-p, --pages <range>", "\uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: 1-3, 1,3,5) \u2014 \uD55C\uCEF4 \uC800\uC7A5\uBCF8\uC740 \uC2E4\uC81C \uD398\uC774\uC9C0, \uC870\uD310 \uCE90\uC2DC \uC5C6\uC73C\uBA74 \uC139\uC158 \uADFC\uC0AC").option("--format <type>", "\uCD9C\uB825 \uD615\uC2DD: markdown (\uAE30\uBCF8), json, chunks (RAG\uC6A9 \uAD6C\uC870 \uCCAD\uD06C JSON \u2014 \uD5E4\uB529\xB7\uAC1C\uC870\uC2DD \uC704\uACC4 breadcrumb + \uD45C \uB3C5\uB9BD \uCCAD\uD06C)", "markdown").option("--no-header-footer", "PDF \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC790\uB3D9 \uC81C\uAC70 \uB044\uAE30 (\uAE30\uBCF8: \uC81C\uAC70\uD568)").option("--no-tables", "PDF \uD45C \uAC10\uC9C0 \uB044\uAE30 \u2014 \uD14C\uB450\uB9AC \uBC15\uC2A4\uB97C \uD45C\uB85C \uC624\uC778\uD574 \uC77D\uAE30 \uC21C\uC11C\uAC00 \uB4A4\uC9D1\uD788\uB294 \uBB38\uC11C(2\uB2E8 \uC2DC\uD5D8\uC9C0 \uB4F1)\uC5D0\uC11C \uC790\uC5F0 \uC77D\uAE30\uC21C \uD14D\uC2A4\uD2B8\uB9CC \uBF51\uB294\uB2E4 (#64)").option("--formula-ocr", "PDF \uC218\uC2DD OCR \uD65C\uC131\uD654 (MFD+MFR ONNX, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~155MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC)").option("--ocr", "\uC2A4\uCE94/\uC774\uBBF8\uC9C0 PDF \uD14D\uC2A4\uD2B8 OCR (\uB0B4\uC7A5 PP-OCRv5 korean, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~18MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC \u2014 OCR \uD544\uC694 \uD398\uC774\uC9C0\uB9CC \uC778\uC2DD)").option("--ocr-force", "\uC804 \uD398\uC774\uC9C0 \uAC15\uC81C OCR (\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC788\uC5B4\uB3C4 \uBB34\uC2DC\uD558\uACE0 \uC7AC\uC778\uC2DD)").option("--dedupe-headers", "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)").option("--keep-empty-cols", "\uD45C \uC624\uB978\uCABD \uB05D \uBE48 \uC5F4(\uC11C\uC2DD \uC785\uB825\uB780) \uBCF4\uC874 (#47, \uAE30\uBCF8 off: \uD6C4\uD589 \uBE48 \uC5F4 \uD2B8\uB9BC)").option("--keep-empty-paragraphs", "\uBE48 \uBB38\uB2E8 \uBCF4\uC874 \u2014 \uBCF8\uBB38\uC740 \uBE48 paragraph \uBE14\uB85D, \uD45C \uC140\uC740 \uBE48 \uC904\uB85C (#57, \uAE30\uBCF8 off: \uBE48 \uBB38\uB2E8 \uC81C\uAC70)").option("--inline-images", "\uC774\uBBF8\uC9C0\uB97C base64 data URI \uB85C \uB9C8\uD06C\uB2E4\uC6B4\uC5D0 \uC778\uB77C\uC778 (BMP\u2192PNG \uC555\uCD95, HWP5 \uC804\uC6A9 \u2014 \uC778\uB77C\uC778\uB41C \uACBD\uC6B0\uB9CC \uD30C\uC77C \uBBF8\uC800\uC7A5, \uADF8 \uC678 \uD3EC\uB9F7\uC740 \uC800\uC7A5 \uC720\uC9C0)").option("--image-refs", "--format json \uC5D0\uC11C \uC774\uBBF8\uC9C0 \uBC14\uC774\uD2B8\uB97C \uC778\uB77C\uC778\uD558\uC9C0 \uC54A\uACE0 \uD30C\uC77C \uCC38\uC870(images/<\uD30C\uC77C\uBA85>)\uB9CC \uB0A8\uAE40 (#65 \u2014 \uC774\uBBF8\uC9C0\uAC00 \uC218\uBC31 \uC7A5\uC778 \uBB38\uC11C\uC758 \uC9C1\uB82C\uD654 \uD55C\uACC4 \uD68C\uD53C, -o/-d \uC640 \uD568\uAED8 \uC0AC\uC6A9)").option("--password <pw>", "\uC554\uD638\uB85C \uBCF4\uD638\uB41C \uBB38\uC11C\uC758 \uC5F4\uAE30 \uC554\uD638 (#59, HWPX\xB7HWP3\xB7HWP5. \uD55C\uCEF4 DRM \uBB38\uC11C\uB294 \uD574\uB2F9 \uC5C6\uC74C)").option("--no-images", "\uC774\uBBF8\uC9C0 \uBC14\uC774\uD2B8\uB97C \uCD94\uCD9C\xB7\uCD9C\uB825\uD558\uC9C0 \uC54A\uC74C: \uAE00\uC790\uB9CC \uD544\uC694\uD560 \uB54C (\uADF8\uB9BC \uC790\uB9AC \uD45C\uC2DC\uB294 \uB0A8\uAE40, PDF \uB294 PNG \uC778\uCF54\uB529\uC744 \uAC74\uB108\uB700)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (files, opts) => {
1132
1261
  const validFormats = ["markdown", "json", "chunks"];
1133
1262
  if (!validFormats.includes(opts.format)) {
1134
1263
  process.stderr.write(`[kordoc] \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD615\uC2DD: ${opts.format} (markdown, json, chunks)
@@ -1141,12 +1270,12 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1141
1270
  }
1142
1271
  for (let fi = 0; fi < files.length; fi++) {
1143
1272
  const filePath = files[fi];
1144
- const absPath = resolve4(filePath);
1273
+ const absPath = resolve5(filePath);
1145
1274
  const fileName = basename3(absPath);
1146
1275
  const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : "";
1147
1276
  let detectedFormat = "unknown";
1148
1277
  try {
1149
- const fileSize = statSync2(absPath).size;
1278
+ const fileSize = statSync4(absPath).size;
1150
1279
  if (fileSize > 500 * 1024 * 1024) {
1151
1280
  process.stderr.write(`
1152
1281
  [kordoc] SKIP: ${fileName} \u2014 \uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${(fileSize / 1024 / 1024).toFixed(1)}MB)
@@ -1154,12 +1283,12 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1154
1283
  process.exitCode = 1;
1155
1284
  continue;
1156
1285
  }
1157
- const buffer = readFileSync4(absPath);
1286
+ const buffer = readFileSync5(absPath);
1158
1287
  const arrayBuffer = toArrayBuffer(buffer);
1159
- const format = detectFormat(arrayBuffer);
1160
- detectedFormat = format;
1288
+ const format2 = detectFormat(arrayBuffer);
1289
+ detectedFormat = format2;
1161
1290
  if (!opts.silent) {
1162
- process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`);
1291
+ process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format2}) ...`);
1163
1292
  }
1164
1293
  const parseOptions = { filePath: absPath };
1165
1294
  if (opts.pages) parseOptions.pages = opts.pages;
@@ -1173,9 +1302,10 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1173
1302
  if (opts.keepEmptyParagraphs) parseOptions.keepEmptyParagraphs = true;
1174
1303
  if (opts.inlineImages) parseOptions.inlineImages = true;
1175
1304
  if (opts.password) parseOptions.password = opts.password;
1305
+ if (opts.images === false) parseOptions.images = false;
1176
1306
  if (!opts.silent) {
1177
1307
  parseOptions.onProgress = (current, total) => {
1178
- process.stderr.write(`\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`);
1308
+ process.stderr.write(`\r[kordoc] ${filePrefix}${fileName} (${format2}) [${current}/${total}]`);
1179
1309
  };
1180
1310
  }
1181
1311
  const result = await parse(arrayBuffer, parseOptions);
@@ -1216,17 +1346,17 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1216
1346
  `);
1217
1347
  }
1218
1348
  } else if (opts.format === "chunks") {
1219
- const { blocksToChunks } = await import("./chunks-SX77P5CV.js");
1349
+ const { blocksToChunks } = await import("./chunks-I7TEMJXH.js");
1220
1350
  output = JSON.stringify(blocksToChunks(result.blocks), null, 2);
1221
1351
  } else {
1222
1352
  output = markdown;
1223
1353
  }
1224
1354
  const saveImages = (dir) => {
1225
1355
  if (!result.images?.length || imagesInlined) return;
1226
- const imgDir = resolve4(dir, "images");
1356
+ const imgDir = resolve5(dir, "images");
1227
1357
  mkdirSync4(imgDir, { recursive: true });
1228
1358
  for (const img of result.images) {
1229
- writeFileSync4(resolve4(imgDir, img.filename), img.data);
1359
+ writeFileSync4(resolve5(imgDir, img.filename), img.data);
1230
1360
  }
1231
1361
  const manifest = result.images.map((img) => ({
1232
1362
  name: img.filename,
@@ -1234,7 +1364,7 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1234
1364
  bytes: img.data.length,
1235
1365
  ...img.source ? { source: img.source } : {}
1236
1366
  }));
1237
- writeFileSync4(resolve4(imgDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
1367
+ writeFileSync4(resolve5(imgDir, "manifest.json"), JSON.stringify(manifest, null, 2), "utf-8");
1238
1368
  if (!opts.silent) process.stderr.write(` \u2192 ${result.images.length}\uAC1C \uC774\uBBF8\uC9C0 \u2192 ${imgDir} (manifest.json \uD3EC\uD568)
1239
1369
  `);
1240
1370
  };
@@ -1242,11 +1372,11 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
1242
1372
  writeFileSync4(opts.output, output, "utf-8");
1243
1373
  if (!opts.silent) process.stderr.write(` \u2192 ${opts.output}
1244
1374
  `);
1245
- saveImages(resolve4(opts.output, ".."));
1375
+ saveImages(resolve5(opts.output, ".."));
1246
1376
  } else if (opts.outDir) {
1247
1377
  mkdirSync4(opts.outDir, { recursive: true });
1248
1378
  const outExt = opts.format === "json" ? ".json" : opts.format === "chunks" ? ".chunks.json" : ".md";
1249
- const outPath = resolve4(opts.outDir, fileName.replace(/\.[^.]+$/, outExt));
1379
+ const outPath = resolve5(opts.outDir, fileName.replace(/\.[^.]+$/, outExt));
1250
1380
  writeFileSync4(outPath, output, "utf-8");
1251
1381
  if (!opts.silent) process.stderr.write(` \u2192 ${outPath}
1252
1382
  `);
@@ -1272,5 +1402,6 @@ registerDocCommands(program);
1272
1402
  registerGenerateCommands(program);
1273
1403
  registerRenderCommands(program);
1274
1404
  registerSystemCommands(program);
1405
+ registerWorkerCommands(program);
1275
1406
  program.parse();
1276
1407
  //# sourceMappingURL=cli.js.map