kordoc 4.19.2 → 4.20.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 (124) hide show
  1. package/NOTICE +25 -0
  2. package/README.md +2 -1
  3. package/THIRD_PARTY/hwp-auto-docfit.LICENSE +23 -0
  4. package/dist/{-3JIHF2AL.js → -TTRGLREH.js} +11 -11
  5. package/dist/{chunk-I2TBI7PN.js → chunk-2U475PJF.js} +2 -2
  6. package/dist/{chunk-R2JM2HOJ.js → chunk-4DIMX2KU.js} +4 -4
  7. package/dist/{chunk-GNUGD4RO.js → chunk-4WOG2SLT.js} +2 -2
  8. package/dist/{chunk-QZ63HXEG.js → chunk-527NBMUE.js} +6 -6
  9. package/dist/{chunk-PWQ2BVAT.js → chunk-7H5GT7HM.js} +22 -3
  10. package/dist/{chunk-PWQ2BVAT.js.map → chunk-7H5GT7HM.js.map} +1 -1
  11. package/dist/{chunk-T2DZTOGG.cjs → chunk-AXQDWE42.cjs} +12 -12
  12. package/dist/{chunk-T2DZTOGG.cjs.map → chunk-AXQDWE42.cjs.map} +1 -1
  13. package/dist/{chunk-ORGWGR4K.cjs → chunk-CJFIHH2N.cjs} +6 -6
  14. package/dist/{chunk-ORGWGR4K.cjs.map → chunk-CJFIHH2N.cjs.map} +1 -1
  15. package/dist/{chunk-XPM7WC54.js → chunk-CKFKC22O.js} +4 -4
  16. package/dist/{chunk-JK7N4R4K.js → chunk-CPZ2LLZA.js} +2 -2
  17. package/dist/{chunk-6ZBORHFB.js → chunk-CS2VWXDS.js} +2 -2
  18. package/dist/{chunk-EUCBMW6C.js → chunk-DPD2L5UK.js} +3 -3
  19. package/dist/{chunk-AOVMOCTK.js → chunk-GHAJHXYA.js} +2 -2
  20. package/dist/{chunk-4CS7XE2Q.js → chunk-JYV3XQYW.js} +2 -2
  21. package/dist/{chunk-MZ6XNFZL.cjs → chunk-K5GCIB2I.cjs} +2 -2
  22. package/dist/{chunk-MZ6XNFZL.cjs.map → chunk-K5GCIB2I.cjs.map} +1 -1
  23. package/dist/{chunk-5PGOZBEQ.cjs → chunk-KDCPBF4X.cjs} +22 -22
  24. package/dist/{chunk-5PGOZBEQ.cjs.map → chunk-KDCPBF4X.cjs.map} +1 -1
  25. package/dist/{chunk-NV46IWKF.js → chunk-LQ4IDHET.js} +234 -24
  26. package/dist/chunk-LQ4IDHET.js.map +1 -0
  27. package/dist/{chunk-U6AJU2VD.js → chunk-MNPPMJBN.js} +2 -2
  28. package/dist/{chunk-J75TVRJB.js → chunk-MXADBQ7E.js} +2 -2
  29. package/dist/{chunk-B4R443MV.js → chunk-NVBX2NKZ.js} +2 -2
  30. package/dist/{chunk-TM4T4NYJ.js → chunk-OX5FA2MU.js} +2 -2
  31. package/dist/{chunk-WQAGDJIP.cjs → chunk-RMDFN5ZF.cjs} +3 -3
  32. package/dist/{chunk-WQAGDJIP.cjs.map → chunk-RMDFN5ZF.cjs.map} +1 -1
  33. package/dist/{chunk-QYJPU4FZ.js → chunk-TM7IOP4P.js} +2 -2
  34. package/dist/{chunk-OKHKEYTL.js → chunk-URQM5TBD.js} +2 -2
  35. package/dist/{chunk-VO22VAR3.js → chunk-VVKMBLG2.js} +2 -2
  36. package/dist/{chunk-JXJDXDOU.js → chunk-WLNEQGQC.js} +3 -3
  37. package/dist/{chunk-56ZWAREM.js → chunk-WLWWODBQ.js} +2 -2
  38. package/dist/{chunk-RVBQT2PD.cjs → chunk-WWOU6ZQ3.cjs} +3 -3
  39. package/dist/{chunk-RVBQT2PD.cjs.map → chunk-WWOU6ZQ3.cjs.map} +1 -1
  40. package/dist/{chunk-AKSCTGKG.js → chunk-X5YHJHWB.js} +2 -2
  41. package/dist/chunks-3NIFJFRQ.js +10 -0
  42. package/dist/cli.js +366 -44
  43. package/dist/cli.js.map +1 -1
  44. package/dist/{formula-STIFIS57.js → formula-D6GGALWI.js} +3 -3
  45. package/dist/{formula-RNATQ3FQ.cjs → formula-FE6LEZTT.cjs} +9 -9
  46. package/dist/{formula-RNATQ3FQ.cjs.map → formula-FE6LEZTT.cjs.map} +1 -1
  47. package/dist/{formula-RSTTP626.js → formula-KWOAYEOG.js} +4 -4
  48. package/dist/{image-ocr-XKSAEEXP.js → image-ocr-XDODV43Y.js} +9 -9
  49. package/dist/{image-ocr-7L5TBBPA.cjs → image-ocr-XGGIYCZ2.cjs} +15 -15
  50. package/dist/{image-ocr-7L5TBBPA.cjs.map → image-ocr-XGGIYCZ2.cjs.map} +1 -1
  51. package/dist/{image-ocr-R6ZDFBAN.js → image-ocr-YYTFOUSY.js} +6 -6
  52. package/dist/index.cjs +682 -459
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +5 -0
  55. package/dist/index.d.ts +5 -0
  56. package/dist/index.js +242 -19
  57. package/dist/index.js.map +1 -1
  58. package/dist/mcp.js +22 -22
  59. package/dist/{model-bundle-NGTKULP7.js → model-bundle-WPFLIKYM.js} +5 -5
  60. package/dist/{models-QOSU5SYL.js → models-WJ5QYELV.js} +5 -5
  61. package/dist/{parser-AIQBU7FS.cjs → parser-6P5ZRWXG.cjs} +132 -132
  62. package/dist/{parser-AIQBU7FS.cjs.map → parser-6P5ZRWXG.cjs.map} +1 -1
  63. package/dist/{parser-5GUEP6EK.js → parser-LY67CB7A.js} +8 -8
  64. package/dist/{parser-3G4G6SST.js → parser-QKLUIMHG.js} +11 -11
  65. package/dist/pdf-ocr-6L4EDRVO.js +20 -0
  66. package/dist/pdf-ocr-J7DHJJ3I.js +16 -0
  67. package/dist/pdf-ocr-MODN6GBT.cjs +17 -0
  68. package/dist/{pdf-ocr-7OAFUDM4.cjs.map → pdf-ocr-MODN6GBT.cjs.map} +1 -1
  69. package/dist/{profile-io-ZVNMDLLS.js → profile-io-I4ORJOE4.js} +3 -3
  70. package/dist/{rasterize-Y2RLMVCL.js → rasterize-MZU5LIA5.js} +3 -3
  71. package/dist/{redact-doc-PNRDDBI3.js → redact-doc-NEUEBXFH.js} +11 -11
  72. package/dist/{render-S3ALARVO.js → render-IL2DYXDP.js} +7 -7
  73. package/dist/seal-O5DKZGTR.js +10 -0
  74. package/dist/{setup-JH66VSFZ.js → setup-PGOCB7YG.js} +3 -3
  75. package/dist/visual-PYV4ZMLH.js +20 -0
  76. package/dist/{watch-KMB2FTOD.js → watch-2F5AMHCW.js} +12 -12
  77. package/package.json +1 -1
  78. package/dist/chunk-NV46IWKF.js.map +0 -1
  79. package/dist/chunks-2EC2R7PY.js +0 -10
  80. package/dist/pdf-ocr-7OAFUDM4.cjs +0 -17
  81. package/dist/pdf-ocr-DAXS5RX4.js +0 -16
  82. package/dist/pdf-ocr-R3VGX6F2.js +0 -20
  83. package/dist/seal-EJWPS5VK.js +0 -10
  84. package/dist/visual-GDXMKDVY.js +0 -20
  85. /package/dist/{-3JIHF2AL.js.map → -TTRGLREH.js.map} +0 -0
  86. /package/dist/{chunk-I2TBI7PN.js.map → chunk-2U475PJF.js.map} +0 -0
  87. /package/dist/{chunk-R2JM2HOJ.js.map → chunk-4DIMX2KU.js.map} +0 -0
  88. /package/dist/{chunk-GNUGD4RO.js.map → chunk-4WOG2SLT.js.map} +0 -0
  89. /package/dist/{chunk-QZ63HXEG.js.map → chunk-527NBMUE.js.map} +0 -0
  90. /package/dist/{chunk-XPM7WC54.js.map → chunk-CKFKC22O.js.map} +0 -0
  91. /package/dist/{chunk-JK7N4R4K.js.map → chunk-CPZ2LLZA.js.map} +0 -0
  92. /package/dist/{chunk-6ZBORHFB.js.map → chunk-CS2VWXDS.js.map} +0 -0
  93. /package/dist/{chunk-EUCBMW6C.js.map → chunk-DPD2L5UK.js.map} +0 -0
  94. /package/dist/{chunk-AOVMOCTK.js.map → chunk-GHAJHXYA.js.map} +0 -0
  95. /package/dist/{chunk-4CS7XE2Q.js.map → chunk-JYV3XQYW.js.map} +0 -0
  96. /package/dist/{chunk-U6AJU2VD.js.map → chunk-MNPPMJBN.js.map} +0 -0
  97. /package/dist/{chunk-J75TVRJB.js.map → chunk-MXADBQ7E.js.map} +0 -0
  98. /package/dist/{chunk-B4R443MV.js.map → chunk-NVBX2NKZ.js.map} +0 -0
  99. /package/dist/{chunk-TM4T4NYJ.js.map → chunk-OX5FA2MU.js.map} +0 -0
  100. /package/dist/{chunk-QYJPU4FZ.js.map → chunk-TM7IOP4P.js.map} +0 -0
  101. /package/dist/{chunk-OKHKEYTL.js.map → chunk-URQM5TBD.js.map} +0 -0
  102. /package/dist/{chunk-VO22VAR3.js.map → chunk-VVKMBLG2.js.map} +0 -0
  103. /package/dist/{chunk-JXJDXDOU.js.map → chunk-WLNEQGQC.js.map} +0 -0
  104. /package/dist/{chunk-56ZWAREM.js.map → chunk-WLWWODBQ.js.map} +0 -0
  105. /package/dist/{chunk-AKSCTGKG.js.map → chunk-X5YHJHWB.js.map} +0 -0
  106. /package/dist/{chunks-2EC2R7PY.js.map → chunks-3NIFJFRQ.js.map} +0 -0
  107. /package/dist/{formula-STIFIS57.js.map → formula-D6GGALWI.js.map} +0 -0
  108. /package/dist/{formula-RSTTP626.js.map → formula-KWOAYEOG.js.map} +0 -0
  109. /package/dist/{image-ocr-XKSAEEXP.js.map → image-ocr-XDODV43Y.js.map} +0 -0
  110. /package/dist/{image-ocr-R6ZDFBAN.js.map → image-ocr-YYTFOUSY.js.map} +0 -0
  111. /package/dist/{model-bundle-NGTKULP7.js.map → model-bundle-WPFLIKYM.js.map} +0 -0
  112. /package/dist/{models-QOSU5SYL.js.map → models-WJ5QYELV.js.map} +0 -0
  113. /package/dist/{parser-5GUEP6EK.js.map → parser-LY67CB7A.js.map} +0 -0
  114. /package/dist/{parser-3G4G6SST.js.map → parser-QKLUIMHG.js.map} +0 -0
  115. /package/dist/{pdf-ocr-DAXS5RX4.js.map → pdf-ocr-6L4EDRVO.js.map} +0 -0
  116. /package/dist/{pdf-ocr-R3VGX6F2.js.map → pdf-ocr-J7DHJJ3I.js.map} +0 -0
  117. /package/dist/{profile-io-ZVNMDLLS.js.map → profile-io-I4ORJOE4.js.map} +0 -0
  118. /package/dist/{rasterize-Y2RLMVCL.js.map → rasterize-MZU5LIA5.js.map} +0 -0
  119. /package/dist/{redact-doc-PNRDDBI3.js.map → redact-doc-NEUEBXFH.js.map} +0 -0
  120. /package/dist/{render-S3ALARVO.js.map → render-IL2DYXDP.js.map} +0 -0
  121. /package/dist/{seal-EJWPS5VK.js.map → seal-O5DKZGTR.js.map} +0 -0
  122. /package/dist/{setup-JH66VSFZ.js.map → setup-PGOCB7YG.js.map} +0 -0
  123. /package/dist/{visual-GDXMKDVY.js.map → visual-PYV4ZMLH.js.map} +0 -0
  124. /package/dist/{watch-KMB2FTOD.js.map → watch-2F5AMHCW.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  parseFormatProfileJson
4
- } from "./chunk-4CS7XE2Q.js";
4
+ } from "./chunk-JYV3XQYW.js";
5
5
  import {
6
6
  BODY_FONTS,
7
7
  BULLET2_CHARS,
@@ -16,6 +16,7 @@ import {
16
16
  PRESET_ALIAS,
17
17
  extractClickHereFields,
18
18
  extractFormFields,
19
+ extractHwpxStyles,
19
20
  fillFormFields,
20
21
  fillHwpx,
21
22
  fillWithUniqueGuard,
@@ -27,38 +28,46 @@ import {
27
28
  markdownToHwpx,
28
29
  muncheLintWarnings,
29
30
  parse,
31
+ parseLeadingMarker,
32
+ parseMarkdownToBlocks,
30
33
  readBuiltinTemplate,
31
34
  resolveBuiltinTemplate,
35
+ resolveSectionPaths,
32
36
  toHtmlTables,
33
37
  toPlainMarkdown,
34
38
  unknownFontWarnings,
35
39
  usesGaejosikMunche
36
- } from "./chunk-NV46IWKF.js";
37
- import "./chunk-VO22VAR3.js";
38
- import "./chunk-PWQ2BVAT.js";
40
+ } from "./chunk-LQ4IDHET.js";
41
+ import "./chunk-VVKMBLG2.js";
42
+ import "./chunk-7H5GT7HM.js";
39
43
  import "./chunk-3WSNLH4B.js";
40
- import "./chunk-TM4T4NYJ.js";
44
+ import "./chunk-OX5FA2MU.js";
41
45
  import {
42
46
  detectFormat,
43
47
  detectImageMime,
44
48
  detectZipFormat
45
- } from "./chunk-QZ63HXEG.js";
49
+ } from "./chunk-527NBMUE.js";
46
50
  import "./chunk-7FCNOKOR.js";
47
- import "./chunk-AOVMOCTK.js";
51
+ import "./chunk-GHAJHXYA.js";
48
52
  import "./chunk-VQFA55IC.js";
49
- import "./chunk-QYJPU4FZ.js";
53
+ import {
54
+ createXmlParser,
55
+ readZipEntry
56
+ } from "./chunk-TM7IOP4P.js";
50
57
  import {
51
58
  blocksToMarkdown
52
- } from "./chunk-B4R443MV.js";
53
- import "./chunk-6ZBORHFB.js";
59
+ } from "./chunk-NVBX2NKZ.js";
60
+ import "./chunk-CS2VWXDS.js";
54
61
  import {
55
62
  KordocError,
56
63
  VERSION,
57
64
  classifyError,
65
+ precheckZipSize,
58
66
  routeConsoleToStderr,
59
67
  sanitizeError,
68
+ stripDtd,
60
69
  toArrayBuffer
61
- } from "./chunk-OKHKEYTL.js";
70
+ } from "./chunk-URQM5TBD.js";
62
71
 
63
72
  // src/cli.ts
64
73
  import { Command } from "commander";
@@ -187,7 +196,7 @@ async function convertFiles(files, opts, writeOutput = (text) => {
187
196
  `);
188
197
  }
189
198
  } else if (opts.format === "chunks") {
190
- const { blocksToChunks } = await import("./chunks-2EC2R7PY.js");
199
+ const { blocksToChunks } = await import("./chunks-3NIFJFRQ.js");
191
200
  const chunks = blocksToChunks(result.blocks, { tableFormat: parseOptions.tableFormat }).map((c) => {
192
201
  let text = c.text;
193
202
  if (opts.plain) text = toPlainMarkdown(text);
@@ -355,7 +364,7 @@ function registerDocCommands(program2) {
355
364
  if (command.getOptionValueSource("format") === "default" && program2.getOptionValueSource("format") === "cli") {
356
365
  opts.format = rootOpts.format;
357
366
  }
358
- const { watchDirectory } = await import("./watch-KMB2FTOD.js");
367
+ const { watchDirectory } = await import("./watch-2F5AMHCW.js");
359
368
  await watchDirectory({
360
369
  dir,
361
370
  outDir: opts.outDir,
@@ -582,7 +591,7 @@ function registerDocCommands(program2) {
582
591
  });
583
592
  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) => {
584
593
  try {
585
- const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-3JIHF2AL.js");
594
+ const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-TTRGLREH.js");
586
595
  const rootOpts = program2.opts();
587
596
  const output = opts.output ?? rootOpts.output;
588
597
  const silent = opts.silent ?? rootOpts.silent;
@@ -658,9 +667,9 @@ function registerDocCommands(program2) {
658
667
  process.exit(1);
659
668
  }
660
669
  });
661
- 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) => {
670
+ 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("--json", "\uACB0\uACFC(\uC801\uC6A9 \uC218\xB7\uAC74\uB108\uB6F4 \uD3B8\uC9D1\xB7\uAC80\uC99D \uC794\uCC28)\uB97C JSON \uC73C\uB85C stdout \uCD9C\uB825 \u2014 --silent \uC640 \uD568\uAED8 \uC368\uB3C4 \uB098\uC628\uB2E4").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (original, edited, opts) => {
662
671
  try {
663
- const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-3JIHF2AL.js");
672
+ const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-TTRGLREH.js");
664
673
  const rootOpts = program2.opts();
665
674
  const output = opts.output ?? rootOpts.output;
666
675
  const silent = opts.silent ?? rootOpts.silent;
@@ -669,6 +678,7 @@ function registerDocCommands(program2) {
669
678
  const format = detectFormat2(originalBuf.buffer);
670
679
  const result = format === "hwp" ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false }) : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false });
671
680
  if (!result.success || !result.data) {
681
+ if (opts.json) process.stdout.write(JSON.stringify({ success: false, error: result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958", applied: result.applied, skipped: result.skipped }, null, 2) + "\n");
672
682
  process.stderr.write(`[kordoc] \uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}
673
683
  `);
674
684
  process.exit(1);
@@ -677,7 +687,16 @@ function registerDocCommands(program2) {
677
687
  const outPath = resolve3(output ?? original.replace(/\.hwpx?$/i, "") + ".patched" + ext);
678
688
  mkdirSync2(dirname(outPath), { recursive: true });
679
689
  writeFileSync2(outPath, result.data);
680
- if (!silent) {
690
+ if (opts.json) {
691
+ process.stdout.write(JSON.stringify({
692
+ success: true,
693
+ output: outPath,
694
+ applied: result.applied,
695
+ skipped: result.skipped,
696
+ ...result.verification ? { verification: result.verification.stats } : {}
697
+ }, null, 2) + "\n");
698
+ }
699
+ if (!silent && !opts.json) {
681
700
  process.stderr.write(`[kordoc] ${result.applied}\uAC1C \uBCC0\uACBD \uC801\uC6A9 (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874) \u2192 ${outPath}
682
701
  `);
683
702
  for (const s of result.skipped) {
@@ -699,9 +718,40 @@ function registerDocCommands(program2) {
699
718
  process.exit(1);
700
719
  }
701
720
  });
721
+ program2.command("compare <a> <b>").description("\uB450 \uBB38\uC11C \uBE44\uAD50 \u2014 \uCD94\uAC00\xB7\uC0AD\uC81C\xB7\uBCC0\uACBD \uBE14\uB85D (HWP\u2194HWPX \uB4F1 \uD615\uC2DD\uC774 \uB2EC\uB77C\uB3C4 \uB428, \uC2E0\uAD6C\uB300\uC870\uD45C\uC6A9). \uCC28\uC774\uAC00 \uC788\uC73C\uBA74 exit 1").option("--json", "\uBE44\uAD50 \uACB0\uACFC(stats\xB7diffs)\uB97C JSON \uC73C\uB85C stdout \uCD9C\uB825").action(async (a, b, opts) => {
722
+ try {
723
+ const { compare } = await import("./-TTRGLREH.js");
724
+ const read = (p) => {
725
+ const buf = readFileSync2(resolve3(p));
726
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
727
+ };
728
+ const result = await compare(read(a), read(b));
729
+ const { stats, diffs } = result;
730
+ if (opts.json) process.stdout.write(JSON.stringify(result, null, 2) + "\n");
731
+ else {
732
+ process.stdout.write(`\uCD94\uAC00 ${stats.added} \xB7 \uC0AD\uC81C ${stats.removed} \xB7 \uBCC0\uACBD ${stats.modified} \xB7 \uB3D9\uC77C ${stats.unchanged}
733
+ `);
734
+ for (const d of diffs) {
735
+ if (d.type === "unchanged") continue;
736
+ const mark = d.type === "added" ? "+" : d.type === "removed" ? "-" : "~";
737
+ const text = (blk) => (blk?.text ?? (blk?.table ? "[\uD45C]" : "")).replace(/\s+/g, " ").slice(0, 160);
738
+ if (d.type === "modified") process.stdout.write(`~ ${text(d.before)}
739
+ \u2192 ${text(d.after)}
740
+ `);
741
+ else process.stdout.write(`${mark} ${text(d.after ?? d.before)}
742
+ `);
743
+ }
744
+ }
745
+ process.exit(stats.added + stats.removed + stats.modified > 0 ? 1 : 0);
746
+ } catch (err) {
747
+ process.stderr.write(`[kordoc] \uC624\uB958: ${sanitizeError(err)}
748
+ `);
749
+ process.exit(2);
750
+ }
751
+ });
702
752
  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) => {
703
753
  try {
704
- const { validateHwpx } = await import("./-3JIHF2AL.js");
754
+ const { validateHwpx } = await import("./-TTRGLREH.js");
705
755
  const buf = new Uint8Array(readFileSync2(resolve3(file)));
706
756
  const result = await validateHwpx(buf);
707
757
  if (opts.json) {
@@ -729,8 +779,224 @@ function registerDocCommands(program2) {
729
779
  // src/cli/commands-generate.ts
730
780
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, statSync as statSync4 } from "fs";
731
781
  import { basename as basename5, dirname as dirname2, resolve as resolve4 } from "path";
782
+
783
+ // src/hwpx/number-lint.ts
784
+ var UNIT = String.raw`억\s?원|조\s?원|백만\s?원|천만\s?원|천\s?원|만\s?원|원|%p|%p|%|%|명|건|개소|곳|대|가구|세대|톤|㎡|㎢|km|㎞`;
785
+ var NUM = String.raw`\d{1,3}(?:,\d{3})+(?:\.\d+)?|\d+(?:\.\d+)?`;
786
+ var UNIT_END = String.raw`(?=$|[^가-힣A-Za-z]|(?:으로|에서|까지|부터|보다|이며|이고|은|는|이|가|을|를|의|에|로|과|와|도|만|씩)(?![가-힣A-Za-z]))`;
787
+ var VALUE_UNIT = new RegExp(String.raw`(?<![\d.,])(${NUM})\s?(${UNIT})${UNIT_END}`, "g");
788
+ var BARE_NUMBER = new RegExp(String.raw`(?<![\d.])(${NUM})`, "g");
789
+ var TABLE_UNIT_NOTE = new RegExp(String.raw`[((]\s*(?:단위\s*[::]\s*)?(${UNIT})\s*[))]|단위\s*[::]\s*(${UNIT})`, "g");
790
+ var MIN_TABLE_NUMBERS = 5;
791
+ var THRESHOLD_AFTER = /^\s?(?:이상|이하|초과|미만|내외|수준|안팎|가량|정도)/;
792
+ var THRESHOLD_BEFORE = /(?:목표|기준|상한|하한|최소|최대|약)[^\d]{0,8}$/;
793
+ var NEAR = 3;
794
+ var FIND_WINDOW = 10;
795
+ var normNumber = (v) => {
796
+ const s = v.replace(/,/g, "");
797
+ return s.includes(".") ? s.replace(/0+$/, "").replace(/\.$/, "") : s;
798
+ };
799
+ var normUnit = (u) => u.replace(/\s/g, "").replace(/%/g, "%");
800
+ function tableNumbers(rows) {
801
+ const all = /* @__PURE__ */ new Set();
802
+ for (const row of rows) for (const cell of row) for (const m of (cell ?? "").matchAll(BARE_NUMBER)) all.add(normNumber(m[1]));
803
+ const byUnit = /* @__PURE__ */ new Map();
804
+ const add = (unit, values) => {
805
+ const set = byUnit.get(unit) ?? /* @__PURE__ */ new Set();
806
+ for (const v of values) set.add(v);
807
+ byUnit.set(unit, set);
808
+ };
809
+ for (const row of rows) {
810
+ for (const cell of row) {
811
+ for (const m of (cell ?? "").matchAll(VALUE_UNIT)) add(normUnit(m[2]), [normNumber(m[1])]);
812
+ for (const m of (cell ?? "").matchAll(TABLE_UNIT_NOTE)) add(normUnit(m[1] ?? m[2]), all);
813
+ }
814
+ }
815
+ return { byUnit, all, count: all.size };
816
+ }
817
+ function checkTableNumbers(blocks) {
818
+ const tables = blocks.flatMap((b, i) => {
819
+ if (b.type !== "table" || !b.rows) return [];
820
+ const t = tableNumbers(b.rows);
821
+ return t.count >= MIN_TABLE_NUMBERS ? [{ i, byUnit: t.byUnit, all: t.all }] : [];
822
+ });
823
+ let checked = 0;
824
+ const review = [];
825
+ blocks.forEach((b, i) => {
826
+ if (b.type !== "text" || !b.text) return;
827
+ const near = tables.filter((t) => Math.abs(t.i - i) <= NEAR);
828
+ if (!near.length) return;
829
+ const seen = /* @__PURE__ */ new Set();
830
+ for (const m of b.text.matchAll(VALUE_UNIT)) {
831
+ const at = m.index, end = at + m[0].length;
832
+ if (THRESHOLD_AFTER.test(b.text.slice(end)) || THRESHOLD_BEFORE.test(b.text.slice(Math.max(0, at - 12), at))) continue;
833
+ const key = m[0].replace(/\s/g, "");
834
+ if (seen.has(key)) continue;
835
+ seen.add(key);
836
+ const unit = normUnit(m[2]);
837
+ if (!near.some((t) => t.byUnit.has(unit))) continue;
838
+ checked++;
839
+ const value = normNumber(m[1]);
840
+ const distinctive = value.includes(".") || value.replace(/^0+/, "").length >= 3;
841
+ const found = tables.some((t) => Math.abs(t.i - i) <= FIND_WINDOW && (t.byUnit.get(unit)?.has(value) || distinctive && t.all.has(value)));
842
+ if (!found) {
843
+ review.push({ match: `${m[1]}${m[2]}`, context: b.text.replace(/\s+/g, " ").trim().slice(0, 80) });
844
+ }
845
+ }
846
+ });
847
+ return { checked, review };
848
+ }
849
+ function numberBlocksFromIR(blocks) {
850
+ return blocks.flatMap((b) => {
851
+ if (b.type === "table" && b.table) return [{ type: "table", rows: b.table.cells.map((row) => row.map((c) => c?.text ?? "")) }];
852
+ return b.text ? [{ type: "text", text: b.text }] : [];
853
+ });
854
+ }
855
+ function numberBlocksFromMarkdown(blocks) {
856
+ return blocks.flatMap((b) => {
857
+ if (b.type === "table" && b.rows) return [{ type: "table", rows: b.rows }];
858
+ return b.text ? [{ type: "text", text: b.text }] : [];
859
+ });
860
+ }
861
+
862
+ // src/hwpx/level-styles.ts
863
+ import JSZip from "jszip";
864
+ var MIN_SAMPLES = 3;
865
+ var MIN_SHARE = 0.6;
866
+ var local = (n) => n.nodeName.replace(/^.*:/, "");
867
+ function runText(t) {
868
+ let out = "";
869
+ for (let n = t.firstChild; n; n = n.nextSibling) {
870
+ if (n.nodeType === 3) out += n.nodeValue ?? "";
871
+ else if (n.nodeType === 1 && local(n) === "tab") out += " ";
872
+ }
873
+ return out;
874
+ }
875
+ function inDataTable(p) {
876
+ for (let n = p.parentNode; n; n = n.parentNode) {
877
+ if (n.nodeType === 1 && local(n) === "tbl") {
878
+ const el = n;
879
+ return Number(el.getAttribute("rowCnt") ?? 1) * Number(el.getAttribute("colCnt") ?? 1) > 1;
880
+ }
881
+ }
882
+ return false;
883
+ }
884
+ function hangulFaces(headerXml) {
885
+ const doc = createXmlParser().parseFromString(stripDtd(headerXml), "text/xml");
886
+ const faces = /* @__PURE__ */ new Map();
887
+ const fontfaces = doc.getElementsByTagNameNS("*", "fontface");
888
+ for (let i = 0; i < fontfaces.length; i++) {
889
+ if (fontfaces[i].getAttribute("lang") !== "HANGUL") continue;
890
+ const fonts = fontfaces[i].getElementsByTagNameNS("*", "font");
891
+ for (let k = 0; k < fonts.length; k++) faces.set(fonts[k].getAttribute("id") ?? "", fonts[k].getAttribute("face") ?? "");
892
+ }
893
+ const out = /* @__PURE__ */ new Map();
894
+ const charPrs = doc.getElementsByTagNameNS("*", "charPr");
895
+ for (let i = 0; i < charPrs.length; i++) {
896
+ const ref = charPrs[i].getElementsByTagNameNS("*", "fontRef")[0];
897
+ const face = ref ? faces.get(ref.getAttribute("hangul") ?? "") : void 0;
898
+ if (face) out.set(charPrs[i].getAttribute("id") ?? "", face);
899
+ }
900
+ return out;
901
+ }
902
+ async function extractLevelStyles(buffer) {
903
+ const format = detectFormat(buffer);
904
+ if (format !== "hwpx") throw new KordocError(`\uB2E8\uACC4\uBCC4 \uC11C\uC2DD\uC740 HWPX \uACAC\uBCF8\uC5D0\uC11C\uB9CC \uC7BD\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format}) \u2014 \uD55C\uAE00\uC5D0\uC11C HWPX \uB85C \uC800\uC7A5\uD574 \uB118\uAE30\uC138\uC694`);
905
+ precheckZipSize(buffer);
906
+ const zip = await JSZip.loadAsync(buffer);
907
+ const decompressed = { total: 0 };
908
+ const styles = await extractHwpxStyles(zip, decompressed);
909
+ const header = zip.file("Contents/header.xml") ?? zip.file("Contents/head.xml");
910
+ const faces = header ? hangulFaces(await readZipEntry(header, "text", decompressed.total)) : /* @__PURE__ */ new Map();
911
+ const samples = [];
912
+ for (const path of await resolveSectionPaths(zip)) {
913
+ const file = zip.file(path);
914
+ if (!file) continue;
915
+ const xml = await readZipEntry(file, "text", decompressed.total);
916
+ decompressed.total += xml.length * 2;
917
+ const doc = createXmlParser().parseFromString(stripDtd(xml), "text/xml");
918
+ const paras = doc.getElementsByTagNameNS("*", "p");
919
+ for (let i = 0; i < paras.length; i++) {
920
+ const p = paras[i];
921
+ if (inDataTable(p)) continue;
922
+ const runs = [];
923
+ for (let c = p.firstChild; c; c = c.nextSibling) {
924
+ if (c.nodeType !== 1 || local(c) !== "run") continue;
925
+ const el = c;
926
+ let text2 = "";
927
+ const ts = el.getElementsByTagNameNS("*", "t");
928
+ for (let k = 0; k < ts.length; k++) if (ts[k].parentNode === el) text2 += runText(ts[k]);
929
+ runs.push({ text: text2, charPr: el.getAttribute("charPrIDRef") });
930
+ }
931
+ const text = runs.map((r) => r.text).join("");
932
+ const lm = parseLeadingMarker(text);
933
+ if (lm.kind !== "box" && lm.kind !== "legal" || !lm.rest) continue;
934
+ const at = text.indexOf(lm.rest);
935
+ let pos = 0, charPr = null;
936
+ for (const r of runs) {
937
+ if (at < pos + r.text.length) {
938
+ charPr = r.charPr;
939
+ break;
940
+ }
941
+ pos += r.text.length;
942
+ }
943
+ const cp = charPr ? styles.charProperties.get(charPr) : void 0;
944
+ if (!cp) continue;
945
+ samples.push({ scheme: lm.kind, depth: lm.depth, marker: lm.marker, text: lm.rest, font: faces.get(charPr) ?? cp.fontName, pt: cp.fontSize, bold: !!cp.bold });
946
+ }
947
+ }
948
+ const report = summarize(samples);
949
+ return styles.charProperties.size === 0 ? { ...report, note: "\uAE00\uC790 \uBAA8\uC591 \uC815\uC758(header.xml charPr)\uAC00 \uC5C6\uC5B4 \uC11C\uC2DD\uC744 \uC7B4 \uC218 \uC5C6\uC74C" } : report;
950
+ }
951
+ var tally = (values) => {
952
+ const out = {};
953
+ for (const v of values) if (v !== void 0) out[v] = (out[v] ?? 0) + 1;
954
+ return out;
955
+ };
956
+ var dominant = (counts, total) => {
957
+ const [value, n] = Object.entries(counts).sort((a, b) => b[1] - a[1])[0] ?? [];
958
+ return value !== void 0 && total >= MIN_SAMPLES && n >= total * MIN_SHARE ? value : void 0;
959
+ };
960
+ function summarize(samples) {
961
+ const box = samples.filter((s) => s.scheme === "box").length, legal = samples.length - box;
962
+ const scheme = samples.length === 0 ? null : box >= legal ? "box" : "legal";
963
+ const stats = [];
964
+ const levels = {};
965
+ for (const sch of ["box", "legal"]) {
966
+ for (const depth of [...new Set(samples.filter((s) => s.scheme === sch).map((s) => s.depth))].sort((a, b) => a - b)) {
967
+ const group = samples.filter((s) => s.scheme === sch && s.depth === depth);
968
+ const st = {
969
+ scheme: sch,
970
+ depth,
971
+ markers: [...new Set(group.map((s) => s.marker))],
972
+ samples: group.length,
973
+ font: tally(group.map((s) => s.font)),
974
+ pt: tally(group.map((s) => s.pt?.toString())),
975
+ bold: tally(group.map((s) => String(s.bold)))
976
+ };
977
+ stats.push(st);
978
+ if (sch !== scheme) continue;
979
+ const font = dominant(st.font, group.length), pt = dominant(st.pt, group.length), bold = dominant(st.bold, group.length);
980
+ const style = { ...font ? { font } : {}, ...pt ? { pt: Number(pt) } : {}, ...bold ? { bold: bold === "true" } : {} };
981
+ if (Object.keys(style).length) levels[depth] = style;
982
+ }
983
+ }
984
+ const deviations = [];
985
+ for (const s of samples) {
986
+ const want = s.scheme === scheme ? levels[s.depth] : void 0;
987
+ if (!want) continue;
988
+ const got = { font: s.font, pt: s.pt, bold: s.bold };
989
+ if (want.font !== void 0 && want.font !== s.font || want.pt !== void 0 && want.pt !== s.pt || want.bold !== void 0 && want.bold !== s.bold) {
990
+ deviations.push({ depth: s.depth, text: s.text.slice(0, 40), got, expected: want });
991
+ }
992
+ }
993
+ const spec = Object.entries(levels).map(([d, st]) => `${d}=${[st.font, st.pt, st.bold === void 0 ? void 0 : st.bold ? "bold" : "plain"].filter((v) => v !== void 0).join("/")}`).join(",");
994
+ return { scheme, levels, spec, stats, deviations };
995
+ }
996
+
997
+ // src/cli/commands-generate.ts
732
998
  function registerGenerateCommands(program2) {
733
- 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\uC11C\uC6B8\uBC29\uCE68(bangchim \u2014 \uC11C\uC6B8\uC2DC \uBC29\uCE68\uC11C: \uC81C\uBAA9\uD45C\xB7\uD30C\uB791 \uBD80\uC81C\xB7\uC694\uC57D\uBC15\uC2A4\xB7[\u2160] \uC7A5 \uC0C1\uC790\xB7\uC808 \uB760\xB7\u2776 \uACFC\uC81C)\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("--chapter-fit", "\uAC1C\uC870\uC2DD \uC7A5 \uD5E4\uB354 \uC81C\uBAA9 \uCE78\uC744 \uAE00\uC790 \uD3ED\uC5D0 \uB9DE\uCDA4 (\uAE30\uBCF8: \uBCF8\uBB38 \uD3ED\uAE4C\uC9C0)").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("--checklist [na]", "\uC11C\uC6B8 \uC0AC\uC804 \uAC80\uD1A0\uD56D\uBAA9 \uC810\uAC80\uD45C(\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uC11C\uC6B8\uBC29\uCE68) \u2014 \uAC12 \uC5C6\uC73C\uBA74 \uBE48 \uC11C\uC2DD, \uD574\uB2F9\uC5C6\uC74C \uBB38\uD56D \uBC88\uD638\uB97C \uC8FC\uBA74(6,7,8) \uB098\uBA38\uC9C0\uB294 \uAC80\uD1A0\uC644\uB8CC").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) => {
999
+ 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\uC11C\uC6B8\uBC29\uCE68(bangchim \u2014 \uC11C\uC6B8\uC2DC \uBC29\uCE68\uC11C: \uC81C\uBAA9\uD45C\xB7\uD30C\uB791 \uBD80\uC81C\xB7\uC694\uC57D\uBC15\uC2A4\xB7[\u2160] \uC7A5 \uC0C1\uC790\xB7\uC808 \uB760\xB7\u2776 \uACFC\uC81C)\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("--chapter-fit", "\uAC1C\uC870\uC2DD \uC7A5 \uD5E4\uB354 \uC81C\uBAA9 \uCE78\uC744 \uAE00\uC790 \uD3ED\uC5D0 \uB9DE\uCDA4 (\uAE30\uBCF8: \uBCF8\uBB38 \uD3ED\uAE4C\uC9C0)").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("--checklist [na]", "\uC11C\uC6B8 \uC0AC\uC804 \uAC80\uD1A0\uD56D\uBAA9 \uC810\uAC80\uD45C(\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uC11C\uC6B8\uBC29\uCE68) \u2014 \uAC12 \uC5C6\uC73C\uBA74 \uBE48 \uC11C\uC2DD, \uD574\uB2F9\uC5C6\uC74C \uBB38\uD56D \uBC88\uD638\uB97C \uC8FC\uBA74(6,7,8) \uB098\uBA38\uC9C0\uB294 \uAC80\uD1A0\uC644\uB8CC").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("--levels-from <hwpx>", "\uACAC\uBCF8 HWPX \uC5D0\uC11C \uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uBCC4 \uAE00\uAF34\xB7\uD06C\uAE30\xB7\uAD75\uAE30\uB97C \uBC30\uC6CC \uC801\uC6A9 (kordoc levels \uC640 \uAC19\uC740 \uCD94\uCD9C, --levels \uB85C \uC900 \uB2E8\uACC4\uAC00 \uC6B0\uC120)").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) => {
734
1000
  try {
735
1001
  const rootOpts = program2.opts();
736
1002
  const output = opts.output ?? rootOpts.output;
@@ -762,6 +1028,14 @@ function registerGenerateCommands(program2) {
762
1028
  }
763
1029
  return value;
764
1030
  };
1031
+ let learnedLevels;
1032
+ if (opts.levelsFrom) {
1033
+ const learned = await extractLevelStyles(toArrayBuffer(readFileSync3(resolve4(String(opts.levelsFrom)))));
1034
+ learnedLevels = learned.levels;
1035
+ if (!silent) process.stderr.write(learned.spec ? `[kordoc] \uACAC\uBCF8 \uB2E8\uACC4\uBCC4 \uC11C\uC2DD: ${learned.spec}
1036
+ ` : `[kordoc] \u26A0\uFE0F \uACAC\uBCF8\uC5D0\uC11C \uB2E8\uACC4\uBCC4 \uB300\uD45C \uC11C\uC2DD\uC744 \uC815\uD558\uC9C0 \uBABB\uD568 (\uB2E8\uACC4\uB9C8\uB2E4 \uD45C\uBCF8 3\uAC1C \uC774\uC0C1\xB7\uD55C \uAC12 60% \uC774\uC0C1 \uD544\uC694) \u2014 \uC5D4\uC9C4 \uAE30\uBCF8\uAC12 \uC0AC\uC6A9
1037
+ `);
1038
+ }
765
1039
  const parseKv = (spec, flag) => {
766
1040
  const out = {};
767
1041
  for (const piece of spec.split(",")) {
@@ -802,7 +1076,7 @@ function registerGenerateCommands(program2) {
802
1076
  sizes: opts.sizes ? Object.fromEntries(
803
1077
  Object.entries(parseKv(String(opts.sizes), "--sizes")).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v))
804
1078
  ) : void 0,
805
- levels: opts.levels ? parseLevelsSpec(String(opts.levels)) : void 0,
1079
+ levels: opts.levels || learnedLevels ? { ...learnedLevels, ...opts.levels ? parseLevelsSpec(String(opts.levels)) : {} } : void 0,
806
1080
  bullet2: enumCheck("--bullet2", opts.bullet2, BULLET2_CHARS),
807
1081
  suppressSingle: opts.suppressSingle ? true : void 0,
808
1082
  docHead: opts.docHead ? parseKv(String(opts.docHead), "--doc-head") : void 0,
@@ -895,6 +1169,33 @@ function registerGenerateCommands(program2) {
895
1169
  }
896
1170
  } catch (err) {
897
1171
  process.stderr.write(`[kordoc] \uC624\uB958: ${sanitizeError(err)}
1172
+ `);
1173
+ process.exit(1);
1174
+ }
1175
+ });
1176
+ program2.command("levels <file>").description("\uACAC\uBCF8 HWPX \uC758 \uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uBCC4 \uAE00\uAF34\xB7\uD06C\uAE30\xB7\uAD75\uAE30 \uCD94\uCD9C \u2014 generate --levels \uAC12\uACFC \uB2E8\uACC4\uBCC4 \uBD84\uD3EC\xB7\uC11C\uC2DD \uD3B8\uCC28 (kordoc levels \uACAC\uBCF8.hwpx, generate --levels-from \uC73C\uB85C \uBC14\uB85C \uC801\uC6A9)").option("--json", "\uCD94\uCD9C \uACB0\uACFC(levels\xB7spec\xB7stats\xB7deviations)\uB97C JSON \uC73C\uB85C stdout \uCD9C\uB825").action(async (file, opts) => {
1177
+ try {
1178
+ const r = await extractLevelStyles(toArrayBuffer(readFileSync3(resolve4(file))));
1179
+ if (opts.json) {
1180
+ process.stdout.write(JSON.stringify(r, null, 2) + "\n");
1181
+ return;
1182
+ }
1183
+ if (!r.scheme) {
1184
+ process.stderr.write(`[kordoc] ${r.note ?? "\uD56D\uBAA9\uBD80\uD638(\u25A1\xB7\u3147\xB7- \uB610\uB294 1.\xB7\uAC00.)\uB85C \uC2DC\uC791\uD558\uB294 \uBB38\uB2E8\uC774 \uC5C6\uC74C"}
1185
+ `);
1186
+ return;
1187
+ }
1188
+ process.stdout.write(`${r.spec || "(\uB300\uD45C\uAC12 \uC5C6\uC74C \u2014 \uB2E8\uACC4\uB9C8\uB2E4 \uD45C\uBCF8 3\uAC1C \uC774\uC0C1\xB7\uD55C \uAC12 60% \uC774\uC0C1 \uD544\uC694)"}
1189
+ `);
1190
+ for (const st of r.stats.filter((x) => x.scheme === r.scheme)) {
1191
+ const top = (m) => Object.entries(m).sort((a, b) => b[1] - a[1]).map(([k, n]) => `${k}\xD7${n}`).join(" ");
1192
+ process.stderr.write(` ${st.depth}\uB2E8\uACC4 ${st.markers.join("")} \uD45C\uBCF8 ${st.samples} \u2014 \uAE00\uAF34 ${top(st.font)} \xB7 \uD06C\uAE30 ${top(st.pt)} \xB7 \uAD75\uAC8C ${top(st.bold)}
1193
+ `);
1194
+ }
1195
+ if (r.deviations.length) process.stderr.write(`[kordoc] \uC11C\uC2DD \uD3B8\uCC28 ${r.deviations.length}\uAC74 \u2014 kordoc lint ${file} --styles \uB85C \uD655\uC778
1196
+ `);
1197
+ } catch (err) {
1198
+ process.stderr.write(`[kordoc] \uC624\uB958: ${sanitizeError(err)}
898
1199
  `);
899
1200
  process.exit(1);
900
1201
  }
@@ -917,28 +1218,36 @@ function registerGenerateCommands(program2) {
917
1218
  process.exit(1);
918
1219
  }
919
1220
  });
920
- program2.command("lint <file>").description("\uACF5\uBB38\uC11C \uD45C\uAE30\uBC95 \uAC80\uC218 \u2014 \uB0A0\uC9DC\xB7\uC2DC\uAC04\xB7\uAE08\uC561\xB7\uBD99\uC784 \uB4F1 \uD589\uC815\uC5C5\uBB34\uC6B4\uC601 \uD3B8\uB78C \uD45C\uAE30\uBC95 (md/txt, '-'=stdin). error \uC788\uC73C\uBA74 exit 1").option("--json", "JSON \uCD9C\uB825").option("--munche", "\uAC1C\uC870\uC2DD \uBB38\uCCB4 \uAC80\uC218 \uBCD1\uD589 \u2014 \uC11C\uC220\uD615 \uC885\uACB0\xB7\uB2F9\uC704\xB7\uC218\uC0AC\xB7\uD56D\uBAA9 \uAE38\uC774 (\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uC6D0\uACE0\uC6A9)").action((file, opts) => {
1221
+ program2.command("lint <file>").description("\uACF5\uBB38\uC11C \uD45C\uAE30\uBC95 \uAC80\uC218 \u2014 \uB0A0\uC9DC\xB7\uC2DC\uAC04\xB7\uAE08\uC561\xB7\uBD99\uC784 \uB4F1 \uD589\uC815\uC5C5\uBB34\uC6B4\uC601 \uD3B8\uB78C \uD45C\uAE30\uBC95 (md/txt \uB610\uB294 HWPX\xB7HWP\xB7PDF \uB4F1 \uBB38\uC11C, '-'=stdin). error \uC788\uC73C\uBA74 exit 1").option("--json", "JSON \uCD9C\uB825").option("--munche", "\uAC1C\uC870\uC2DD \uBB38\uCCB4 \uAC80\uC218 \uBCD1\uD589 \u2014 \uC11C\uC220\uD615 \uC885\uACB0\xB7\uB2F9\uC704\xB7\uC218\uC0AC\xB7\uD56D\uBAA9 \uAE38\uC774 (\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uC6D0\uACE0\uC6A9)").option("--numbers", "\uBCF8\uBB38 \uC218\uCE58 \u2194 \uD45C \uC218\uCE58 \uB300\uC870 \uBCD1\uD589 \u2014 \uD45C \uAC00\uAE4C\uC774 \uBCF8\uBB38\uC758 \uC218\uCE58\uAC00 \uADF8 \uD45C\uC5D0 \uC788\uB294\uC9C0 (\uD655\uC778 \uBAA9\uB85D, exit \uCF54\uB4DC\uC5D0\uB294 \uC601\uD5A5 \uC5C6\uC74C)").option("--styles", "\uB2E8\uACC4\uBCC4 \uC11C\uC2DD \uD3B8\uCC28 \uBCD1\uD589 (HWPX) \u2014 \uAC19\uC740 \uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uC778\uB370 \uAE00\uAF34\xB7\uD06C\uAE30\xB7\uAD75\uAE30\uAC00 \uB300\uD45C\uAC12\uACFC \uB2E4\uB978 \uBB38\uB2E8 (exit \uCF54\uB4DC\uC5D0\uB294 \uC601\uD5A5 \uC5C6\uC74C)").action(async (file, opts) => {
921
1222
  try {
922
1223
  const raw = file === "-" ? readFileSync3(0) : readFileSync3(resolve4(file));
923
- const kind = detectFormat(
924
- raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength)
925
- );
926
- if (kind !== "unknown") {
927
- process.stderr.write(
928
- `[kordoc] lint \uB294 \uD14D\uC2A4\uD2B8(\uB9C8\uD06C\uB2E4\uC6B4/txt)\uB97C \uAC80\uC0AC\uD569\uB2C8\uB2E4 \u2014 ${kind} \uBB38\uC11C\uB294 \uBC1B\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.
929
- \uC6D0\uACE0 \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uB118\uAE30\uAC70\uB098, \uBB38\uC11C \uBCF8\uBB38\uC744 \uD30C\uC774\uD504\uD558\uC138\uC694: kordoc ${file} | kordoc lint -
930
- `
931
- );
932
- process.exit(1);
1224
+ const ab = raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength);
1225
+ const kind = detectFormat(ab);
1226
+ let text;
1227
+ let irBlocks;
1228
+ if (kind === "unknown") text = raw.toString("utf-8");
1229
+ else {
1230
+ const { parse: parse2 } = await import("./-TTRGLREH.js");
1231
+ const parsed = await parse2(ab, file === "-" ? void 0 : { filePath: resolve4(file) });
1232
+ if (!parsed.success) {
1233
+ process.stderr.write(`[kordoc] \uC624\uB958: ${kind} \uBB38\uC11C\uB97C \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4 \u2014 ${parsed.error}
1234
+ `);
1235
+ process.exit(1);
1236
+ }
1237
+ text = parsed.markdown;
1238
+ irBlocks = parsed.blocks;
933
1239
  }
934
- const text = raw.toString("utf-8");
935
- const findings = lintGongmunText(text, { document: true });
1240
+ const findings = lintGongmunText(text, { document: true, parsed: kind !== "unknown" });
936
1241
  const munche = opts.munche ? lintMuncheText(text) : [];
1242
+ const styles = opts.styles && kind === "hwpx" ? (await extractLevelStyles(ab)).deviations : void 0;
1243
+ if (opts.styles && kind !== "hwpx") process.stderr.write(`[kordoc] --styles \uB294 HWPX \uBB38\uC11C\uB9CC \u2014 \uAC74\uB108\uB700
1244
+ `);
1245
+ const numbers = opts.numbers ? checkTableNumbers(irBlocks ? numberBlocksFromIR(irBlocks) : numberBlocksFromMarkdown(parseMarkdownToBlocks(text))) : void 0;
937
1246
  const errors = findings.filter((f) => f.severity === "error").length + munche.filter((f) => f.severity === "error").length;
938
1247
  if (opts.json) {
939
1248
  const total = findings.length + munche.length;
940
1249
  process.stdout.write(JSON.stringify(
941
- { findings, ...opts.munche ? { munche } : {}, summary: { total, errors, ok: errors === 0 } },
1250
+ { findings, ...opts.munche ? { munche } : {}, ...numbers ? { numbers } : {}, ...styles ? { styles } : {}, summary: { total, errors, ok: errors === 0 } },
942
1251
  null,
943
1252
  2
944
1253
  ) + "\n");
@@ -947,6 +1256,19 @@ function registerGenerateCommands(program2) {
947
1256
  `);
948
1257
  for (const f of findings) {
949
1258
  process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: "${f.match}" \u2014 ${f.message}${f.suggest ? ` \u2192 ${f.suggest}` : ""}
1259
+ `);
1260
+ }
1261
+ if (styles) {
1262
+ process.stderr.write(`[kordoc] \uB2E8\uACC4\uBCC4 \uC11C\uC2DD \uD3B8\uCC28: ${styles.length}\uAC74
1263
+ `);
1264
+ const show = (st) => [st.font, st.pt === void 0 ? void 0 : `${st.pt}pt`, st.bold === void 0 ? void 0 : st.bold ? "\uAD75\uAC8C" : "\uBCF4\uD1B5"].filter(Boolean).join("/");
1265
+ for (const d of styles) process.stderr.write(` ${d.depth}\uB2E8\uACC4 "${d.text}" \u2014 ${show(d.got)} (\uB300\uD45C ${show(d.expected)})
1266
+ `);
1267
+ }
1268
+ if (numbers) {
1269
+ process.stderr.write(`[kordoc] \uC218\uCE58 \uB300\uC870: \uD45C \uAC00\uAE4C\uC774 \uBCF8\uBB38 \uC218\uCE58 ${numbers.checked}\uAC1C \uC911 \uD45C\uC5D0\uC11C \uBABB \uCC3E\uC740 ${numbers.review.length}\uAC1C (\uD655\uC778 \uD544\uC694)
1270
+ `);
1271
+ for (const r of numbers.review) process.stderr.write(` "${r.match}" \u2014 ${r.context}
950
1272
  `);
951
1273
  }
952
1274
  if (opts.munche) {
@@ -968,7 +1290,7 @@ function registerGenerateCommands(program2) {
968
1290
  });
969
1291
  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(--rules \uB85C \uC778\uBA85\xB7\uC8FC\uC18C opt-in)\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,name(\uC778\uBA85),address(\uC8FC\uC18C)\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) => {
970
1292
  const { ALL_REDACT_RULES, DEFAULT_REDACT_RULES, redactText } = await import("./redact-NV2QCDGE.js");
971
- const { redactDocument } = await import("./redact-doc-PNRDDBI3.js");
1293
+ const { redactDocument } = await import("./redact-doc-NEUEBXFH.js");
972
1294
  const rootOpts = program2.opts();
973
1295
  const output = opts.output ?? rootOpts.output;
974
1296
  const outDir = opts.outDir ?? rootOpts.outDir;
@@ -1130,7 +1452,7 @@ function registerRenderCommands(program2) {
1130
1452
  const absPath = resolve5(file);
1131
1453
  const stem = file.replace(/\.hwpx?$/i, "");
1132
1454
  if (fmt === "svg" && !outDir && !pages && !/\.hwp$/i.test(absPath)) {
1133
- const { renderHwpxToSvg } = await import("./render-S3ALARVO.js");
1455
+ const { renderHwpxToSvg } = await import("./render-IL2DYXDP.js");
1134
1456
  const buffer = readFileSync4(absPath);
1135
1457
  const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode });
1136
1458
  const outPath = resolve5(output ?? stem + ".svg");
@@ -1144,7 +1466,7 @@ function registerRenderCommands(program2) {
1144
1466
  }
1145
1467
  return;
1146
1468
  }
1147
- const { renderDocument } = await import("./render-S3ALARVO.js");
1469
+ const { renderDocument } = await import("./render-IL2DYXDP.js");
1148
1470
  const { scene, assets } = await renderDocument(absPath, {
1149
1471
  format: fmt,
1150
1472
  pages,
@@ -1194,7 +1516,7 @@ function registerRenderCommands(program2) {
1194
1516
  if (!outDir) throw new KordocError("--out-dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4 (crop \uC740 \uD30C\uC77C \uC5EC\uB7EC \uAC1C\uB97C \uB0C5\uB2C8\uB2E4)");
1195
1517
  const types = String(opts.target).split(",").map((t) => t.trim()).filter(Boolean);
1196
1518
  for (const t of types) if (!["table", "image", "paragraph", "shape"].includes(t)) throw new KordocError(`--target \uC720\uD615 \uC624\uB958: ${t}`);
1197
- const { extractRenderedRegions } = await import("./render-S3ALARVO.js");
1519
+ const { extractRenderedRegions } = await import("./render-IL2DYXDP.js");
1198
1520
  const regions = await extractRenderedRegions(resolve5(file), {
1199
1521
  types,
1200
1522
  format: fmt,
@@ -1232,7 +1554,7 @@ function registerRenderCommands(program2) {
1232
1554
  if (policy !== "none" && !outDir) throw new KordocError("--visual \uC740 crop \uD30C\uC77C\uC744 \uB0B4\uBBC0\uB85C --out-dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4");
1233
1555
  const cropFmt = String(opts.cropFormat);
1234
1556
  if (!["png", "jpeg"].includes(cropFmt)) throw new KordocError(`--crop-format \uC740 png|jpeg: ${cropFmt}`);
1235
- const { extractTables } = await import("./visual-GDXMKDVY.js");
1557
+ const { extractTables } = await import("./visual-PYV4ZMLH.js");
1236
1558
  const tables = await extractTables(resolve5(file), { policy, format: cropFmt, paddingPt: Number(opts.padding) || 0 });
1237
1559
  const dir = outDir ? resolve5(outDir) : void 0;
1238
1560
  if (dir) mkdirSync4(dir, { recursive: true });
@@ -1276,7 +1598,7 @@ function registerRenderCommands(program2) {
1276
1598
  });
1277
1599
  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 () => {
1278
1600
  const { createInterface } = await import("readline");
1279
- const { renderHwpxToSvg } = await import("./render-S3ALARVO.js");
1601
+ const { renderHwpxToSvg } = await import("./render-IL2DYXDP.js");
1280
1602
  const rl = createInterface({ input: process.stdin });
1281
1603
  const write = (o) => void process.stdout.write(JSON.stringify(o) + "\n");
1282
1604
  write({ ready: true, version: VERSION });
@@ -1325,12 +1647,12 @@ function registerSystemCommands(program2) {
1325
1647
  await startMcpServer();
1326
1648
  });
1327
1649
  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 () => {
1328
- const { runSetup } = await import("./setup-JH66VSFZ.js");
1650
+ const { runSetup } = await import("./setup-PGOCB7YG.js");
1329
1651
  await runSetup();
1330
1652
  });
1331
1653
  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) => {
1332
1654
  try {
1333
- const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import("./formula-RSTTP626.js");
1655
+ const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import("./formula-KWOAYEOG.js");
1334
1656
  const dir = getFormulaModelsDir();
1335
1657
  if (opts.statusOnly) {
1336
1658
  const status = await getFormulaModelStatus();
@@ -1384,7 +1706,7 @@ function registerSystemCommands(program2) {
1384
1706
  });
1385
1707
  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) => {
1386
1708
  try {
1387
- const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import("./models-QOSU5SYL.js");
1709
+ const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import("./models-WJ5QYELV.js");
1388
1710
  const dir = getOcrModelsDir();
1389
1711
  if (opts.statusOnly) {
1390
1712
  const status = await getOcrModelStatus();
@@ -1438,7 +1760,7 @@ function registerSystemCommands(program2) {
1438
1760
  });
1439
1761
  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) => {
1440
1762
  try {
1441
- const { exportModels, importModels, modelCacheStatus } = await import("./model-bundle-NGTKULP7.js");
1763
+ const { exportModels, importModels, modelCacheStatus } = await import("./model-bundle-WPFLIKYM.js");
1442
1764
  if (opts.status) {
1443
1765
  process.stdout.write(JSON.stringify(await modelCacheStatus(), null, 2) + "\n");
1444
1766
  return;