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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/cli/convert.ts","../src/cli/output-path.ts","../src/cli/batch.ts","../src/cli/commands-docs.ts","../src/cli/commands-generate.ts","../src/cli/commands-render.ts","../src/cli/commands-system.ts","../src/cli/commands-worker.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 (하위 명령은 cli/ 아래 명령군 모듈) */\n\nimport { Command } from \"commander\"\nimport { VERSION, sanitizeError, routeConsoleToStderr } from \"./utils.js\"\nimport { convertFiles } from \"./cli/convert.js\"\nimport { assertDistinctStems, convertParallel, registerBatchWorker } from \"./cli/batch.js\"\nimport { registerDocCommands } from \"./cli/commands-docs.js\"\nimport { registerGenerateCommands } from \"./cli/commands-generate.js\"\nimport { registerRenderCommands } from \"./cli/commands-render.js\"\nimport { registerSystemCommands } from \"./cli/commands-system.js\"\nimport { registerWorkerCommands } from \"./cli/commands-worker.js\"\n\nconst program = new Command()\n\nprogram\n .name(\"kordoc\")\n .description(\"모두 파싱해버리겠다 — HWP, HWPX, PDF, XLSX, DOCX, 이미지(PNG/JPG/WebP) → Markdown\")\n .version(VERSION)\n .argument(\"<files...>\", \"변환할 파일 경로 (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP — 이미지는 OCR 자동 적용)\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (단일 파일 시)\")\n .option(\"--jobs <count>\", \"병렬 변환 프로세스 수 (기본 1, 다중 파일은 -d 필요)\", \"1\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\n .option(\"-p, --pages <range>\", \"페이지 범위 (예: 1-3, 1,3,5) — 한컴 저장본은 실제 페이지, 조판 캐시 없으면 섹션 근사\")\n .option(\"--format <type>\", \"출력 형식: markdown (기본), json, chunks (RAG용 구조 청크 JSON — 헤딩·개조식 위계 breadcrumb + 표 독립 청크)\", \"markdown\")\n .option(\"--no-header-footer\", \"PDF 머리글/바닥글 자동 제거 끄기 (기본: 제거함)\")\n .option(\"--no-tables\", \"PDF 표 감지 끄기 — 테두리 박스를 표로 오인해 읽기 순서가 뒤집히는 문서(2단 시험지 등)에서 자연 읽기순 텍스트만 뽑는다 (#64)\")\n .option(\"--formula-ocr\", \"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드)\")\n .option(\"--ocr\", \"스캔/이미지 PDF 텍스트 OCR (내장 PP-OCRv5 korean, 첫 사용 시 모델 ~18MB 자동 다운로드 — OCR 필요 페이지만 인식)\")\n .option(\"--ocr-force\", \"전 페이지 강제 OCR (텍스트층이 있어도 무시하고 재인식)\")\n .option(\"--dedupe-headers\", \"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의)\")\n .option(\"--keep-empty-cols\", \"표 오른쪽 끝 빈 열(서식 입력란) 보존 (#47, 기본 off: 후행 빈 열 트림)\")\n .option(\"--keep-empty-paragraphs\", \"빈 문단 보존 — 본문은 빈 paragraph 블록, 표 셀은 빈 줄로 (#57, 기본 off: 빈 문단 제거)\")\n .option(\"--include-field-placeholders\", \"미기입 누름틀 안내문도 출력 — 빈 서식의 칸 용도 보존 (#92, 기본 off: 인쇄되지 않는 안내문 제외)\")\n .option(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\n .option(\"--image-refs\", \"--format json 에서 이미지 바이트를 인라인하지 않고 파일 참조(images/<문서 이름>/<파일명>)만 남김 (#65 — 이미지가 수백 장인 문서의 직렬화 한계 회피, -o/-d 와 함께 사용)\")\n .option(\"--password <pw>\", \"암호로 보호된 문서의 열기 암호 (#59, HWPX·HWP3·HWP5. 한컴 DRM 문서는 해당 없음)\")\n .option(\"--html-tables\", \"모든 표를 HTML 로 — 파이프 표도 HTML 표로, 태그마다 한 줄씩 들여써 냄\")\n .option(\"--table-format <format>\", \"표 출력 형식: gfm — 모든 표를 HTML 없이 GFM 파이프 표로, 셀 안 표는 부모 뒤 독립 표 + 관계 표지(<!-- <table … /> -->) (RAG 색인용, --html-tables 와 함께 못 씀)\")\n .option(\"--keep-layout-tables\", \"테두리가 안 보이는 틀 표도 원본 표 구조 그대로 (기본: 보이는 대로 — 틀은 글, 칸으로 조립한 분수는 수식). patch 로 되돌릴 편집본은 이 옵션으로 뽑는다\")\n .option(\"--script-tags\", \"위·아래첨자를 <sup>·<sub> 로 표기 — PDF 는 기본 끔(논문·수식 PDF 에 권장), HWPX·HWP·DOCX 는 기본 켬\")\n .option(\"--no-script-tags\", \"첨자 표기 끄기 — 모든 형식에서 평문(\\\"104 m2\\\")\")\n .option(\"--plain\", \"평문 Markdown — 그림 자리 표시·링크 URL·밑줄/굵게 표기를 빼고 글만 (제목·목록·표 구조는 유지, 색인·RAG 용)\")\n .option(\"--no-images\", \"이미지 바이트를 추출·출력하지 않음: 글자만 필요할 때 (그림 자리 표시는 남김, PDF 는 PNG 인코딩을 건너뜀)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (files: string[], opts) => {\n const validFormats = [\"markdown\", \"json\", \"chunks\"]\n if (!validFormats.includes(opts.format)) {\n process.stderr.write(`[kordoc] 지원하지 않는 형식: ${opts.format} (markdown, json, chunks)\\n`)\n process.exit(1)\n }\n if (opts.tableFormat !== undefined && opts.tableFormat !== \"gfm\") {\n process.stderr.write(`[kordoc] 지원하지 않는 표 형식: ${opts.tableFormat} (gfm)\\n`)\n process.exit(1)\n }\n if (opts.tableFormat && opts.htmlTables) {\n process.stderr.write(`[kordoc] --table-format 과 --html-tables 는 함께 쓸 수 없습니다\\n`)\n process.exit(1)\n }\n // -o는 단일 파일 전용 — 다중 파일에서 무음 무시되지 않게 경고\n if (opts.output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\n const jobs = Number(opts.jobs)\n if (!/^\\d+$/.test(opts.jobs) || !Number.isSafeInteger(jobs) || jobs < 1) {\n program.error(\"--jobs must be a positive integer\")\n }\n if (jobs > 1 && files.length > 1) {\n if (!opts.outDir) program.error(\"--jobs > 1 requires --out-dir for multiple files\")\n try {\n if (!await convertParallel(files, opts, jobs)) process.exitCode = 1\n } catch (err) {\n program.error(sanitizeError(err))\n }\n } else {\n if (opts.outDir && files.length > 1) {\n try { assertDistinctStems(files) } catch (err) { program.error(sanitizeError(err)) }\n }\n if (!await convertFiles(files, opts)) process.exitCode = 1\n }\n })\n\nregisterDocCommands(program)\nregisterGenerateCommands(program)\nregisterRenderCommands(program)\nregisterSystemCommands(program)\nregisterWorkerCommands(program)\nregisterBatchWorker(program)\n\n// stdout 은 마크다운·JSON·생성 바이너리 채널 — pdfjs 등이 console 로 찍는 경고가 섞이지 않게 stderr 로\n// (parse-worker·MCP 와 같은 처리). setup 은 사람이 보는 설치 화면이라 그대로 둔다\nprogram.hook(\"preAction\", (_program, action) => {\n if (action.name() !== \"setup\") routeConsoleToStderr()\n})\n\n// 출처를 node 로 고정 — 정하지 않으면 commander 가 process.versions.electron 을 보고 Electron 앱 방식(argv[1]부터)으로\n// 읽어, Electron 을 node 로 띄운(ELECTRON_RUN_AS_NODE) 데스크톱 앱에서 cli.js 자신이 입력 파일로 잡힌다\nprogram.parse(process.argv, { from: \"node\" })\n","/** Shared sequential conversion path for the CLI and batch workers. */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, resolve } from \"path\"\nimport type { OptionValues } from \"commander\"\nimport { parse, detectFormat } from \"../index.js\"\nimport type { ParseOptions } from \"../types.js\"\nimport { toArrayBuffer, sanitizeError, classifyError } from \"../utils.js\"\nimport { detectImageMime } from \"../hwp5/images.js\"\nimport { toPlainMarkdown } from \"../plain-markdown.js\"\nimport { toHtmlTables } from \"../html-tables.js\"\nimport { createOutputGuard } from \"./output-path.js\"\n\nexport async function convertFiles(files: string[], opts: OptionValues, writeOutput: (text: string) => void = text => { process.stdout.write(text) }, assertSafeOutputs = createOutputGuard(files)): Promise<boolean> {\n let failed = false\n for (let fi = 0; fi < files.length; fi++) {\n const filePath = files[fi]\n const absPath = resolve(filePath)\n const fileName = basename(absPath)\n const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : \"\"\n let detectedFormat: ReturnType<typeof detectFormat> = \"unknown\"\n\n try {\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`\\n[kordoc] SKIP: ${fileName} — 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n failed = true\n continue\n }\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n const format = detectFormat(arrayBuffer)\n detectedFormat = format\n\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`)\n }\n\n const parseOptions: ParseOptions = { filePath: absPath }\n if (opts.pages) parseOptions.pages = opts.pages as string\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\n if (opts.tables === false) parseOptions.tables = false\n if (opts.formulaOcr) parseOptions.formulaOcr = true\n if (opts.ocrForce) parseOptions.ocr = \"force\"\n else if (opts.ocr) parseOptions.ocr = true\n if (opts.dedupeHeaders) parseOptions.dedupeRunningHeaders = true\n if (opts.keepEmptyCols) parseOptions.keepTrailingEmptyCols = true\n if (opts.keepEmptyParagraphs) parseOptions.keepEmptyParagraphs = true\n if (opts.includeFieldPlaceholders) parseOptions.includeFieldPlaceholders = true\n if (opts.inlineImages) parseOptions.inlineImages = true\n if (opts.password) parseOptions.password = opts.password as string\n if (opts.images === false) parseOptions.images = false\n if (opts.plain) parseOptions.plain = true\n if (opts.scriptTags !== undefined) parseOptions.scriptTags = opts.scriptTags as boolean\n if (opts.htmlTables) parseOptions.htmlTables = true\n if (opts.tableFormat === \"gfm\") parseOptions.tableFormat = \"gfm\"\n if (opts.keepLayoutTables) parseOptions.layoutTables = \"keep\"\n if (!opts.silent) {\n parseOptions.onProgress = (current: number, total: number) => {\n process.stderr.write(`\\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`)\n }\n }\n const result = await parse(arrayBuffer, parseOptions)\n detectedFormat = result.fileType // ZIP 세분화(xlsx·docx) 반영 — 실패 JSON 의 fileType\n\n if (!result.success) {\n process.stderr.write(` FAIL\\n`)\n process.stderr.write(` → ${result.error}\\n`)\n // 실패는 모든 --format 에서 stdout 에 동일한 실패 JSON(success:false + code)을 낸다(#69)\n // — 호출자가 원인 코드(ENCRYPTED 등)로 분기할 수 있는 기계 계약. 성공 출력과 충돌하지\n // 않는다: markdown 성공은 마크다운, chunks 성공은 JSON 배열이고 실패는 객체 + exit 1.\n // stderr 의 FAIL 문구는 사람용으로 그대로 둔다.\n writeOutput(JSON.stringify({ ...result, file: fileName }, null, 2) + \"\\n\")\n failed = true\n continue\n }\n\n if (!opts.silent) process.stderr.write(` OK\\n`)\n\n let markdown = result.markdown\n // 이미지 인라인은 HWP5 경로에서만 실제로 일어난다(parser.ts). 그 외 포맷(HWPX/DOCX 등)은\n // --inline-images 를 줘도 인라인되지 않으므로, 이미지 저장/경로접두사를 생략하면 참조가\n // 깨지고(dangling) 바이트가 유실된다 → 실제 인라인된 경우에만 생략한다.\n const imagesInlined = opts.inlineImages && result.fileType === \"hwp\"\n // 그림을 파일로 저장하는 실행(--out-dir 또는 단일 파일 --output, 아래 saveImages)이면 이미지 참조 경로에 images/ 접두사 추가\n // (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀). 종전엔 --out-dir 만 봐서 -o 결과의 그림 링크가 전부 깨졌다(#94).\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\n const savesImageFiles = Boolean(opts.outDir || (opts.output && files.length === 1))\n // 그림은 문서마다 images/<문서 이름>/ 에 — 같은 폴더로 여러 문서를 변환하면 image_001.png 가 서로 덮어써졌다(#98).\n // 문서 이름은 출력 파일 이름(-o) 또는 입력 파일 이름(-d)에서 확장자를 뺀 것. 링크에서는 공백·괄호만 퍼센트 인코딩한다\n const docStem = (opts.output && files.length === 1 ? basename(opts.output) : fileName).replace(/\\.[^.]+$/, \"\")\n const imgLink = `images/${docStem.replace(/[ ()]/g, ch => encodeURIComponent(ch))}/`\n const linkImages = (text: string): string => savesImageFiles && result.images?.length && !imagesInlined\n ? text.replace(/!\\[image\\]\\(image_/g, `![image](${imgLink}image_`).replace(/(<img\\b[^>]*\\bsrc=\")image_/g, `$1${imgLink}image_`)\n : text\n markdown = linkImages(markdown)\n // json 직렬화 — refsOnly면 이미지 바이트를 빼고 저장 경로만 남긴다.\n // 이미지가 수백 장인 문서는 base64 총량이 V8 문자열 한계를 넘어 RangeError 로\n // 터졌고, 그 예외가 성공 로그 뒤 비-JSON 출력이 되어 파이프라인이 깨졌다 (#65).\n const serializeJson = (refsOnly: boolean): string => {\n const payload = refsOnly && result.images?.length\n ? { ...result, images: result.images.map(img => ({ filename: img.filename, mimeType: img.mimeType, path: `images/${docStem}/${img.filename}` })) }\n : result\n return JSON.stringify(payload, (_key, value) =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n , 2)\n }\n let output: string\n if (opts.format === \"json\") {\n const savesImages = Boolean((opts.output && files.length === 1) || opts.outDir) && !imagesInlined\n try {\n output = serializeJson(Boolean(opts.imageRefs) && savesImages)\n } catch (err) {\n // 한계 초과 — 이미지를 어차피 파일로 저장하는 실행이면 참조 모드로 자동 강등한다.\n // 저장 위치가 없으면(stdout) 구제할 방법이 없으므로 실패 JSON 계약으로 넘긴다.\n if (!savesImages || !result.images?.length) throw err\n output = serializeJson(true)\n process.stderr.write(` ⚠️ 이미지 base64 인라인이 직렬화 한계를 넘어 파일 참조로 대체했습니다 (${result.images.length}개 → images/${docStem}/)\\n`)\n }\n } else if (opts.format === \"chunks\") {\n // 청크 글에도 본문 마크다운과 같은 후처리(평문·HTML 표·그림 경로) — 종전엔 IR 에서 바로 만들어 --plain·--html-tables 를 무시했다\n const { blocksToChunks } = await import(\"../chunks.js\")\n const chunks = blocksToChunks(result.blocks, { tableFormat: parseOptions.tableFormat }).map(c => {\n let text = c.text\n if (opts.plain) text = toPlainMarkdown(text)\n if (opts.htmlTables) text = toHtmlTables(text)\n return { ...c, text: linkImages(text) }\n })\n output = JSON.stringify(chunks, null, 2)\n } else {\n output = markdown\n }\n\n // 이미지 저장 (--out-dir 또는 --output 시) — 실제 인라인된 경우(HWP5)에만 미저장, 그 외엔 저장 유지\n const saveImages = (dir: string) => {\n if (!result.images?.length || imagesInlined) return\n const imgDir = resolve(dir, \"images\", docStem)\n mkdirSync(imgDir, { recursive: true })\n for (const img of result.images) {\n writeFileSync(resolve(imgDir, img.filename), img.data)\n }\n // images/<문서 이름>/manifest.json — 소비자가 확장자·매직바이트 추측 없이 형식 분기(#70).\n // mimeType 은 매직바이트 실측 우선 — 확장자 유래 선언값은 실데이터와 어긋날 수 있다.\n const manifest = result.images.map(img => ({\n name: img.filename,\n mimeType: detectImageMime(img.data) ?? img.mimeType,\n bytes: img.data.length,\n ...(img.source ? { source: img.source } : {}),\n }))\n writeFileSync(resolve(imgDir, \"manifest.json\"), JSON.stringify(manifest, null, 2), \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir} (manifest.json 포함)\\n`)\n }\n\n // Validate the document and all image destinations together, before any file is written.\n const assertSafeDestination = (output: string, dir: string) => {\n const imageOutputs = result.images?.length && !imagesInlined\n ? [...result.images.map(img => resolve(dir, \"images\", docStem, img.filename)), resolve(dir, \"images\", docStem, \"manifest.json\")]\n : []\n assertSafeOutputs([output, ...imageOutputs])\n }\n\n if (opts.output && files.length === 1) {\n assertSafeDestination(opts.output, resolve(opts.output, \"..\"))\n writeFileSync(opts.output, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${opts.output}\\n`)\n saveImages(resolve(opts.output, \"..\"))\n } else if (opts.outDir) {\n mkdirSync(opts.outDir, { recursive: true })\n const outExt = opts.format === \"json\" ? \".json\" : opts.format === \"chunks\" ? \".chunks.json\" : \".md\"\n // 확장자 없는 입력(\"slides\")도 이름 뒤에 붙인다 — 종전 replace 는 그대로 두어 -d 가 입력 폴더면 입력 파일을 덮어썼다\n const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, \"\") + outExt)\n assertSafeDestination(outPath, opts.outDir)\n writeFileSync(outPath, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\n saveImages(opts.outDir)\n } else {\n writeOutput(output + \"\\n\")\n }\n } catch (err) {\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n // 파싱 이후(출력·직렬화) 단계에서 터져도 실패 JSON 을 내야 호출자가 원인 코드로\n // 분기할 수 있다 — 종전엔 성공 로그 뒤 비-JSON 이었다 (#65). json 외 포맷에도\n // 동일 계약을 적용한다 (#69).\n writeOutput(JSON.stringify({\n success: false,\n fileType: detectedFormat,\n // 다중 입력에서 어느 파일이 실패했는지 호출자가 기계적으로 특정할 수 있게 한다 (#69).\n // basename 만 노출 — 전체 경로는 내부 정보로 보아 넣지 않는다.\n file: fileName,\n error: sanitizeError(err),\n code: classifyError(err),\n }, null, 2) + \"\\n\")\n failed = true\n }\n }\n return !failed\n}\n","/** Protect every batch input, including symlink and hardlink aliases, before writing output. */\nimport { statSync } from \"node:fs\"\nimport { basename, resolve } from \"node:path\"\n\nexport function createOutputGuard(inputs: string[]): (outputs: string[]) => void {\n const paths = new Map(inputs.map(input => [resolve(input), basename(input)]))\n const identities = new Map<string, string>()\n for (const [input, name] of paths) {\n try {\n const stat = statSync(input, { bigint: true })\n identities.set(`${stat.dev}:${stat.ino}`, name)\n } catch { /* Missing or unreadable inputs are reported by the normal conversion path. */ }\n }\n return outputs => {\n for (const output of outputs) {\n let input = paths.get(resolve(output))\n if (!input) {\n try {\n const stat = statSync(output, { bigint: true })\n input = identities.get(`${stat.dev}:${stat.ino}`)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\" && (err as NodeJS.ErrnoException).code !== \"ENOTDIR\") throw err\n }\n }\n if (input) throw new Error(`출력 경로가 입력 파일과 같습니다: ${input}`)\n }\n }\n}\n","/** Bounded, persistent process pool: CPU-heavy parsers get separate JS runtimes. */\nimport { fork, type ChildProcess } from \"node:child_process\"\nimport { basename } from \"node:path\"\nimport type { Command, OptionValues } from \"commander\"\nimport { KordocError } from \"../utils.js\"\nimport { convertFiles } from \"./convert.js\"\nimport { createOutputGuard } from \"./output-path.js\"\n\ninterface Job { file: string; opts: OptionValues; inputs?: string[] }\ninterface Done { ok: boolean; output: string[] }\n\nexport function registerBatchWorker(program: Command): void {\n program.command(\"__convert-worker\", { hidden: true }).action(() => {\n if (!process.send) program.error(\"Internal command requires an IPC channel\")\n // Do not leave native parser handles alive if the parent disappears.\n process.on(\"disconnect\", () => process.exit(0))\n let assertSafeOutputs: ReturnType<typeof createOutputGuard> | undefined\n process.on(\"message\", async ({ file, opts, inputs }: Job) => {\n const output: string[] = []\n assertSafeOutputs ??= createOutputGuard(inputs ?? [file])\n const ok = await convertFiles([file], opts, text => { output.push(text) }, assertSafeOutputs)\n process.send!({ ok, output } satisfies Done)\n })\n })\n}\n\n/**\n * Both converted documents and image directories are named after the input stem. Reject ambiguous\n * destinations before anything is written, including case variants — sequential `-d` runs used to\n * overwrite `a.md` and mix `images/a/` silently when two inputs shared a stem.\n */\nexport function assertDistinctStems(files: string[]): void {\n const stems = new Set<string>()\n for (const file of files) {\n const stem = basename(file).replace(/\\.[^.]+$/, \"\").normalize(\"NFC\").toLowerCase()\n if (stems.has(stem)) throw new KordocError(`Output name collision: ${basename(file)}; use distinct file stems`)\n stems.add(stem)\n }\n}\n\nexport async function convertParallel(files: string[], opts: OptionValues, jobs: number): Promise<boolean> {\n assertDistinctStems(files)\n\n const workers: ChildProcess[] = []\n let next = 0\n let failed = false\n const stop = () => { for (const worker of workers) worker.kill() }\n const onSigint = () => { stop(); process.exit(130) }\n const onSigterm = () => { stop(); process.exit(143) }\n process.once(\"SIGINT\", onSigint)\n process.once(\"SIGTERM\", onSigterm)\n try {\n await Promise.all(Array.from({ length: Math.min(jobs, files.length) }, () => new Promise<void>((resolve, reject) => {\n // Fork the same entry point: works in the bundled CLI and under tsx in tests.\n // Options travel over IPC so passwords never appear in child command lines.\n const worker = fork(process.argv[1], [\"__convert-worker\"], { stdio: [\"ignore\", \"ignore\", \"inherit\", \"ipc\"] })\n workers.push(worker)\n let current: string | undefined\n let finished = false\n let firstJob = true\n worker.on(\"error\", reject)\n worker.on(\"exit\", (code, signal) => {\n if (!finished) reject(new KordocError(`Conversion worker exited (${signal ?? code}) while processing ${basename(current ?? \"unknown\")}`))\n })\n const dispatch = () => {\n if (next === files.length) {\n finished = true\n worker.disconnect()\n resolve()\n return\n }\n current = files[next++]\n if (!opts.silent) process.stderr.write(`[kordoc] [${next}/${files.length}] ${basename(current)} ...\\n`)\n // Each worker writes a separate output tree; successful document data stays\n // in the worker, avoiding large IPC copies and buffering the entire batch.\n worker.send({ file: current, opts: { ...opts, output: undefined, silent: true }, ...(firstJob ? { inputs: files } : {}) } satisfies Job, err => {\n if (err) reject(err)\n })\n firstJob = false\n }\n worker.on(\"message\", ({ ok, output }: Done) => {\n if (!ok) failed = true\n // Only the parent writes stdout, preserving each failure JSON as one unit.\n for (const text of output) process.stdout.write(text)\n if (!opts.silent) process.stderr.write(`[kordoc] ${basename(current!)} ${ok ? \"OK\" : \"FAIL\"}\\n`)\n dispatch()\n })\n dispatch()\n })))\n return !failed\n } finally {\n stop()\n process.removeListener(\"SIGINT\", onSigint)\n process.removeListener(\"SIGTERM\", onSigterm)\n }\n}\n","/** kordoc CLI 명령 — 문서 처리 — watch·fill·seal·patch·validate */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, dirname, resolve, extname } from \"path\"\nimport { Command } from \"commander\"\nimport { parse, detectFormat, detectZipFormat, fillFormFields, extractFormFields, blocksToMarkdown, markdownToHwpx, fillHwpx, fillWithUniqueGuard, PRESET_ALIAS, extractClickHereFields, BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate } from \"../index.js\"\nimport type { FillInput } from \"../index.js\"\nimport { toArrayBuffer, sanitizeError } from \"../utils.js\"\n\nexport function registerDocCommands(program: Command): void {\n program\n .command(\"watch <dir>\")\n .description(\"디렉토리 감시 — 새 문서 자동 변환\")\n .option(\"--webhook <url>\", \"결과 전송 웹훅 URL\")\n .option(\"-d, --out-dir <dir>\", \"변환 결과 출력 디렉토리\")\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위\")\n .option(\"--format <type>\", \"출력 형식: markdown 또는 json\", \"markdown\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (dir: string, opts, command: Command) => {\n // 루트 커맨드의 동명 옵션(-d/--out-dir·-p/--pages·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.outDir ??= rootOpts.outDir\n opts.pages ??= rootOpts.pages\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\n const { watchDirectory } = await import(\"../watch.js\")\n await watchDirectory({\n dir,\n outDir: opts.outDir,\n webhook: opts.webhook,\n format: opts.format,\n pages: opts.pages,\n silent: opts.silent,\n })\n })\n\n program\n .command(\"fill [file]\")\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx / 내장 기안문 서식은 kordoc fill --template gian\")\n .option(\"-f, --fields <pairs>\", \"채울 필드 (key=value 쉼표 구분 또는 JSON)\")\n .option(\"-j, --json <path>\", \"채울 필드 JSON 파일 경로\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (확장자로 포맷 결정: .md, .hwpx)\")\n .option(\"--format <type>\", \"출력 포맷: hwpx-preserve (기본, 원본 스타일 보존), hwpx, markdown\", \"hwpx-preserve\")\n .option(\"--formats <json>\", \"필드별 값 서식 JSON (라벨→포맷) — 예: '{\\\"날짜\\\":\\\"yy.mm.dd\\\",\\\"주민등록번호\\\":\\\"rrn:masked\\\"}'\")\n .option(\"--template <name>\", \"내장 표준 서식 사용 (파일 경로 불필요): gian(일반기안문) | gian-simple(간이기안문). 위치 인자 'templates:일반기안문' 표기도 동일\")\n .option(\"--list-templates\", \"내장 표준 서식 목록 + 누름틀 필드 나열\")\n .option(\"--require-unique\", \"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 (반복 라벨 양식 오염 방지)\")\n .option(\"--mask\", \"채운 값 미노출 — 출력 파일 없이 markdown을 stdout으로 낼 때 본문 대신 안내만 표시\")\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string | undefined, opts, command: Command) => {\n try {\n // 루트 커맨드의 동명 옵션(-o/--output·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.output ??= rootOpts.output\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\n\n if (![\"hwpx-preserve\", \"hwpx\", \"markdown\"].includes(opts.format)) {\n process.stderr.write(`[kordoc] --format 는 hwpx-preserve/hwpx/markdown 중 하나여야 합니다: ${opts.format}\\n`)\n process.exit(1)\n }\n\n // --list-templates: 내장 서식 목록 + 누름틀 필드\n if (opts.listTemplates) {\n const list = []\n for (const t of BUILTIN_TEMPLATES) {\n const fields = await extractClickHereFields(readBuiltinTemplate(t))\n list.push({ id: t.id, aliases: t.aliases, title: t.title, fields: fields.map(f => f.name) })\n }\n process.stdout.write(JSON.stringify(list, null, 2) + \"\\n\")\n return\n }\n\n // 입력 소스 결정 — 내장 템플릿(--template 또는 'templates:이름' 위치 인자) 우선\n const templateName = opts.template ?? (file && /^templates?:/i.test(file) ? file : undefined)\n let arrayBuffer: ArrayBuffer\n let inputName: string\n if (templateName) {\n const t = resolveBuiltinTemplate(templateName)\n if (!t) {\n process.stderr.write(`[kordoc] 알 수 없는 내장 템플릿: ${templateName} (사용 가능: ${BUILTIN_TEMPLATES.map(x => `${x.id}(${x.aliases[0]})`).join(\", \")})\\n`)\n process.exit(1)\n }\n arrayBuffer = readBuiltinTemplate(t)\n inputName = t.file\n } else if (file) {\n const absPath = resolve(file)\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n process.exit(1)\n }\n arrayBuffer = toArrayBuffer(readFileSync(absPath))\n inputName = basename(absPath)\n } else {\n process.stderr.write(`[kordoc] 서식 파일 경로 또는 --template 을 지정해주세요 (목록: kordoc fill --list-templates)\\n`)\n process.exit(1)\n return\n }\n\n if (!opts.silent) process.stderr.write(`[kordoc] ${inputName} 파싱 중...\\n`)\n\n // --dry-run: 필드 목록만 출력 — 서식 입력란(빈 후행 열)이 목록에 나오도록 보존 (#47)\n if (opts.dryRun) {\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true, layoutTables: \"keep\" })\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n const formInfo = extractFormFields(result.blocks)\n // 누름틀(CLICK_HERE) 필드도 함께 나열 — 표준 서식은 라벨 표 없이 누름틀만 있을 수 있다\n const clickHereFields = detectFormat(arrayBuffer) === \"hwpx\"\n ? await extractClickHereFields(arrayBuffer)\n : []\n if (formInfo.fields.length === 0 && clickHereFields.length === 0) {\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\n process.exit(1)\n }\n process.stdout.write(JSON.stringify(\n clickHereFields.length > 0 ? { ...formInfo, clickHereFields } : formInfo,\n null, 2,\n ) + \"\\n\")\n return\n }\n\n // 필드 값 파싱\n let values: Record<string, string> = {}\n if (opts.json) {\n const jsonPath = resolve(opts.json)\n // Windows 메모장·PowerShell 이 붙이는 UTF-8 BOM 은 JSON.parse 가 거부한다\n const jsonContent = readFileSync(jsonPath, \"utf-8\").replace(/^/, \"\")\n values = JSON.parse(jsonContent)\n } else if (opts.fields) {\n const fieldsStr: string = opts.fields\n if (fieldsStr.startsWith(\"{\")) {\n values = JSON.parse(fieldsStr)\n } else {\n // \"key1=value1,key2=value2\" 파싱 — 값에 쉼표가 있을 수 있으므로\n // '=' 앞의 키를 기준으로 분리 (쉼표+한글/영문+= 패턴)\n const pairs = fieldsStr.split(/,(?=[가-힣A-Za-z][가-힣A-Za-z\\s]*=)/)\n for (const pair of pairs) {\n const eqIdx = pair.indexOf(\"=\")\n if (eqIdx > 0) {\n const key = pair.slice(0, eqIdx).trim()\n const val = pair.slice(eqIdx + 1).trim()\n values[key] = val\n }\n }\n }\n } else {\n process.stderr.write(`[kordoc] 채울 필드를 지정해주세요 (-f 또는 -j 옵션)\\n`)\n process.exit(1)\n }\n\n // 필드별 값 서식 결합 — MCP fill_form(formats)과 동일 의미론 (form/match.js FillInput)\n let inputs: Record<string, FillInput> = values\n if (opts.formats) {\n let formatMap: Record<string, string>\n try {\n formatMap = JSON.parse(String(opts.formats))\n } catch {\n process.stderr.write(`[kordoc] --formats 는 JSON 객체여야 합니다 (라벨→포맷)\\n`)\n process.exit(1)\n }\n inputs = Object.fromEntries(Object.entries(values).map(([k, v]) => {\n const format = formatMap[k]\n return [k, format ? { value: v, format } : v]\n }))\n }\n\n // 출력 포맷 결정 — 확장자 오버라이드가 명시 --format 과 충돌하면 경고 후 확장자 우선\n let outputFormat = opts.format as string\n if (opts.output) {\n const ext = extname(opts.output).toLowerCase()\n const explicitFormat = command.getOptionValueSource(\"format\") === \"cli\" || program.getOptionValueSource(\"format\") === \"cli\"\n const before = outputFormat\n if (ext === \".hwpx\") outputFormat = outputFormat === \"markdown\" ? \"hwpx-preserve\" : outputFormat\n else if (ext === \".md\") outputFormat = \"markdown\"\n if (explicitFormat && before !== outputFormat) {\n process.stderr.write(`[kordoc] ⚠️ --format ${before} 가 출력 확장자(${ext})와 충돌합니다 — 확장자 기준 ${outputFormat} 로 진행\\n`)\n }\n }\n\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 ───\n if (outputFormat === \"hwpx-preserve\") {\n const format = detectFormat(arrayBuffer)\n let isHwpx = format === \"hwpx\"\n if (isHwpx) {\n const zipFormat = await detectZipFormat(arrayBuffer)\n isHwpx = zipFormat === \"hwpx\"\n }\n if (!isHwpx) {\n if (!opts.silent) process.stderr.write(`[kordoc] HWPX가 아니므로 hwpx 모드로 전환합니다\\n`)\n outputFormat = \"hwpx\"\n } else {\n const hwpxResult = opts.requireUnique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(arrayBuffer, vals, blocked))\n : { ...(await fillHwpx(arrayBuffer, inputs)), rejected: [] as string[] }\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${hwpxResult.filled.length}개 필드 채움 (원본 스타일 보존)\\n`)\n if (hwpxResult.rejected.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${hwpxResult.rejected.join(\", \")}\\n`)\n }\n if (hwpxResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${hwpxResult.unmatched.join(\", \")}\\n`)\n }\n }\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxResult.buffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxResult.buffer))\n }\n return\n }\n }\n\n // ─── 일반 경로: parse → fill → output ─── (양식 입력란 보존, #47)\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true, layoutTables: \"keep\" })\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n\n const formInfo = extractFormFields(result.blocks)\n if (!opts.silent) {\n process.stderr.write(`[kordoc] 서식 필드 ${formInfo.fields.length}개 감지 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)\\n`)\n }\n\n const fillResult = opts.requireUnique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked))\n : { ...fillFormFields(result.blocks, inputs), rejected: [] as string[] }\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${fillResult.filled.length}개 필드 채움\\n`)\n if (fillResult.rejected.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${fillResult.rejected.join(\", \")}\\n`)\n }\n if (fillResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${fillResult.unmatched.join(\", \")}\\n`)\n }\n }\n\n const markdown = blocksToMarkdown(fillResult.blocks)\n\n if (outputFormat === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxBuffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxBuffer))\n }\n } else {\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), markdown, \"utf-8\")\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else if (opts.mask) {\n // 채운 값(주민번호·연락처 등)이 터미널 로그에 남지 않게 본문 대신 안내 (MCP mask_values와 동일 취지)\n process.stdout.write(`⚠️ --mask 활성 — 개인정보 노출 방지를 위해 본문을 출력하지 않습니다. -o 로 파일 저장 후 확인하세요.\\n`)\n } else {\n process.stdout.write(markdown + \"\\n\")\n }\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"seal <file>\")\n .description('도장/서명 이미지를 앵커 문구 위에 부유 배치 (표/페이지 불확장) — kordoc seal 신청서.hwpx --image 도장.png --anchor \"(인)\" -o 결과.hwpx')\n .requiredOption(\"--image <path>\", \"도장/서명 이미지 (투명 배경 PNG 권장)\")\n .option(\"--anchor <text>\", \"앵커 문구\", \"(인)\")\n .option(\"-n, --occurrence <num>\", \"같은 앵커가 여럿일 때 0-based 선택\", \"0\")\n .option(\"--size-mm <num>\", \"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\")\n .option(\"--mode <mode>\", \"overlap(문구 위 겹침) | right(오른쪽 옆) | auto\", \"auto\")\n .option(\"--dx <mm>\", \"x 미세조정 mm\", \"0\")\n .option(\"--dy <mm>\", \"y 미세조정 mm\", \"0\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <입력>.sealed.hwpx)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const { placeSealHwpx, detectFormat } = await import(\"../index.js\")\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const mode = String(opts.mode).toLowerCase()\n if (![\"overlap\", \"right\", \"auto\"].includes(mode)) {\n process.stderr.write(`[kordoc] --mode 는 overlap/right/auto 중 하나여야 합니다\\n`)\n process.exit(1)\n }\n const buf = new Uint8Array(readFileSync(resolve(file)))\n if (detectFormat(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer) !== \"hwpx\") {\n process.stderr.write(`[kordoc] seal 은 HWPX 전용입니다 (HWP 5.x 바이너리는 미지원)\\n`)\n process.exit(1)\n }\n const imgPath = resolve(opts.image)\n const imgSize = statSync(imgPath).size\n if (imgSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB)\\n`)\n process.exit(1)\n }\n const image = new Uint8Array(readFileSync(imgPath))\n const ext = extname(opts.image).slice(1).toLowerCase() || \"png\"\n // 숫자 플래그 엄격 검증 — 비숫자가 NaN→0 무증상 강제, 음수 occurrence가 truthy로\n // 통과하던 것 차단 (MCP zod와 동등, v4.0.6: --size-mm만 검증하던 것을 전 숫자 플래그로)\n const parseNum = (flag: string, raw: unknown, { min, allowNeg = false }: { min?: number; allowNeg?: boolean } = {}): number => {\n const n = Number(raw)\n if (!Number.isFinite(n) || (!allowNeg && n < 0) || (min !== undefined && n < min)) {\n process.stderr.write(`[kordoc] ${flag} 값이 잘못됐습니다: ${raw}${allowNeg ? \"\" : \" (0 이상 숫자)\"}\\n`)\n process.exit(1)\n }\n return n\n }\n let sizeMm: number | undefined\n if (opts.sizeMm != null) {\n const n = Number(opts.sizeMm)\n if (!Number.isFinite(n) || n <= 0) {\n process.stderr.write(`[kordoc] --size-mm 은 양수여야 합니다: ${opts.sizeMm}\\n`)\n process.exit(1)\n }\n sizeMm = n\n }\n const result = await placeSealHwpx(\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer,\n [{\n anchor: opts.anchor,\n occurrence: parseNum(\"--occurrence\", opts.occurrence),\n image,\n ext: ext as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\",\n sizeMm,\n mode: mode as \"overlap\" | \"right\" | \"auto\",\n dxMm: parseNum(\"--dx\", opts.dx, { allowNeg: true }),\n dyMm: parseNum(\"--dy\", opts.dy, { allowNeg: true }),\n }],\n )\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".sealed.hwpx\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(result.buffer))\n if (!silent) {\n for (const p of result.placed) {\n process.stderr.write(`[kordoc] 도장 배치: \"${p.anchor}\" #${p.occurrence} → ${p.mode} (${p.posXMm}mm, ${p.posYMm}mm, ${p.sizeMm}mm) [${p.entry}]\\n`)\n for (const w of p.warnings ?? []) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n process.stderr.write(`[kordoc] → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"patch <original> <edited>\")\n .description(\"서식 보존 라운드트립 패치 — 편집된 마크다운을 원본 HWPX/HWP에 in-place 반영 (kordoc patch 원본.hwpx 편집.md -o 출력.hwpx). 미적용(skip) 편집이 있으면 exit 2\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <원본>.patched.hwpx|.hwp)\")\n .option(\"--no-verify\", \"패치 후 재파싱 자동 검증 생략\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (original: string, edited: string, opts) => {\n try {\n const { patchHwpx, patchHwp, detectFormat } = await import(\"../index.js\")\n // 루트 커맨드의 동명 옵션(-o/--silent)이 서브커맨드 옵션을 가로채는 commander 동작 보완\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const originalBuf = new Uint8Array(readFileSync(resolve(original)))\n const editedMarkdown = readFileSync(resolve(edited), \"utf-8\")\n\n const format = detectFormat(originalBuf.buffer as ArrayBuffer)\n const result = format === \"hwp\"\n ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n if (!result.success || !result.data) {\n process.stderr.write(`[kordoc] 패치 실패: ${result.error ?? \"알 수 없는 오류\"}\\n`)\n process.exit(1)\n }\n\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\n const outPath = resolve(output ?? original.replace(/\\.hwpx?$/i, \"\") + \".patched\" + ext)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.data)\n\n if (!silent) {\n process.stderr.write(`[kordoc] ${result.applied}개 변경 적용 (원본 서식 보존) → ${outPath}\\n`)\n for (const s of result.skipped) {\n process.stderr.write(`[kordoc] ⚠️ SKIP: ${s.reason}${s.before ? ` | ${s.before}` : \"\"}\\n`)\n }\n if (result.verification) {\n const v = result.verification.stats\n const residual = v.added + v.removed + v.modified\n process.stderr.write(residual === 0\n ? `[kordoc] ✓ 검증: 편집 마크다운과 재파싱 결과 완전 일치 (${v.unchanged}블록)\\n`\n : `[kordoc] ⚠️ 검증 잔차: 수정 ${v.modified}, 추가 ${v.added}, 삭제 ${v.removed} (미지원 변경은 skip 목록 참조)\\n`)\n }\n }\n if (result.skipped.length > 0) process.exitCode = 2\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"validate <file>\")\n .description(\"HWPX 구조 검증 — ZIP·mimetype·필수 파일·XML 웰폼드·secCnt·manifest 참조 (한컴독스 거부 요인 사전 차단)\")\n .option(\"--json\", \"결과를 JSON으로 stdout에 출력\")\n .action(async (file: string, opts) => {\n try {\n const { validateHwpx } = await import(\"../index.js\")\n const buf = new Uint8Array(readFileSync(resolve(file)))\n const result = await validateHwpx(buf)\n if (opts.json) {\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\n } else if (result.ok) {\n process.stderr.write(`[kordoc] ✓ 구조 검증 통과 (엔트리 ${result.entryCount}개): ${file}\\n`)\n } else {\n process.stderr.write(`[kordoc] ✗ 구조 문제 ${result.issues.length}건: ${file}\\n`)\n for (const i of result.issues) {\n process.stderr.write(`[kordoc] - ${i.path ? `${i.path}: ` : \"\"}${i.message}\\n`)\n }\n }\n if (!result.ok) process.exit(1)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n // 공문서 프리셋 별칭(한글/영문) → 내부 preset 키 — gongmun.ts와 공용(PRESET_ALIAS)\n}\n","/** kordoc CLI 명령 — 생성·검수 — generate·profile·lint·redact */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, dirname, resolve } from \"path\"\nimport { detectFormat, markdownToHwpx, hwpxToProfile, PRESET_ALIAS, unknownFontWarnings, incompatibleGongmunWarnings, lintGongmunText, gongmunLintWarnings, lintMuncheText, muncheLintWarnings, usesGaejosikMunche } from \"../index.js\"\nimport { parseFormatProfileJson } from \"../hwpx/profile-io.js\"\nimport { loadGenerationImages } from \"../shared/generate-images.js\"\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS, parseLevelsSpec, levelFontRecord } from \"../hwpx/gongmun-surface.js\"\nimport type { FormatProfile } from \"../hwpx/gen-profile.js\"\nimport { toArrayBuffer, sanitizeError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerGenerateCommands(program: Command): void {\n program\n .command(\"generate <markdown>\")\n .alias(\"gen\")\n .description(\"마크다운 → 공문서 HWPX 생성 — kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 (markdown에 '-' 지정 시 stdin)\")\n .option(\"-o, --output <path>\", \"출력 HWPX 경로 (기본: <입력>.hwpx)\")\n .option(\"--preset <name>\", \"공문서 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)·개조식(gaejosik — 표지·목차·장헤더 자동)·업무보고(ministry — 중앙부처 업무보고: 장 띠·절 숫자칸·소제목 박스·① 항목 띠·성과 요약박스·별첨 띠)·서울방침(bangchim — 서울시 방침서: 제목표·파랑 부제·요약박스·[Ⅰ] 장 상자·절 띠·❶ 과제)·보도자료(press)\", \"기안문\")\n .option(\"--font <type>\", \"본문 글꼴: myeongjo(함초롬바탕) 또는 gothic(맑은 고딕)\")\n .option(\"--pt <size>\", \"본문 글자 크기(pt)\")\n .option(\"--line-spacing <percent>\", \"본문 줄간격(%)\")\n .option(\"--profile <path>\", \"서식 프로필 JSON (kordoc profile로 추출) — 참조 문서의 표 테두리·음영·열폭·셀 글꼴 재현\")\n .option(\"--org <name>\", \"표지 기관명 (표지를 켜는 프리셋 공통)\")\n .option(\"--date <date>\", \"표지 날짜 (기본 오늘 — 'YYYY. M. D.')\")\n .option(\"--toc\", \"목차 페이지 강제 켜기 (개조식 외 프리셋에서도 h2 목록으로 생성)\")\n .option(\"--no-toc\", \"목차 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\n .option(\"--cover\", \"표지 페이지 강제 켜기 (개조식 외 프리셋에서도 첫 h1을 표지로)\")\n .option(\"--no-cover\", \"표지 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\n .option(\"--approval <labels>\", \"결재란 직위 라벨 (쉼표 구분, 예: 담당,팀장,과장) — 문서 최상단 우측\")\n .option(\"--page-numbers\", \"쪽번호 강제 켜기 (하단 중앙 '- 1 -')\")\n .option(\"--no-page-numbers\", \"쪽번호 끄기 (개조식·보고서·계획서 기본 켜짐)\")\n .option(\"--end-mark\", \"본문 끝 '끝.' 표시 강제 켜기\")\n .option(\"--no-end-mark\", \"'끝.' 표시 끄기 (기안문 기본 켜짐)\")\n .option(\"--no-body-title-box\", \"본문 첫 페이지 제목 반복 박스 끄기 (개조식+표지 기본 켜짐)\")\n .option(\"--chapter-fit\", \"개조식 장 헤더 제목 칸을 글자 폭에 맞춤 (기본: 본문 폭까지)\")\n .option(\"--h2-marker <type>\", \"h2 장 제목 표기: band(로마자 채움 칸 + 제목 띠 표 — 보고서·계획서 기본)·roman(Ⅰ. 텍스트)·number(1. — 통지 기본)·box(장 없이 □ 대항목)·none\")\n .option(\"--band-color <hex>\", \"띠 제목 번호칸 채움색 #RRGGBB (기본 #003366 — 실측 최다. 교육청형 밝은 띠: #DFE6F7)\")\n .option(\"--band-text-color <hex>\", \"띠 제목 번호 글자색 #RRGGBB (기본 #FFFFFF — 밝은 띠면 #000000)\")\n .option(\"--summary <text>\", \"보고서 요약 박스 (제목표 아래 음영 상자 — 마크다운 제목 직후 인용문(>)으로도 지정)\")\n .option(\"--doc-info <spec>\", \"보고서 표지 문서정보표: docNum=스마트도시과-123,date=2026. 9. 6.,disclosure=공개,policyNo= (--cover와 함께)\")\n .option(\"--dept <name>\", \"표지 부서명 (기관명 아래 괄호)\")\n .option(\"--checklist [na]\", \"서울 사전 검토항목 점검표(보고서·계획서·서울방침) — 값 없으면 빈 서식, 해당없음 문항 번호를 주면(6,7,8) 나머지는 검토완료\")\n .option(\"--cover-label <text>\", \"표지 우상단 취급 표시 — '대외주의'·'비공개' 빨간 테두리 박스 (업무보고 프리셋 실측)\")\n .option(\"--fonts <spec>\", \"요소별 글꼴 오버라이드: body=나눔명조,heading=나눔고딕,ref=한양중고딕,table=맑은 고딕\")\n .option(\"--sizes <spec>\", \"개조식 요소별 크기(pt): dae=16,cham=13,table=12,coverTitle=30 …\")\n .option(\"--levels <spec>\", \"항목부호 단계별 위계 타이포: 0=HY견고딕/17/bold,1=한컴돋움/15/bold,2=휴먼명조/14 (depth 0~7, 숫자=pt·bold·plain·글꼴명)\")\n .option(\"--bullet2 <char>\", \"2단계 항목부호: ㅇ(이응 — 기안문·공고문 실측 지배) 또는 ○(원 — 보고서 양식)\")\n .option(\"--suppress-single\", \"단일 형제 항목 부호 생략 (편람 규정 — 기본은 하나여도 부호 부여)\")\n .option(\"--doc-head <spec>\", \"기안문 두문표: org=기관명,slogan=원훈,to=수신처,title=제목 (별지 제1호서식·서울 실결재 6행 표)\")\n .option(\"--doc-foot <spec>\", \"기안문 결문표: sender=발신명의,drafter=주무관 홍길동,reviewer=과장 김철수,approver=국장 박영희,cooperator=협조자,docNum=시행(과-번호 (날짜)),receive=접수,zip=우편번호,address=주소,site=홈페이지,phone=전화,fax=전송,email=메일,disclosure=공개구분\")\n .option(\"--report-info <text>\", \"보고서 담당자 행(제목표 아래) / 기안문 우상단 보고정보 행 — 예: '(2026. 7. 11., 과장 홍길동, ☎02-120)'\")\n .option(\"--notice-head <spec>\", \"공고문 두문·결문: no=공고 제2026-1호,date=2026년 7월 11일,sender=행정안전부장관\")\n .option(\"--press-head <spec>\", \"보도자료 머리: release=보도시점,distribute=배포일,dept=담당부서,manager=담당자,phone=연락처\")\n .option(\"--press-sub <items>\", \"보도자료 부제 (세미콜론 구분, 제목 아래 '- … -')\")\n .option(\"--plain\", \"공문서 모드 끄기 (범용 마크다운 변환)\")\n .option(\"--paper <size>\", \"용지: A4·A3·B4·B5·Letter 또는 '210x297'(mm)\")\n .option(\"--landscape\", \"용지 가로 방향\")\n .option(\"--columns <n>\", \"다단 개수 (1~8)\")\n .option(\"--header <text>\", \"머리말 텍스트 (모든 쪽, 인라인 마크다운 허용)\")\n .option(\"--footer <text>\", \"꼬리말 텍스트\")\n .option(\"--image-dir <dir>\", \"마크다운 이미지 참조(![](x.png))를 이 디렉토리에서 읽어 실데이터 임베드\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (markdown: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const plain: boolean = opts.plain ?? rootOpts.plain\n\n // 입력: '-' 이면 stdin, 아니면 파일\n let md: string\n let baseName = \"document\"\n if (markdown === \"-\") {\n md = readFileSync(0, \"utf-8\")\n } else {\n const inPath = resolve(markdown)\n md = readFileSync(inPath, \"utf-8\")\n baseName = basename(inPath).replace(/\\.(md|markdown|txt)$/i, \"\")\n }\n\n // 공문서 옵션 구성 — 값 검증(열거)과 조립은 gongmun-surface SSOT, 여기는\n // commander 표면 사정(kv 파싱·--no-x 기본값)을 중립 입력으로 정돈하는 어댑터만\n let gongmun: import(\"../index.js\").GongmunOptions | undefined\n if (!plain) {\n const preset = PRESET_ALIAS[String(opts.preset).trim()]\n if (!preset) {\n process.stderr.write(`[kordoc] 알 수 없는 프리셋: ${opts.preset} (기안문/보고서/계획서/통지/회의록/개조식/업무보고/서울방침/보도자료)\\n`)\n process.exit(1)\n }\n const enumCheck = <T extends readonly string[]>(flag: string, value: unknown, allowed: T): (typeof allowed)[number] | undefined => {\n if (value === undefined) return undefined\n if (!allowed.includes(String(value))) {\n process.stderr.write(`[kordoc] ${flag} 는 ${allowed.join(\"/\")}\\n`)\n process.exit(1)\n }\n return value as (typeof allowed)[number]\n }\n // \"key=value,key=value\" 스펙 파싱 — 값의 '='는 보존(첫 '='만 분리). 쉼표는\n // 구분자라 값에 못 들어감 — '=' 없는 조각(잘린 값의 꼬리 등)은 무증상 드랍\n // 대신 경고로 노출 (v4.0.6: 두문 title 값 유실이 조용히 지나가던 것 봉합)\n const parseKv = (spec: string, flag: string): Record<string, string> => {\n const out: Record<string, string> = {}\n for (const piece of spec.split(\",\")) {\n const p = piece.trim()\n if (!p) continue\n const eq = p.indexOf(\"=\")\n const key = eq > 0 ? p.slice(0, eq).trim() : \"\"\n const value = eq > 0 ? p.slice(eq + 1).trim() : \"\"\n if (!key || !value) {\n process.stderr.write(`[kordoc] ${flag}: 'key=value' 형식이 아닌 조각 무시 — \"${p}\" (값에 쉼표는 쓸 수 없습니다)\\n`)\n continue\n }\n out[key] = value\n }\n return out\n }\n const pressKv = opts.pressHead ? parseKv(String(opts.pressHead), \"--press-head\") : {}\n gongmun = buildGongmunOptions({\n preset,\n font: enumCheck(\"--font\", opts.font, BODY_FONTS),\n bodyPt: opts.pt ? Number(opts.pt) : undefined,\n lineSpacing: opts.lineSpacing ? Number(opts.lineSpacing) : undefined,\n org: opts.org, date: opts.date,\n cover: opts.cover, toc: opts.toc,\n approval: opts.approval ? String(opts.approval).split(\",\").map((s: string) => s.trim()).filter(Boolean) : undefined,\n pageNumbers: opts.pageNumbers, endMark: opts.endMark,\n // --no-body-title-box 단독 플래그 — commander 기본 true는 \"미지정\"으로 정돈\n bodyTitleBox: opts.bodyTitleBox === false ? false : undefined,\n chapterFit: opts.chapterFit,\n h2Marker: enumCheck(\"--h2-marker\", opts.h2Marker, H2_MARKERS),\n bandColor: opts.bandColor, bandTextColor: opts.bandTextColor,\n fonts: opts.fonts ? parseKv(String(opts.fonts), \"--fonts\") : undefined,\n sizes: opts.sizes\n ? Object.fromEntries(\n Object.entries(parseKv(String(opts.sizes), \"--sizes\")).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v as number)),\n )\n : undefined,\n levels: opts.levels ? parseLevelsSpec(String(opts.levels)) : undefined,\n bullet2: enumCheck(\"--bullet2\", opts.bullet2, BULLET2_CHARS),\n suppressSingle: opts.suppressSingle ? true : undefined,\n docHead: opts.docHead ? parseKv(String(opts.docHead), \"--doc-head\") : undefined,\n docFoot: opts.docFoot ? parseKv(String(opts.docFoot), \"--doc-foot\") : undefined,\n reportInfo: opts.reportInfo ? String(opts.reportInfo) : undefined,\n summary: opts.summary ? String(opts.summary) : undefined,\n docInfo: opts.docInfo ? parseKv(String(opts.docInfo), \"--doc-info\") : undefined,\n checklist: opts.checklist === undefined ? undefined : opts.checklist === true ? true : { na: String(opts.checklist).split(\",\").map((x) => Number(x.trim())).filter((x) => x !== 0) },\n dept: opts.dept ? String(opts.dept) : undefined,\n coverLabel: opts.coverLabel ? String(opts.coverLabel) : undefined,\n noticeHead: opts.noticeHead ? parseKv(String(opts.noticeHead), \"--notice-head\") : undefined,\n press: opts.pressHead || opts.pressSub\n ? {\n release: pressKv.release, distribute: pressKv.distribute,\n sub: opts.pressSub ? String(opts.pressSub).split(\";\").map((s: string) => s.trim()).filter(Boolean) : undefined,\n contact: pressKv.dept || pressKv.manager || pressKv.phone ? { dept: pressKv.dept, manager: pressKv.manager, phone: pressKv.phone } : undefined,\n }\n : undefined,\n })\n }\n\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행\n if (gongmun?.fonts && !silent) {\n for (const w of unknownFontWarnings(gongmun.fonts)) process.stderr.write(`[kordoc] ${w}\\n`)\n }\n if (gongmun?.levels && !silent) {\n for (const w of unknownFontWarnings(levelFontRecord(gongmun.levels))) process.stderr.write(`[kordoc] ${w}\\n`)\n }\n // 프리셋 비호환 옵션 경고 (v4.0.6) — 조용한 폐기 대신 노출, 생성은 진행\n if (gongmun && !silent) {\n for (const w of incompatibleGongmunWarnings(gongmun)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n // 공문서 표기법 검수 (편람 기준, 조언용) — 생성은 진행, stderr 경고만\n if (gongmun && !silent) {\n for (const w of gongmunLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n // 개조식 문체 검수 — 보고서·계획서·개조식 프리셋만. 기안문(경어)·통지·보도자료는\n // 문체 관행이 달라 적용하지 않는다 (범위를 좁히는 것이 오탐을 막는다)\n if (gongmun && !silent && usesGaejosikMunche(gongmun.preset)) {\n for (const w of muncheLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n\n // 서식 프로필 (이슈 #41) — 경계 zod 검증 후 라이브러리에 전달 (MCP와 공유 스키마)\n let profile: FormatProfile | undefined\n if (opts.profile) {\n profile = parseFormatProfileJson(readFileSync(resolve(String(opts.profile)), \"utf-8\"))\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 적용: 표 ${profile.tables.length}개 (${opts.profile})\\n`)\n }\n\n // 페이지 옵션 (v4.5.0) — 용지·방향·다단·머리말/꼬리말\n let page: import(\"../index.js\").PageOptions | undefined\n if (opts.paper || opts.landscape || opts.columns || opts.header || opts.footer) {\n let size: import(\"../index.js\").PageOptions[\"size\"]\n if (opts.paper) {\n const wh = /^(\\d+(?:\\.\\d+)?)x(\\d+(?:\\.\\d+)?)$/i.exec(String(opts.paper).trim())\n size = wh ? { widthMm: Number(wh[1]), heightMm: Number(wh[2]) } : (String(opts.paper) as \"A4\")\n }\n page = {\n ...(size !== undefined ? { size } : {}),\n ...(opts.landscape ? { orientation: \"landscape\" as const } : {}),\n ...(opts.columns ? { columns: Number(opts.columns) } : {}),\n ...(opts.header ? { header: String(opts.header) } : {}),\n ...(opts.footer ? { footer: String(opts.footer) } : {}),\n }\n }\n // MCP와 같은 Unicode·실경로 검증을 적용한다.\n let imageBytes: Record<string, Uint8Array> | undefined\n if (opts.imageDir) {\n const dir = resolve(String(opts.imageDir))\n const loaded = await loadGenerationImages(md, dir)\n imageBytes = loaded.images\n if (!silent) {\n process.stderr.write(`[kordoc] 이미지 임베드: ${Object.keys(imageBytes ?? {}).length}개 (${dir})\\n`)\n for (const warning of loaded.warnings) process.stderr.write(`[kordoc] ⚠ ${warning}\\n`)\n }\n }\n\n const genWarnings: string[] = []\n const buf = await markdownToHwpx(md, gongmun || profile || page || imageBytes\n ? {\n ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}),\n ...(page ? { page } : {}), ...(imageBytes ? { images: imageBytes } : {}),\n warnings: genWarnings,\n }\n : undefined)\n if (!silent) for (const w of genWarnings) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n const outPath = resolve(output ?? (markdown === \"-\" ? `${baseName}.hwpx` : markdown.replace(/\\.(md|markdown|txt)$/i, \"\") + \".hwpx\"))\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(buf))\n\n if (!silent) {\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\n process.stderr.write(`[kordoc] HWPX 생성 (${mode}) → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"profile <file>\")\n .description(\"HWPX 표 서식 프로필 추출 — 참조 문서의 표 테두리·음영·열폭·셀 글꼴을 JSON으로 (generate --profile로 재현) — kordoc profile 참조.hwpx -o 서식.json\")\n .option(\"-o, --output <path>\", \"출력 JSON 경로 (기본: <입력>.profile.json)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const absPath = resolve(file)\n const profile = await hwpxToProfile(readFileSync(absPath))\n const outPath = resolve(output ?? absPath.replace(/\\.hwpx$/i, \"\") + \".profile.json\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, JSON.stringify(profile, null, 2))\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 추출: 표 ${profile.tables.length}개 → ${outPath}\\n`)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"lint <file>\")\n .description(\"공문서 표기법 검수 — 날짜·시간·금액·붙임 등 행정업무운영 편람 표기법 (md/txt, '-'=stdin). error 있으면 exit 1\")\n .option(\"--json\", \"JSON 출력\")\n .option(\"--munche\", \"개조식 문체 검수 병행 — 서술형 종결·당위·수사·항목 길이 (보고서·계획서 원고용)\")\n .action((file: string, opts) => {\n try {\n const raw = file === \"-\" ? readFileSync(0) : readFileSync(resolve(file))\n // 문서 파일을 UTF-8 텍스트로 읽으면 압축 바이트가 본문으로 둔갑해 위반 수백~수천 건이\n // 쏟아진다(\"보고서.hwpx\" 실측 1,193건) — 검수 결과처럼 보이는 쓰레기가 최악이라 먼저 막는다.\n const kind = detectFormat(\n raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength) as ArrayBuffer\n )\n if (kind !== \"unknown\") {\n process.stderr.write(\n `[kordoc] lint 는 텍스트(마크다운/txt)를 검사합니다 — ${kind} 문서는 받지 않습니다.\\n` +\n ` 원고 마크다운을 넘기거나, 문서 본문을 파이프하세요: kordoc ${file} | kordoc lint -\\n`\n )\n process.exit(1)\n }\n const text = raw.toString(\"utf-8\")\n const findings = lintGongmunText(text, { document: true })\n // 문체 검수는 옵트인 — 축이 다르고(표기법 vs 종결·수사), 개조식이 아닌 원고에는\n // 적용하면 안 되기 때문에 기본 동작은 종전 그대로 둔다\n const munche = opts.munche ? lintMuncheText(text) : []\n const errors = findings.filter((f) => f.severity === \"error\").length\n + munche.filter((f) => f.severity === \"error\").length\n if (opts.json) {\n const total = findings.length + munche.length\n process.stdout.write(JSON.stringify(\n { findings, ...(opts.munche ? { munche } : {}), summary: { total, errors, ok: errors === 0 } }, null, 2) + \"\\n\")\n } else {\n // 사람용 리포트는 stderr — 기계용(--json)만 stdout (validate와 채널 일관)\n process.stderr.write(`[kordoc] 표기법 검수: 위반 ${findings.length}건 (error ${findings.filter((f) => f.severity === \"error\").length}, warning ${findings.filter((f) => f.severity !== \"error\").length})\\n`)\n for (const f of findings) {\n process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\n }\n if (opts.munche) {\n const me = munche.filter((f) => f.severity === \"error\").length\n process.stderr.write(`[kordoc] 문체 검수: 위반 ${munche.length}건 (error ${me}, warning ${munche.length - me})\\n`)\n for (const f of munche) {\n process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\n }\n }\n }\n process.exit(errors > 0 ? 1 : 0)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"redact <files...>\")\n .description(\"개인정보 서식 보존 마스킹 — 주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허(--rules 로 인명·주소 opt-in)를 탐지해 HWPX/HWP는 원본 서식 그대로 같은 길이로 가린 파일(본문·표·머리말/꼬리말·각주·글상자·미리보기·메타데이터 포함), 그 외 포맷(PDF 등)은 원본을 건드리지 않고 마스킹된 마크다운만 출력. 자동 검출 보조 도구이므로 결과는 반드시 사람이 최종 확인하세요 (이미지 속 글자는 탐지 불가)\")\n .option(\"--rules <csv>\", \"적용 룰 (기본: rrn,phone,email,card,account,brn,passport,driver — crn(법인등록번호),ip,name(인명),address(주소)는 opt-in)\")\n .option(\"--mask-char <ch>\", \"마스크 문자 1글자 (기본: ●)\")\n .option(\"-o, --output <path>\", \"출력 경로 (단일 파일 시)\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\n .option(\"--dry-run\", \"탐지 리포트만 출력, 파일 미생성\")\n .option(\"--json\", \"리포트를 JSON으로 stdout 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (files: string[], opts) => {\n const { ALL_REDACT_RULES, DEFAULT_REDACT_RULES, redactText } = await import(\"../redact.js\")\n const { redactDocument } = await import(\"../redact-doc.js\")\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n // 루트 명령도 -d/--out-dir 를 정의해 먼저 삼킨다 — -o 와 같은 방식으로 양쪽을 본다\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const KNOWN_RULES = new Set<string>(ALL_REDACT_RULES)\n const rules = opts.rules\n ? String(opts.rules).split(\",\").map((r: string) => r.trim()).filter(Boolean)\n : [...DEFAULT_REDACT_RULES]\n const badRule = rules.find((r: string) => !KNOWN_RULES.has(r))\n if (badRule) {\n process.stderr.write(`[kordoc] 알 수 없는 룰: ${badRule} (허용: ${[...KNOWN_RULES].join(\", \")})\\n`)\n process.exit(1)\n }\n const maskChar: string = opts.maskChar ?? \"●\"\n try { redactText(\"\", { maskChar }) } catch (err) {\n process.stderr.write(`[kordoc] ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n if (output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\n // 파일 이름에도 PII 가 있을 수 있다 — 결과 파일 이름·메시지·JSON 에는 가린 이름을 쓴다\n // (디렉토리 이름은 그대로). 윈도가 파일 이름에 못 쓰는 마스크 문자(* ?)는 ●로\n const nameMask = /[*?]/.test(maskChar) ? \"●\" : maskChar\n const maskName = (name: string): string => {\n // 파일 이름은 _ 로 낱말을 잇는다(\"민원_010-2345-6789\") — 탐지만 공백으로 보고 같은 자리를 가린다\n const probe = name.replace(/_/g, \" \")\n const out = [...name]\n for (const h of redactText(probe, { rules: rules as never, maskChar: nameMask }).hits) {\n for (let k = 0; k < h.length; k++) if (h.masked[k] !== probe[h.index + k]) out[h.index + k] = nameMask\n }\n return out.join(\"\")\n }\n const shown = (p: string): string => resolve(dirname(p), maskName(basename(p)))\n const inputs = files.map((f) => resolve(f))\n const sameFile = (a: string, b: string): boolean => {\n if (a === b) return true\n try {\n const sa = statSync(a), sb = statSync(b)\n return sa.ino === sb.ino && sa.dev === sb.dev // 대소문자 무시 파일시스템·하드링크\n } catch { return false }\n }\n const written = new Set<string>()\n /** 기본 출력 경로 — 입력 파일·이번 실행의 다른 출력과 겹치면 -2, -3 … 을 붙인다 */\n const defaultOut = (absPath: string, ext: string): string => {\n const stem = maskName(basename(absPath)).replace(/\\.[^.]+$/, \"\")\n const dir = resolve(outDir ?? dirname(absPath))\n for (let n = 1; ; n++) {\n const p = resolve(dir, `${stem}${n > 1 ? `-${n}` : \"\"}.redacted${ext}`)\n if (!written.has(p) && !inputs.some((i) => sameFile(i, p))) return p\n }\n }\n const MAX_LINES = 200\n const jsonReports: unknown[] = []\n for (const absPath of inputs) {\n const fileName = maskName(basename(absPath))\n if (output && files.length === 1 && !opts.dryRun && sameFile(absPath, resolve(output))) {\n process.stderr.write(`[kordoc] ERROR: ${fileName} — 출력 경로가 입력 파일과 같습니다. 원본을 덮어쓰지 않습니다 — 다른 -o 경로를 지정하세요\\n`)\n process.exitCode = 1\n continue\n }\n try {\n const buffer = readFileSync(absPath)\n const r = await redactDocument(toArrayBuffer(buffer), {\n rules: rules as never, maskChar, filePath: absPath, dryRun: opts.dryRun,\n })\n // 리포트 기준: HWPX/HWP 는 파일 안 위치(본문·머리말·미리보기 …), 그 외 포맷은 본문 마크다운\n const listed = r.fileHits.length > 0\n ? r.fileHits.map((h) => ({ rule: h.rule, masked: h.masked, at: `${h.where} @ ${h.part}` }))\n : r.markdownHits.map((h) => ({ rule: h.rule, masked: h.masked, at: \"\" }))\n const byRule = new Map<string, number>()\n for (const h of listed) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\n const ruleSummary = [...byRule.entries()].map(([k, v]) => `${k} ${v}건`).join(\", \") || \"0건\"\n const failed = r.residual.length > 0 || r.unscanned.length > 0\n\n let outPath: string | null = null\n let note = \"\"\n // HWPX/HWP 는 결과 바이트가 원본과 다르면 저장 (탐지 0건이어도 미할당 영역을 비웠으면 저장),\n // 그 외 포맷은 본문에서 찾은 게 있을 때 마스킹된 마크다운을 저장\n const save = r.data ? r.changed : r.markdownHits.length > 0\n if (!opts.dryRun && save) {\n const ext = r.data ? (r.format === \"hwp\" ? \".hwp\" : \".hwpx\") : \".md\"\n outPath = output && files.length === 1 ? resolve(output) : defaultOut(absPath, ext)\n mkdirSync(dirname(outPath), { recursive: true })\n if (r.data) writeFileSync(outPath, r.data)\n else {\n writeFileSync(outPath, r.markdown, \"utf-8\")\n note = ` (${r.format} 원본은 수정하지 않음 — 마스킹된 마크다운만 출력)`\n }\n written.add(outPath)\n } else if (!opts.dryRun && r.data && listed.length > 0) {\n note = \" (❌ 파일에서 가린 곳이 없어 출력하지 않음)\"\n }\n if (failed && process.exitCode !== 1) process.exitCode = 2 // 실패(1)가 우선\n if (opts.json) {\n jsonReports.push({\n file: shown(absPath), format: r.format, rules, hits: r.markdownHits, fileHits: r.fileHits,\n residual: r.residual, unscanned: r.unscanned, warnings: r.warnings, output: outPath,\n })\n }\n if (!silent) {\n process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` → ${outPath}` : opts.dryRun ? \" (dry-run)\" : \"\"}${note}\\n`)\n // 같은 값·같은 위치는 한 줄로 (미리보기·메타데이터에 같은 번호가 반복되는 경우), 너무 길면 자른다\n const grouped = new Map<string, number>()\n for (const h of listed) {\n const key = ` - [${h.rule}] ${h.masked}${h.at ? ` (${h.at})` : \"\"}`\n grouped.set(key, (grouped.get(key) ?? 0) + 1)\n }\n const lines = [...grouped].map(([line, n]) => `${line}${n > 1 ? ` ×${n}` : \"\"}`)\n for (const line of lines.slice(0, MAX_LINES)) process.stderr.write(`${line}\\n`)\n if (lines.length > MAX_LINES) process.stderr.write(` … 외 ${lines.length - MAX_LINES}줄 (전체는 --json)\\n`)\n if (r.residual.length > 0) {\n process.stderr.write(`[kordoc] ❌ 마스킹 후 재검사에서 PII ${r.residual.length}건이 남아 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요:\\n`)\n for (const h of r.residual.slice(0, MAX_LINES)) process.stderr.write(` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})\\n`)\n if (r.residual.length > MAX_LINES) process.stderr.write(` … 외 ${r.residual.length - MAX_LINES}건 (전체는 --json)\\n`)\n }\n if (r.unscanned.length > 0) {\n process.stderr.write(`[kordoc] ❌ 글자를 검사하지 못한 곳이 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요: ${r.unscanned.join(\", \")}\\n`)\n }\n for (const w of r.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n }\n if (opts.json) process.stdout.write(JSON.stringify(files.length === 1 ? jsonReports[0] ?? null : jsonReports, null, 2) + \"\\n\")\n })\n}\n","/** kordoc CLI 명령 — 렌더 — render·crop·tables·render-worker */\n\nimport { readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport { parse } from \"../index.js\"\nimport { VERSION, toArrayBuffer, sanitizeError, KordocError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerRenderCommands(program: Command): void {\n program\n .command(\"render <file>\")\n .description(\"레이아웃 보존 렌더 — HWPX·HWP(5.x)를 SVG(기본, HWPX 는 전체 페이지 세로 스택)·HTML·PNG·JPEG·PDF로. 한컴 저장본은 조판 캐시 그대로, 캐시 없는 생성본·편집본은 순수 TS 조판(reflow, 기본 켬) — kordoc render 문서.hwpx -o 문서.svg / --format png --pages 2-4 -d ./pages / --format pdf -o 문서.pdf\")\n .option(\"-o, --output <path>\", \"출력 경로 (단일 산출: svg 스택·html·pdf·한 쪽 png/jpeg. 기본: <입력>.<확장자>)\")\n .option(\"-d, --out-dir <dir>\", \"페이지별 산출 디렉토리 (svg/png/jpeg 여러 쪽 → page_001.png …)\")\n .option(\"--format <fmt>\", \"svg(기본) | html | png | jpeg | pdf\")\n .option(\"--pages <range>\", \"렌더할 페이지 (1-based: 3 / 1-3 / 1,3,7-9)\")\n .option(\"--max-width <px>\", \"래스터 최대 폭 px (기본 1400)\")\n .option(\"--title <text>\", \"HTML/PDF 문서 제목\")\n .option(\"--browser <path>\", \"PDF 용 Chromium 실행 파일 (기본: PUPPETEER_EXECUTABLE_PATH 또는 자동 탐지)\")\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\n .option(\"--no-reflow\", \"순수 TS 조판 끄기 (조판 캐시 없는 문서가 빈 페이지로 나올 수 있음)\")\n .option(\"--reflow\", \"순수 TS 조판 켜기 — 기본값과 같다 (옛 안내 호환, #97)\")\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep(어절) | charAll(글자)\", \"keep\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n // 루트 --format(markdown 기본) 이 서브커맨드 뒤 --format 을 흡수한다(cli-options 회귀) — 기본값이 아니면 그 값을 쓴다\n const fmt: string = opts.format ?? (rootOpts.format && rootOpts.format !== \"markdown\" ? rootOpts.format : \"svg\")\n const pages: string | undefined = opts.pages ?? rootOpts.pages\n if (![\"svg\", \"html\", \"png\", \"jpeg\", \"pdf\"].includes(fmt)) throw new KordocError(`--format 은 svg|html|png|jpeg|pdf 중 하나: ${fmt}`)\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\n const absPath = resolve(file)\n const stem = file.replace(/\\.hwpx?$/i, \"\")\n if (fmt === \"svg\" && !outDir && !pages && !/\\.hwp$/i.test(absPath)) {\n // 종전 동작(HWPX) — 전체 페이지 세로 스택 SVG 한 파일. HWP5 는 통합 렌더러(페이지별)\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n const buffer = readFileSync(absPath)\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\n const outPath = resolve(output ?? stem + \".svg\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n if (!silent) {\n process.stderr.write(`[kordoc] 렌더 (${result.pageCount}페이지, ${result.width}x${result.height}pt, 텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables}) → ${outPath}\\n`)\n for (const w of result.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n return\n }\n const { renderDocument } = await import(\"../render/index.js\")\n const { scene, assets } = await renderDocument(absPath, {\n format: fmt as \"svg\" | \"html\" | \"png\" | \"jpeg\" | \"pdf\", pages, highlights, reflow: opts.reflow, reflowMode: opts.reflowMode,\n maxWidthPx: opts.maxWidth ? Number(opts.maxWidth) : undefined, title: opts.title, browserExecutablePath: opts.browser,\n })\n const ext = fmt === \"jpeg\" ? \"jpg\" : fmt\n const written: string[] = []\n if (fmt === \"html\" || fmt === \"pdf\" || (assets.length === 1 && !outDir)) {\n const outPath = resolve(output ?? stem + \".\" + ext)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, assets[0].data)\n written.push(outPath)\n } else {\n if (!outDir) throw new KordocError(`페이지 ${assets.length}장 산출은 --out-dir 이 필요합니다 (한 쪽만 내려면 --pages 로 선택)`)\n mkdirSync(resolve(outDir), { recursive: true })\n for (const a of assets) {\n const outPath = resolve(outDir, `page_${String(a.page).padStart(3, \"0\")}.${ext}`)\n writeFileSync(outPath, a.data)\n written.push(outPath)\n }\n }\n if (!silent) {\n process.stderr.write(`[kordoc] 렌더 ${fmt} (${scene.pages.length}페이지 중 ${assets.length}건, 텍스트 ${scene.stats.texts}·이미지 ${scene.stats.images}·표 ${scene.stats.tables}·도형 ${scene.stats.shapes}) → ${written.length === 1 ? written[0] : resolve(outDir!)}\\n`)\n for (const w of scene.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n } catch (err) {\n // exit(1) 을 바로 부르면 파이프 stderr 가 유실된다 — exitCode 로 정상 종료\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"crop <file>\")\n .description(\"렌더 영역 잘라내기 — 표·이미지·문단·도형을 페이지 이미지에서 crop (HWPX·HWP) — kordoc crop 문서.hwpx --target table -d ./regions\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (필수) — <유형>_<번호>_page_<쪽>.png + regions.json\")\n .option(\"--target <types>\", \"유형(쉼표): table | image | paragraph | shape\", \"table\")\n .option(\"--format <fmt>\", \"png(기본) | jpeg\")\n .option(\"--pages <range>\", \"대상 페이지 (1-based)\")\n .option(\"--padding <pt>\", \"bbox 둘레 여백 pt\", \"0\")\n .option(\"--max-width <px>\", \"페이지 래스터 최대 폭 px (crop 해상도, 기본 1400)\")\n .option(\"--no-reflow\", \"순수 TS 조판 끄기\")\n .option(\"--reflow\", \"순수 TS 조판 켜기 — 기본값과 같다 (옛 안내 호환)\")\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep | charAll\", \"keep\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const fmt: string = opts.format ?? (rootOpts.format && rootOpts.format !== \"markdown\" ? rootOpts.format : \"png\")\n const pages: string | undefined = opts.pages ?? rootOpts.pages\n if (![\"png\", \"jpeg\"].includes(fmt)) throw new KordocError(`--format 은 png|jpeg 중 하나: ${fmt}`)\n if (!outDir) throw new KordocError(\"--out-dir 이 필요합니다 (crop 은 파일 여러 개를 냅니다)\")\n const types = String(opts.target).split(\",\").map((t: string) => t.trim()).filter(Boolean)\n for (const t of types) if (![\"table\", \"image\", \"paragraph\", \"shape\"].includes(t)) throw new KordocError(`--target 유형 오류: ${t}`)\n const { extractRenderedRegions } = await import(\"../render/index.js\")\n const regions = await extractRenderedRegions(resolve(file), {\n types: types as Array<\"table\" | \"image\" | \"paragraph\" | \"shape\">, format: fmt as \"png\" | \"jpeg\", pages,\n paddingPt: Number(opts.padding) || 0, maxWidthPx: opts.maxWidth ? Number(opts.maxWidth) : undefined, reflow: opts.reflow, reflowMode: opts.reflowMode,\n })\n const dir = resolve(outDir)\n mkdirSync(dir, { recursive: true })\n const ext = fmt === \"jpeg\" ? \"jpg\" : \"png\"\n const manifest = regions.map(r => {\n const name = `${r.region.id.replace(\"-\", \"_\")}_page_${String(r.page).padStart(3, \"0\")}.${ext}`\n writeFileSync(resolve(dir, name), r.data)\n return { file: name, id: r.region.id, type: r.region.type, sourceId: r.region.sourceId, parentId: r.region.parentId, page: r.page, bbox: r.bbox, widthPx: r.widthPx, heightPx: r.heightPx }\n })\n writeFileSync(resolve(dir, \"regions.json\"), JSON.stringify(manifest, null, 2))\n if (!silent) process.stderr.write(`[kordoc] crop ${regions.length}건 (${types.join(\",\")}) → ${dir}\\n`)\n } catch (err) {\n // exit(1) 을 바로 부르면 파이프 stderr 가 유실된다 — exitCode 로 정상 종료\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"tables <file>\")\n .description(\"표 추출·분류 — 의미표/레이아웃(조직도 등)/불확실 분류 JSON + 선택적 시각 crop (HWPX·HWP) — kordoc tables 문서.hwpx --visual non-tabular-and-uncertain -d ./tables\")\n .option(\"-o, --output <path>\", \"JSON 출력 경로 (기본 stdout; -d 지정 시 <out-dir>/tables.json)\")\n .option(\"-d, --out-dir <dir>\", \"crop 저장 디렉토리 (--visual 지정 시 필수)\")\n .option(\"--visual <policy>\", \"crop 대상: none(기본) | non-tabular | non-tabular-and-uncertain | all\", \"none\")\n .option(\"--crop-format <fmt>\", \"png(기본) | jpeg\", \"png\")\n .option(\"--padding <pt>\", \"crop 여백 pt\", \"0\")\n .option(\"--cells\", \"JSON 에 셀 텍스트 격자 포함\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const policy = String(opts.visual)\n if (![\"none\", \"non-tabular\", \"non-tabular-and-uncertain\", \"all\"].includes(policy)) throw new KordocError(`--visual 은 none|non-tabular|non-tabular-and-uncertain|all: ${policy}`)\n if (policy !== \"none\" && !outDir) throw new KordocError(\"--visual 은 crop 파일을 내므로 --out-dir 이 필요합니다\")\n const cropFmt = String(opts.cropFormat)\n if (![\"png\", \"jpeg\"].includes(cropFmt)) throw new KordocError(`--crop-format 은 png|jpeg: ${cropFmt}`)\n const { extractTables } = await import(\"../table/visual.js\")\n const tables = await extractTables(resolve(file), { policy: policy as \"none\" | \"non-tabular\" | \"non-tabular-and-uncertain\" | \"all\", format: cropFmt as \"png\" | \"jpeg\", paddingPt: Number(opts.padding) || 0 })\n const dir = outDir ? resolve(outDir) : undefined\n if (dir) mkdirSync(dir, { recursive: true })\n const ext = cropFmt === \"jpeg\" ? \"jpg\" : \"png\"\n const report = tables.map(t => {\n const crops = t.crops.map(c => {\n const name = `${t.id.replace(/[^\\w.-]/g, \"_\")}_page_${String(c.page).padStart(3, \"0\")}.${ext}`\n if (dir) writeFileSync(resolve(dir, name), c.data)\n return { file: dir ? name : undefined, page: c.page, bbox: c.bbox }\n })\n return {\n id: t.id, sourceId: t.sourceId, page: t.page, classification: t.classification,\n table: { rows: t.table.rows, cols: t.table.cols, hasHeader: t.table.hasHeader, caption: t.table.caption, ...(opts.cells ? { cells: t.table.cells.map(r => r.map(c => c.text)) } : {}) },\n regions: t.regions, crops, warnings: t.warnings,\n }\n })\n const json = JSON.stringify(report, null, 2)\n const jsonPath = output ? resolve(output) : dir ? resolve(dir, \"tables.json\") : undefined\n if (jsonPath) { mkdirSync(dirname(jsonPath), { recursive: true }); writeFileSync(jsonPath, json + \"\\n\") }\n else process.stdout.write(json + \"\\n\")\n if (!silent) {\n const kinds = report.reduce<Record<string, number>>((m, r) => { m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1; return m }, {})\n process.stderr.write(`[kordoc] 표 ${report.length}개 (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(\", \")}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}건${jsonPath ? ` → ${jsonPath}` : \"\"}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"render-worker\")\n .description(\"persistent 렌더 워커 — stdin NDJSON 요청 → 조판 SVG 파일 출력 (프로세스 유지, 콜드스타트 제거)\")\n .action(async () => {\n // 프로토콜(NDJSON, 한 줄=한 요청/응답):\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"out\":\"a.svg\",\"reflow\":true,\"highlight\":[\"term\"]}\n // 응답 {\"id\":1,\"ok\":true,\"out\":\"a.svg\",\"width\":..,\"height\":..,\"pageCount\":..,\"stats\":{..},\"warnings\":[..]}\n // {\"cmd\":\"quit\"} 로 종료. 모듈은 최초 1회만 로드 → 이후 요청은 콜드스타트 없음.\n const { createInterface } = await import(\"node:readline\")\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n const rl = createInterface({ input: process.stdin })\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o) + \"\\n\")\n write({ ready: true, version: VERSION })\n for await (const line of rl) {\n const t = line.trim()\n if (!t) continue\n let req: { id?: number; cmd?: string; file?: string; out?: string; reflow?: boolean; reflowMode?: string; highlight?: string[] }\n // 비JSON 라인도 응답은 낸다 — 무음 삼킴이면 id 대기 클라이언트가 영구 행\n try { req = JSON.parse(t) } catch { write({ ok: false, error: \"잘못된 JSON 라인\" }); continue }\n if (req === null || typeof req !== \"object\") { write({ ok: false, error: \"JSON 객체가 아닙니다\" }); continue }\n if (req.cmd === \"quit\") { rl.close(); break }\n const id = req.id\n try {\n if (!req.file || !req.out) throw new Error(\"file·out 필수\")\n const buffer = readFileSync(resolve(req.file))\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), {\n highlights: req.highlight, reflow: req.reflow, reflowMode: req.reflowMode as \"keep\" | \"charAll\" | undefined,\n })\n const outPath = resolve(req.out)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n write({ id, ok: true, out: outPath, width: result.width, height: result.height, pageCount: result.pageCount, stats: result.stats, warnings: result.warnings })\n } catch (err) {\n write({ id, ok: false, error: sanitizeError(err) })\n }\n }\n })\n}\n","/** kordoc CLI 명령 — 서버·설정·모델 — mcp·setup·check-formula-models·check-ocr-models·models */\n\nimport { sanitizeError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerSystemCommands(program: Command): void {\n program\n .command(\"mcp\")\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\n .action(async () => {\n const { startMcpServer } = await import(\"../mcp.js\")\n await startMcpServer()\n })\n\n program\n .command(\"setup\")\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\n .action(async () => {\n const { runSetup } = await import(\"../setup.js\")\n await runSetup()\n })\n\n program\n .command(\"check-formula-models\")\n .description(\"PDF 수식 OCR 모델(MFD + MFR + tokenizer, ~155MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\n .action(async (opts) => {\n try {\n const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import(\n \"../pdf/formula/index.js\"\n )\n const dir = getFormulaModelsDir()\n if (opts.statusOnly) {\n const status = await getFormulaModelStatus()\n process.stdout.write(\n JSON.stringify(\n {\n modelsDir: dir,\n allReady: status.every((s) => s.verified),\n models: status.map((s) => ({\n name: s.spec.name,\n filename: s.spec.filename,\n sizeMb: s.spec.sizeMb,\n exists: s.exists,\n verified: s.verified,\n invalidReason: s.invalidReason,\n path: s.localPath,\n })),\n },\n null,\n 2,\n ) + \"\\n\",\n )\n return\n }\n process.stderr.write(`[kordoc-formula] 캐시 디렉토리: ${dir}\\n`)\n await ensureFormulaModels((p) => {\n if (p.phase === \"download\" && p.total) {\n const pct = Math.floor((p.downloaded / p.total) * 100)\n process.stderr.write(\n `\\r[kordoc-formula] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\n )\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\n } else if (p.phase === \"verify\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} SHA-256 검증 중...\\n`)\n } else if (p.phase === \"done\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 준비 완료\\n`)\n } else if (p.phase === \"skip\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 이미 존재 (skip)\\n`)\n }\n })\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] 수식 모델 준비 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"check-ocr-models\")\n .description(\"텍스트 OCR 모델(PP-OCRv5 korean det+rec, ~18MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\n .action(async (opts) => {\n try {\n const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import(\"../ocr/models.js\")\n const dir = getOcrModelsDir()\n if (opts.statusOnly) {\n const status = await getOcrModelStatus()\n process.stdout.write(\n JSON.stringify(\n {\n modelsDir: dir,\n allReady: status.every((s) => s.verified),\n models: status.map((s) => ({\n name: s.spec.name,\n filename: s.spec.filename,\n sizeMb: s.spec.sizeMb,\n exists: s.exists,\n verified: s.verified,\n invalidReason: s.invalidReason,\n path: s.localPath,\n })),\n },\n null,\n 2,\n ) + \"\\n\",\n )\n return\n }\n process.stderr.write(`[kordoc-ocr] 캐시 디렉토리: ${dir}\\n`)\n await ensureOcrModels((p) => {\n if (p.phase === \"download\" && p.total) {\n const pct = Math.floor((p.downloaded / p.total) * 100)\n process.stderr.write(\n `\\r[kordoc-ocr] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\n )\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\n } else if (p.phase === \"verify\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} SHA-256 검증 중...\\n`)\n } else if (p.phase === \"done\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 준비 완료\\n`)\n } else if (p.phase === \"skip\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 이미 존재 (skip)\\n`)\n }\n })\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] OCR 모델 준비 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"models\")\n .description(\"OCR/수식 모델 오프라인 사이드로드 — 폐쇄망 반입용 내보내기/가져오기 (SHA-256 검증)\")\n .option(\"--status\", \"캐시에 설치된 모델 상태를 JSON 으로 출력\")\n .option(\"--export <dir>\", \"로컬 캐시 → 번들 디렉토리로 내보내기 (온라인 PC에서 실행)\")\n .option(\"--import <dir>\", \"번들 디렉토리 → 로컬 캐시로 설치 (내부망 PC에서 실행)\")\n .action(async (opts) => {\n try {\n const { exportModels, importModels, modelCacheStatus } = await import(\"../shared/model-bundle.js\")\n if (opts.status) {\n process.stdout.write(JSON.stringify(await modelCacheStatus(), null, 2) + \"\\n\")\n return\n }\n const dir = opts.export ?? opts.import\n if (!dir) {\n process.stderr.write(\"[kordoc] --status / --export <dir> / --import <dir> 중 하나가 필요합니다\\n\")\n process.exit(1)\n }\n if (opts.export && opts.import) {\n process.stderr.write(\"[kordoc] --export 와 --import 는 함께 쓸 수 없습니다\\n\")\n process.exit(1)\n }\n const result = opts.export ? await exportModels(dir) : await importModels(dir)\n for (const f of result.files) {\n const mark = f.status === \"copied\" ? \"+\" : f.status === \"invalid\" ? \"!\" : \"-\"\n process.stderr.write(` ${mark} ${f.group}/${f.filename}${f.reason ? ` — ${f.reason}` : \"\"}\\n`)\n }\n const verb = opts.export ? \"내보내기\" : \"설치\"\n const copied = result.files.filter((f) => f.status === \"copied\").length\n process.stderr.write(\n `[kordoc-models] ${verb} ${result.ok ? `완료 (${copied}개)` : \"실패 — 위 ! / - 항목 확인\"}: ${dir}\\n`,\n )\n if (!result.ok) process.exit(1)\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] 모델 사이드로드 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n}\n","/** kordoc CLI 명령: 상주 파싱 워커 (parse-worker) */\n\nimport { readFileSync, statSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { parse } from \"../index.js\"\nimport type { ParseOptions, ParseResult } from \"../types.js\"\nimport { VERSION, toArrayBuffer, sanitizeError, classifyError, routeConsoleToStderr } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\n/** 요청·응답 필드가 바뀌면 올린다. 호스트가 ready 줄로 호환을 판단한다 */\nexport const PARSE_WORKER_PROTOCOL = 1\n\n/** CLI 와 같은 입력 상한 */\nconst MAX_FILE_BYTES = 500 * 1024 * 1024\n\ninterface ParseWorkerRequest {\n id?: number\n cmd?: string\n file?: string\n /** false 면 이미지 바이트를 싣지 않는다 (ParseOptions.images) */\n images?: boolean\n /** \"off\"(기본) | \"auto\"(OCR 필요 페이지만) | \"force\"(전 페이지) */\n ocr?: \"off\" | \"auto\" | \"force\"\n formulaOcr?: boolean\n password?: string | null\n}\n\n/** 이미지 바이트는 --format json 과 같게 base64 로 */\nconst bytesToBase64 = (_key: string, value: unknown): unknown =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n\nasync function parseOne(req: ParseWorkerRequest & { file: string }): Promise<ParseResult> {\n const absPath = resolve(req.file)\n try {\n const size = statSync(absPath).size\n if (size > MAX_FILE_BYTES) {\n return { success: false, fileType: \"unknown\", error: `파일이 너무 큽니다 (${(size / 1024 / 1024).toFixed(1)}MB)`, code: \"PARSE_ERROR\" }\n }\n const options: ParseOptions = { filePath: absPath }\n if (req.images === false) options.images = false\n if (req.ocr === \"force\") options.ocr = \"force\"\n else if (req.ocr === \"auto\") options.ocr = true\n if (req.formulaOcr) options.formulaOcr = true\n if (req.password) options.password = req.password\n return await parse(toArrayBuffer(readFileSync(absPath)), options)\n } catch (err) {\n return { success: false, fileType: \"unknown\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\nexport function registerWorkerCommands(program: Command): void {\n program\n .command(\"parse-worker\")\n .description(\"상주 파싱 워커: stdin NDJSON 요청 → 한 줄 JSON 응답 (프로세스 유지, 파일마다 node 를 새로 띄우는 비용 제거)\")\n .action(async () => {\n // 프로토콜(NDJSON, 한 줄 = 한 메시지):\n // 시작 {\"ready\":true,\"version\":\"4.14.3\",\"protocol\":1}\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"images\":false,\"ocr\":\"off\",\"formulaOcr\":false,\"password\":null}\n // 응답 {\"id\":1,\"rss\":123456789,\"result\":{…}}: result 는 --format json 과 같은 ParseResult (실패도 success:false 로)\n // {\"id\":1,\"error\":\"…\"}: 요청 자체가 잘못됐을 때\n // {\"cmd\":\"quit\"} 또는 stdin 닫힘으로 종료. rss 는 호스트가 워커 교체 시점을 정하는 데 쓴다.\n // pdfjs 등이 console 로 찍는 경고가 stdout 프로토콜 줄을 깨지 않게 stderr 로 돌린다\n routeConsoleToStderr()\n const { createInterface } = await import(\"node:readline\")\n const rl = createInterface({ input: process.stdin, crlfDelay: Infinity })\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o, bytesToBase64) + \"\\n\")\n write({ ready: true, version: VERSION, protocol: PARSE_WORKER_PROTOCOL })\n for await (const line of rl) {\n const t = line.trim()\n if (!t) continue\n let req: ParseWorkerRequest\n // 비JSON 라인도 응답은 낸다. 무음 삼킴이면 id 를 기다리는 호스트가 영구 대기\n try { req = JSON.parse(t) } catch { write({ error: \"잘못된 JSON 라인\" }); continue }\n if (req === null || typeof req !== \"object\") { write({ error: \"JSON 객체가 아닙니다\" }); continue }\n if (req.cmd === \"quit\") break\n const id = req.id\n if (typeof req.file !== \"string\" || !req.file) { write({ id, error: \"file 필수\" }); continue }\n const result = await parseOne({ ...req, file: req.file })\n try {\n write({ id, rss: process.memoryUsage.rss(), result })\n } catch (err) {\n // 직렬화 한계(이미지 수백 장 base64 등, #65)는 실패 JSON 계약으로\n write({ id, rss: process.memoryUsage.rss(), result: { success: false, fileType: result.fileType, error: sanitizeError(err), code: classifyError(err) } })\n }\n }\n rl.close()\n // 파이프 stdout 은 맥·윈도에서 비동기라 바로 exit 하면 마지막 응답이 잘린다. 다 비운 뒤 끝낸다.\n // pdfjs 등이 남긴 핸들이 있어도 워커는 끝낸다 (호스트가 죽어 stdin 이 닫힌 경우의 고아 방지)\n await new Promise<void>((done) => process.stdout.write(\"\", () => done()))\n process.exit(0)\n })\n}\n"],"mappings":"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","names":["statSync","basename","resolve","resolve","basename","statSync","output","basename","program","basename","resolve","readFileSync","writeFileSync","mkdirSync","statSync","basename","resolve","program","resolve","statSync","readFileSync","basename","result","formInfo","mkdirSync","writeFileSync","detectFormat","readFileSync","writeFileSync","mkdirSync","statSync","basename","dirname","resolve","program","readFileSync","resolve","basename","mkdirSync","dirname","writeFileSync","statSync","readFileSync","writeFileSync","mkdirSync","dirname","resolve","program","resolve","readFileSync","mkdirSync","dirname","writeFileSync","program","readFileSync","statSync","resolve","resolve","statSync","readFileSync","program"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/cli/convert.ts","../src/cli/output-path.ts","../src/cli/batch.ts","../src/cli/commands-docs.ts","../src/cli/commands-generate.ts","../src/hwpx/number-lint.ts","../src/hwpx/level-styles.ts","../src/cli/commands-render.ts","../src/cli/commands-system.ts","../src/cli/commands-worker.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 (하위 명령은 cli/ 아래 명령군 모듈) */\n\nimport { Command } from \"commander\"\nimport { VERSION, sanitizeError, routeConsoleToStderr } from \"./utils.js\"\nimport { convertFiles } from \"./cli/convert.js\"\nimport { assertDistinctStems, convertParallel, registerBatchWorker } from \"./cli/batch.js\"\nimport { registerDocCommands } from \"./cli/commands-docs.js\"\nimport { registerGenerateCommands } from \"./cli/commands-generate.js\"\nimport { registerRenderCommands } from \"./cli/commands-render.js\"\nimport { registerSystemCommands } from \"./cli/commands-system.js\"\nimport { registerWorkerCommands } from \"./cli/commands-worker.js\"\n\nconst program = new Command()\n\nprogram\n .name(\"kordoc\")\n .description(\"모두 파싱해버리겠다 — HWP, HWPX, PDF, XLSX, DOCX, 이미지(PNG/JPG/WebP) → Markdown\")\n .version(VERSION)\n .argument(\"<files...>\", \"변환할 파일 경로 (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP — 이미지는 OCR 자동 적용)\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (단일 파일 시)\")\n .option(\"--jobs <count>\", \"병렬 변환 프로세스 수 (기본 1, 다중 파일은 -d 필요)\", \"1\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\n .option(\"-p, --pages <range>\", \"페이지 범위 (예: 1-3, 1,3,5) — 한컴 저장본은 실제 페이지, 조판 캐시 없으면 섹션 근사\")\n .option(\"--format <type>\", \"출력 형식: markdown (기본), json, chunks (RAG용 구조 청크 JSON — 헤딩·개조식 위계 breadcrumb + 표 독립 청크)\", \"markdown\")\n .option(\"--no-header-footer\", \"PDF 머리글/바닥글 자동 제거 끄기 (기본: 제거함)\")\n .option(\"--no-tables\", \"PDF 표 감지 끄기 — 테두리 박스를 표로 오인해 읽기 순서가 뒤집히는 문서(2단 시험지 등)에서 자연 읽기순 텍스트만 뽑는다 (#64)\")\n .option(\"--formula-ocr\", \"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드)\")\n .option(\"--ocr\", \"스캔/이미지 PDF 텍스트 OCR (내장 PP-OCRv5 korean, 첫 사용 시 모델 ~18MB 자동 다운로드 — OCR 필요 페이지만 인식)\")\n .option(\"--ocr-force\", \"전 페이지 강제 OCR (텍스트층이 있어도 무시하고 재인식)\")\n .option(\"--dedupe-headers\", \"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의)\")\n .option(\"--keep-empty-cols\", \"표 오른쪽 끝 빈 열(서식 입력란) 보존 (#47, 기본 off: 후행 빈 열 트림)\")\n .option(\"--keep-empty-paragraphs\", \"빈 문단 보존 — 본문은 빈 paragraph 블록, 표 셀은 빈 줄로 (#57, 기본 off: 빈 문단 제거)\")\n .option(\"--include-field-placeholders\", \"미기입 누름틀 안내문도 출력 — 빈 서식의 칸 용도 보존 (#92, 기본 off: 인쇄되지 않는 안내문 제외)\")\n .option(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\n .option(\"--image-refs\", \"--format json 에서 이미지 바이트를 인라인하지 않고 파일 참조(images/<문서 이름>/<파일명>)만 남김 (#65 — 이미지가 수백 장인 문서의 직렬화 한계 회피, -o/-d 와 함께 사용)\")\n .option(\"--password <pw>\", \"암호로 보호된 문서의 열기 암호 (#59, HWPX·HWP3·HWP5. 한컴 DRM 문서는 해당 없음)\")\n .option(\"--html-tables\", \"모든 표를 HTML 로 — 파이프 표도 HTML 표로, 태그마다 한 줄씩 들여써 냄\")\n .option(\"--table-format <format>\", \"표 출력 형식: gfm — 모든 표를 HTML 없이 GFM 파이프 표로, 셀 안 표는 부모 뒤 독립 표 + 관계 표지(<!-- <table … /> -->) (RAG 색인용, --html-tables 와 함께 못 씀)\")\n .option(\"--keep-layout-tables\", \"테두리가 안 보이는 틀 표도 원본 표 구조 그대로 (기본: 보이는 대로 — 틀은 글, 칸으로 조립한 분수는 수식). patch 로 되돌릴 편집본은 이 옵션으로 뽑는다\")\n .option(\"--script-tags\", \"위·아래첨자를 <sup>·<sub> 로 표기 — PDF 는 기본 끔(논문·수식 PDF 에 권장), HWPX·HWP·DOCX 는 기본 켬\")\n .option(\"--no-script-tags\", \"첨자 표기 끄기 — 모든 형식에서 평문(\\\"104 m2\\\")\")\n .option(\"--plain\", \"평문 Markdown — 그림 자리 표시·링크 URL·밑줄/굵게 표기를 빼고 글만 (제목·목록·표 구조는 유지, 색인·RAG 용)\")\n .option(\"--no-images\", \"이미지 바이트를 추출·출력하지 않음: 글자만 필요할 때 (그림 자리 표시는 남김, PDF 는 PNG 인코딩을 건너뜀)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (files: string[], opts) => {\n const validFormats = [\"markdown\", \"json\", \"chunks\"]\n if (!validFormats.includes(opts.format)) {\n process.stderr.write(`[kordoc] 지원하지 않는 형식: ${opts.format} (markdown, json, chunks)\\n`)\n process.exit(1)\n }\n if (opts.tableFormat !== undefined && opts.tableFormat !== \"gfm\") {\n process.stderr.write(`[kordoc] 지원하지 않는 표 형식: ${opts.tableFormat} (gfm)\\n`)\n process.exit(1)\n }\n if (opts.tableFormat && opts.htmlTables) {\n process.stderr.write(`[kordoc] --table-format 과 --html-tables 는 함께 쓸 수 없습니다\\n`)\n process.exit(1)\n }\n // -o는 단일 파일 전용 — 다중 파일에서 무음 무시되지 않게 경고\n if (opts.output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\n const jobs = Number(opts.jobs)\n if (!/^\\d+$/.test(opts.jobs) || !Number.isSafeInteger(jobs) || jobs < 1) {\n program.error(\"--jobs must be a positive integer\")\n }\n if (jobs > 1 && files.length > 1) {\n if (!opts.outDir) program.error(\"--jobs > 1 requires --out-dir for multiple files\")\n try {\n if (!await convertParallel(files, opts, jobs)) process.exitCode = 1\n } catch (err) {\n program.error(sanitizeError(err))\n }\n } else {\n if (opts.outDir && files.length > 1) {\n try { assertDistinctStems(files) } catch (err) { program.error(sanitizeError(err)) }\n }\n if (!await convertFiles(files, opts)) process.exitCode = 1\n }\n })\n\nregisterDocCommands(program)\nregisterGenerateCommands(program)\nregisterRenderCommands(program)\nregisterSystemCommands(program)\nregisterWorkerCommands(program)\nregisterBatchWorker(program)\n\n// stdout 은 마크다운·JSON·생성 바이너리 채널 — pdfjs 등이 console 로 찍는 경고가 섞이지 않게 stderr 로\n// (parse-worker·MCP 와 같은 처리). setup 은 사람이 보는 설치 화면이라 그대로 둔다\nprogram.hook(\"preAction\", (_program, action) => {\n if (action.name() !== \"setup\") routeConsoleToStderr()\n})\n\n// 출처를 node 로 고정 — 정하지 않으면 commander 가 process.versions.electron 을 보고 Electron 앱 방식(argv[1]부터)으로\n// 읽어, Electron 을 node 로 띄운(ELECTRON_RUN_AS_NODE) 데스크톱 앱에서 cli.js 자신이 입력 파일로 잡힌다\nprogram.parse(process.argv, { from: \"node\" })\n","/** Shared sequential conversion path for the CLI and batch workers. */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, resolve } from \"path\"\nimport type { OptionValues } from \"commander\"\nimport { parse, detectFormat } from \"../index.js\"\nimport type { ParseOptions } from \"../types.js\"\nimport { toArrayBuffer, sanitizeError, classifyError } from \"../utils.js\"\nimport { detectImageMime } from \"../hwp5/images.js\"\nimport { toPlainMarkdown } from \"../plain-markdown.js\"\nimport { toHtmlTables } from \"../html-tables.js\"\nimport { createOutputGuard } from \"./output-path.js\"\n\nexport async function convertFiles(files: string[], opts: OptionValues, writeOutput: (text: string) => void = text => { process.stdout.write(text) }, assertSafeOutputs = createOutputGuard(files)): Promise<boolean> {\n let failed = false\n for (let fi = 0; fi < files.length; fi++) {\n const filePath = files[fi]\n const absPath = resolve(filePath)\n const fileName = basename(absPath)\n const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : \"\"\n let detectedFormat: ReturnType<typeof detectFormat> = \"unknown\"\n\n try {\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`\\n[kordoc] SKIP: ${fileName} — 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n failed = true\n continue\n }\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n const format = detectFormat(arrayBuffer)\n detectedFormat = format\n\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`)\n }\n\n const parseOptions: ParseOptions = { filePath: absPath }\n if (opts.pages) parseOptions.pages = opts.pages as string\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\n if (opts.tables === false) parseOptions.tables = false\n if (opts.formulaOcr) parseOptions.formulaOcr = true\n if (opts.ocrForce) parseOptions.ocr = \"force\"\n else if (opts.ocr) parseOptions.ocr = true\n if (opts.dedupeHeaders) parseOptions.dedupeRunningHeaders = true\n if (opts.keepEmptyCols) parseOptions.keepTrailingEmptyCols = true\n if (opts.keepEmptyParagraphs) parseOptions.keepEmptyParagraphs = true\n if (opts.includeFieldPlaceholders) parseOptions.includeFieldPlaceholders = true\n if (opts.inlineImages) parseOptions.inlineImages = true\n if (opts.password) parseOptions.password = opts.password as string\n if (opts.images === false) parseOptions.images = false\n if (opts.plain) parseOptions.plain = true\n if (opts.scriptTags !== undefined) parseOptions.scriptTags = opts.scriptTags as boolean\n if (opts.htmlTables) parseOptions.htmlTables = true\n if (opts.tableFormat === \"gfm\") parseOptions.tableFormat = \"gfm\"\n if (opts.keepLayoutTables) parseOptions.layoutTables = \"keep\"\n if (!opts.silent) {\n parseOptions.onProgress = (current: number, total: number) => {\n process.stderr.write(`\\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`)\n }\n }\n const result = await parse(arrayBuffer, parseOptions)\n detectedFormat = result.fileType // ZIP 세분화(xlsx·docx) 반영 — 실패 JSON 의 fileType\n\n if (!result.success) {\n process.stderr.write(` FAIL\\n`)\n process.stderr.write(` → ${result.error}\\n`)\n // 실패는 모든 --format 에서 stdout 에 동일한 실패 JSON(success:false + code)을 낸다(#69)\n // — 호출자가 원인 코드(ENCRYPTED 등)로 분기할 수 있는 기계 계약. 성공 출력과 충돌하지\n // 않는다: markdown 성공은 마크다운, chunks 성공은 JSON 배열이고 실패는 객체 + exit 1.\n // stderr 의 FAIL 문구는 사람용으로 그대로 둔다.\n writeOutput(JSON.stringify({ ...result, file: fileName }, null, 2) + \"\\n\")\n failed = true\n continue\n }\n\n if (!opts.silent) process.stderr.write(` OK\\n`)\n\n let markdown = result.markdown\n // 이미지 인라인은 HWP5 경로에서만 실제로 일어난다(parser.ts). 그 외 포맷(HWPX/DOCX 등)은\n // --inline-images 를 줘도 인라인되지 않으므로, 이미지 저장/경로접두사를 생략하면 참조가\n // 깨지고(dangling) 바이트가 유실된다 → 실제 인라인된 경우에만 생략한다.\n const imagesInlined = opts.inlineImages && result.fileType === \"hwp\"\n // 그림을 파일로 저장하는 실행(--out-dir 또는 단일 파일 --output, 아래 saveImages)이면 이미지 참조 경로에 images/ 접두사 추가\n // (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀). 종전엔 --out-dir 만 봐서 -o 결과의 그림 링크가 전부 깨졌다(#94).\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\n const savesImageFiles = Boolean(opts.outDir || (opts.output && files.length === 1))\n // 그림은 문서마다 images/<문서 이름>/ 에 — 같은 폴더로 여러 문서를 변환하면 image_001.png 가 서로 덮어써졌다(#98).\n // 문서 이름은 출력 파일 이름(-o) 또는 입력 파일 이름(-d)에서 확장자를 뺀 것. 링크에서는 공백·괄호만 퍼센트 인코딩한다\n const docStem = (opts.output && files.length === 1 ? basename(opts.output) : fileName).replace(/\\.[^.]+$/, \"\")\n const imgLink = `images/${docStem.replace(/[ ()]/g, ch => encodeURIComponent(ch))}/`\n const linkImages = (text: string): string => savesImageFiles && result.images?.length && !imagesInlined\n ? text.replace(/!\\[image\\]\\(image_/g, `![image](${imgLink}image_`).replace(/(<img\\b[^>]*\\bsrc=\")image_/g, `$1${imgLink}image_`)\n : text\n markdown = linkImages(markdown)\n // json 직렬화 — refsOnly면 이미지 바이트를 빼고 저장 경로만 남긴다.\n // 이미지가 수백 장인 문서는 base64 총량이 V8 문자열 한계를 넘어 RangeError 로\n // 터졌고, 그 예외가 성공 로그 뒤 비-JSON 출력이 되어 파이프라인이 깨졌다 (#65).\n const serializeJson = (refsOnly: boolean): string => {\n const payload = refsOnly && result.images?.length\n ? { ...result, images: result.images.map(img => ({ filename: img.filename, mimeType: img.mimeType, path: `images/${docStem}/${img.filename}` })) }\n : result\n return JSON.stringify(payload, (_key, value) =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n , 2)\n }\n let output: string\n if (opts.format === \"json\") {\n const savesImages = Boolean((opts.output && files.length === 1) || opts.outDir) && !imagesInlined\n try {\n output = serializeJson(Boolean(opts.imageRefs) && savesImages)\n } catch (err) {\n // 한계 초과 — 이미지를 어차피 파일로 저장하는 실행이면 참조 모드로 자동 강등한다.\n // 저장 위치가 없으면(stdout) 구제할 방법이 없으므로 실패 JSON 계약으로 넘긴다.\n if (!savesImages || !result.images?.length) throw err\n output = serializeJson(true)\n process.stderr.write(` ⚠️ 이미지 base64 인라인이 직렬화 한계를 넘어 파일 참조로 대체했습니다 (${result.images.length}개 → images/${docStem}/)\\n`)\n }\n } else if (opts.format === \"chunks\") {\n // 청크 글에도 본문 마크다운과 같은 후처리(평문·HTML 표·그림 경로) — 종전엔 IR 에서 바로 만들어 --plain·--html-tables 를 무시했다\n const { blocksToChunks } = await import(\"../chunks.js\")\n const chunks = blocksToChunks(result.blocks, { tableFormat: parseOptions.tableFormat }).map(c => {\n let text = c.text\n if (opts.plain) text = toPlainMarkdown(text)\n if (opts.htmlTables) text = toHtmlTables(text)\n return { ...c, text: linkImages(text) }\n })\n output = JSON.stringify(chunks, null, 2)\n } else {\n output = markdown\n }\n\n // 이미지 저장 (--out-dir 또는 --output 시) — 실제 인라인된 경우(HWP5)에만 미저장, 그 외엔 저장 유지\n const saveImages = (dir: string) => {\n if (!result.images?.length || imagesInlined) return\n const imgDir = resolve(dir, \"images\", docStem)\n mkdirSync(imgDir, { recursive: true })\n for (const img of result.images) {\n writeFileSync(resolve(imgDir, img.filename), img.data)\n }\n // images/<문서 이름>/manifest.json — 소비자가 확장자·매직바이트 추측 없이 형식 분기(#70).\n // mimeType 은 매직바이트 실측 우선 — 확장자 유래 선언값은 실데이터와 어긋날 수 있다.\n const manifest = result.images.map(img => ({\n name: img.filename,\n mimeType: detectImageMime(img.data) ?? img.mimeType,\n bytes: img.data.length,\n ...(img.source ? { source: img.source } : {}),\n }))\n writeFileSync(resolve(imgDir, \"manifest.json\"), JSON.stringify(manifest, null, 2), \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir} (manifest.json 포함)\\n`)\n }\n\n // Validate the document and all image destinations together, before any file is written.\n const assertSafeDestination = (output: string, dir: string) => {\n const imageOutputs = result.images?.length && !imagesInlined\n ? [...result.images.map(img => resolve(dir, \"images\", docStem, img.filename)), resolve(dir, \"images\", docStem, \"manifest.json\")]\n : []\n assertSafeOutputs([output, ...imageOutputs])\n }\n\n if (opts.output && files.length === 1) {\n assertSafeDestination(opts.output, resolve(opts.output, \"..\"))\n writeFileSync(opts.output, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${opts.output}\\n`)\n saveImages(resolve(opts.output, \"..\"))\n } else if (opts.outDir) {\n mkdirSync(opts.outDir, { recursive: true })\n const outExt = opts.format === \"json\" ? \".json\" : opts.format === \"chunks\" ? \".chunks.json\" : \".md\"\n // 확장자 없는 입력(\"slides\")도 이름 뒤에 붙인다 — 종전 replace 는 그대로 두어 -d 가 입력 폴더면 입력 파일을 덮어썼다\n const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, \"\") + outExt)\n assertSafeDestination(outPath, opts.outDir)\n writeFileSync(outPath, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\n saveImages(opts.outDir)\n } else {\n writeOutput(output + \"\\n\")\n }\n } catch (err) {\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n // 파싱 이후(출력·직렬화) 단계에서 터져도 실패 JSON 을 내야 호출자가 원인 코드로\n // 분기할 수 있다 — 종전엔 성공 로그 뒤 비-JSON 이었다 (#65). json 외 포맷에도\n // 동일 계약을 적용한다 (#69).\n writeOutput(JSON.stringify({\n success: false,\n fileType: detectedFormat,\n // 다중 입력에서 어느 파일이 실패했는지 호출자가 기계적으로 특정할 수 있게 한다 (#69).\n // basename 만 노출 — 전체 경로는 내부 정보로 보아 넣지 않는다.\n file: fileName,\n error: sanitizeError(err),\n code: classifyError(err),\n }, null, 2) + \"\\n\")\n failed = true\n }\n }\n return !failed\n}\n","/** Protect every batch input, including symlink and hardlink aliases, before writing output. */\nimport { statSync } from \"node:fs\"\nimport { basename, resolve } from \"node:path\"\n\nexport function createOutputGuard(inputs: string[]): (outputs: string[]) => void {\n const paths = new Map(inputs.map(input => [resolve(input), basename(input)]))\n const identities = new Map<string, string>()\n for (const [input, name] of paths) {\n try {\n const stat = statSync(input, { bigint: true })\n identities.set(`${stat.dev}:${stat.ino}`, name)\n } catch { /* Missing or unreadable inputs are reported by the normal conversion path. */ }\n }\n return outputs => {\n for (const output of outputs) {\n let input = paths.get(resolve(output))\n if (!input) {\n try {\n const stat = statSync(output, { bigint: true })\n input = identities.get(`${stat.dev}:${stat.ino}`)\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\" && (err as NodeJS.ErrnoException).code !== \"ENOTDIR\") throw err\n }\n }\n if (input) throw new Error(`출력 경로가 입력 파일과 같습니다: ${input}`)\n }\n }\n}\n","/** Bounded, persistent process pool: CPU-heavy parsers get separate JS runtimes. */\nimport { fork, type ChildProcess } from \"node:child_process\"\nimport { basename } from \"node:path\"\nimport type { Command, OptionValues } from \"commander\"\nimport { KordocError } from \"../utils.js\"\nimport { convertFiles } from \"./convert.js\"\nimport { createOutputGuard } from \"./output-path.js\"\n\ninterface Job { file: string; opts: OptionValues; inputs?: string[] }\ninterface Done { ok: boolean; output: string[] }\n\nexport function registerBatchWorker(program: Command): void {\n program.command(\"__convert-worker\", { hidden: true }).action(() => {\n if (!process.send) program.error(\"Internal command requires an IPC channel\")\n // Do not leave native parser handles alive if the parent disappears.\n process.on(\"disconnect\", () => process.exit(0))\n let assertSafeOutputs: ReturnType<typeof createOutputGuard> | undefined\n process.on(\"message\", async ({ file, opts, inputs }: Job) => {\n const output: string[] = []\n assertSafeOutputs ??= createOutputGuard(inputs ?? [file])\n const ok = await convertFiles([file], opts, text => { output.push(text) }, assertSafeOutputs)\n process.send!({ ok, output } satisfies Done)\n })\n })\n}\n\n/**\n * Both converted documents and image directories are named after the input stem. Reject ambiguous\n * destinations before anything is written, including case variants — sequential `-d` runs used to\n * overwrite `a.md` and mix `images/a/` silently when two inputs shared a stem.\n */\nexport function assertDistinctStems(files: string[]): void {\n const stems = new Set<string>()\n for (const file of files) {\n const stem = basename(file).replace(/\\.[^.]+$/, \"\").normalize(\"NFC\").toLowerCase()\n if (stems.has(stem)) throw new KordocError(`Output name collision: ${basename(file)}; use distinct file stems`)\n stems.add(stem)\n }\n}\n\nexport async function convertParallel(files: string[], opts: OptionValues, jobs: number): Promise<boolean> {\n assertDistinctStems(files)\n\n const workers: ChildProcess[] = []\n let next = 0\n let failed = false\n const stop = () => { for (const worker of workers) worker.kill() }\n const onSigint = () => { stop(); process.exit(130) }\n const onSigterm = () => { stop(); process.exit(143) }\n process.once(\"SIGINT\", onSigint)\n process.once(\"SIGTERM\", onSigterm)\n try {\n await Promise.all(Array.from({ length: Math.min(jobs, files.length) }, () => new Promise<void>((resolve, reject) => {\n // Fork the same entry point: works in the bundled CLI and under tsx in tests.\n // Options travel over IPC so passwords never appear in child command lines.\n const worker = fork(process.argv[1], [\"__convert-worker\"], { stdio: [\"ignore\", \"ignore\", \"inherit\", \"ipc\"] })\n workers.push(worker)\n let current: string | undefined\n let finished = false\n let firstJob = true\n worker.on(\"error\", reject)\n worker.on(\"exit\", (code, signal) => {\n if (!finished) reject(new KordocError(`Conversion worker exited (${signal ?? code}) while processing ${basename(current ?? \"unknown\")}`))\n })\n const dispatch = () => {\n if (next === files.length) {\n finished = true\n worker.disconnect()\n resolve()\n return\n }\n current = files[next++]\n if (!opts.silent) process.stderr.write(`[kordoc] [${next}/${files.length}] ${basename(current)} ...\\n`)\n // Each worker writes a separate output tree; successful document data stays\n // in the worker, avoiding large IPC copies and buffering the entire batch.\n worker.send({ file: current, opts: { ...opts, output: undefined, silent: true }, ...(firstJob ? { inputs: files } : {}) } satisfies Job, err => {\n if (err) reject(err)\n })\n firstJob = false\n }\n worker.on(\"message\", ({ ok, output }: Done) => {\n if (!ok) failed = true\n // Only the parent writes stdout, preserving each failure JSON as one unit.\n for (const text of output) process.stdout.write(text)\n if (!opts.silent) process.stderr.write(`[kordoc] ${basename(current!)} ${ok ? \"OK\" : \"FAIL\"}\\n`)\n dispatch()\n })\n dispatch()\n })))\n return !failed\n } finally {\n stop()\n process.removeListener(\"SIGINT\", onSigint)\n process.removeListener(\"SIGTERM\", onSigterm)\n }\n}\n","/** kordoc CLI 명령 — 문서 처리 — watch·fill·seal·patch·validate */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, dirname, resolve, extname } from \"path\"\nimport { Command } from \"commander\"\nimport { parse, detectFormat, detectZipFormat, fillFormFields, extractFormFields, blocksToMarkdown, markdownToHwpx, fillHwpx, fillWithUniqueGuard, PRESET_ALIAS, extractClickHereFields, BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate } from \"../index.js\"\nimport type { FillInput } from \"../index.js\"\nimport { toArrayBuffer, sanitizeError } from \"../utils.js\"\n\nexport function registerDocCommands(program: Command): void {\n program\n .command(\"watch <dir>\")\n .description(\"디렉토리 감시 — 새 문서 자동 변환\")\n .option(\"--webhook <url>\", \"결과 전송 웹훅 URL\")\n .option(\"-d, --out-dir <dir>\", \"변환 결과 출력 디렉토리\")\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위\")\n .option(\"--format <type>\", \"출력 형식: markdown 또는 json\", \"markdown\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (dir: string, opts, command: Command) => {\n // 루트 커맨드의 동명 옵션(-d/--out-dir·-p/--pages·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.outDir ??= rootOpts.outDir\n opts.pages ??= rootOpts.pages\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\n const { watchDirectory } = await import(\"../watch.js\")\n await watchDirectory({\n dir,\n outDir: opts.outDir,\n webhook: opts.webhook,\n format: opts.format,\n pages: opts.pages,\n silent: opts.silent,\n })\n })\n\n program\n .command(\"fill [file]\")\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx / 내장 기안문 서식은 kordoc fill --template gian\")\n .option(\"-f, --fields <pairs>\", \"채울 필드 (key=value 쉼표 구분 또는 JSON)\")\n .option(\"-j, --json <path>\", \"채울 필드 JSON 파일 경로\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (확장자로 포맷 결정: .md, .hwpx)\")\n .option(\"--format <type>\", \"출력 포맷: hwpx-preserve (기본, 원본 스타일 보존), hwpx, markdown\", \"hwpx-preserve\")\n .option(\"--formats <json>\", \"필드별 값 서식 JSON (라벨→포맷) — 예: '{\\\"날짜\\\":\\\"yy.mm.dd\\\",\\\"주민등록번호\\\":\\\"rrn:masked\\\"}'\")\n .option(\"--template <name>\", \"내장 표준 서식 사용 (파일 경로 불필요): gian(일반기안문) | gian-simple(간이기안문). 위치 인자 'templates:일반기안문' 표기도 동일\")\n .option(\"--list-templates\", \"내장 표준 서식 목록 + 누름틀 필드 나열\")\n .option(\"--require-unique\", \"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 (반복 라벨 양식 오염 방지)\")\n .option(\"--mask\", \"채운 값 미노출 — 출력 파일 없이 markdown을 stdout으로 낼 때 본문 대신 안내만 표시\")\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string | undefined, opts, command: Command) => {\n try {\n // 루트 커맨드의 동명 옵션(-o/--output·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.output ??= rootOpts.output\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\n\n if (![\"hwpx-preserve\", \"hwpx\", \"markdown\"].includes(opts.format)) {\n process.stderr.write(`[kordoc] --format 는 hwpx-preserve/hwpx/markdown 중 하나여야 합니다: ${opts.format}\\n`)\n process.exit(1)\n }\n\n // --list-templates: 내장 서식 목록 + 누름틀 필드\n if (opts.listTemplates) {\n const list = []\n for (const t of BUILTIN_TEMPLATES) {\n const fields = await extractClickHereFields(readBuiltinTemplate(t))\n list.push({ id: t.id, aliases: t.aliases, title: t.title, fields: fields.map(f => f.name) })\n }\n process.stdout.write(JSON.stringify(list, null, 2) + \"\\n\")\n return\n }\n\n // 입력 소스 결정 — 내장 템플릿(--template 또는 'templates:이름' 위치 인자) 우선\n const templateName = opts.template ?? (file && /^templates?:/i.test(file) ? file : undefined)\n let arrayBuffer: ArrayBuffer\n let inputName: string\n if (templateName) {\n const t = resolveBuiltinTemplate(templateName)\n if (!t) {\n process.stderr.write(`[kordoc] 알 수 없는 내장 템플릿: ${templateName} (사용 가능: ${BUILTIN_TEMPLATES.map(x => `${x.id}(${x.aliases[0]})`).join(\", \")})\\n`)\n process.exit(1)\n }\n arrayBuffer = readBuiltinTemplate(t)\n inputName = t.file\n } else if (file) {\n const absPath = resolve(file)\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n process.exit(1)\n }\n arrayBuffer = toArrayBuffer(readFileSync(absPath))\n inputName = basename(absPath)\n } else {\n process.stderr.write(`[kordoc] 서식 파일 경로 또는 --template 을 지정해주세요 (목록: kordoc fill --list-templates)\\n`)\n process.exit(1)\n return\n }\n\n if (!opts.silent) process.stderr.write(`[kordoc] ${inputName} 파싱 중...\\n`)\n\n // --dry-run: 필드 목록만 출력 — 서식 입력란(빈 후행 열)이 목록에 나오도록 보존 (#47)\n if (opts.dryRun) {\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true, layoutTables: \"keep\" })\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n const formInfo = extractFormFields(result.blocks)\n // 누름틀(CLICK_HERE) 필드도 함께 나열 — 표준 서식은 라벨 표 없이 누름틀만 있을 수 있다\n const clickHereFields = detectFormat(arrayBuffer) === \"hwpx\"\n ? await extractClickHereFields(arrayBuffer)\n : []\n if (formInfo.fields.length === 0 && clickHereFields.length === 0) {\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\n process.exit(1)\n }\n process.stdout.write(JSON.stringify(\n clickHereFields.length > 0 ? { ...formInfo, clickHereFields } : formInfo,\n null, 2,\n ) + \"\\n\")\n return\n }\n\n // 필드 값 파싱\n let values: Record<string, string> = {}\n if (opts.json) {\n const jsonPath = resolve(opts.json)\n // Windows 메모장·PowerShell 이 붙이는 UTF-8 BOM 은 JSON.parse 가 거부한다\n const jsonContent = readFileSync(jsonPath, \"utf-8\").replace(/^/, \"\")\n values = JSON.parse(jsonContent)\n } else if (opts.fields) {\n const fieldsStr: string = opts.fields\n if (fieldsStr.startsWith(\"{\")) {\n values = JSON.parse(fieldsStr)\n } else {\n // \"key1=value1,key2=value2\" 파싱 — 값에 쉼표가 있을 수 있으므로\n // '=' 앞의 키를 기준으로 분리 (쉼표+한글/영문+= 패턴)\n const pairs = fieldsStr.split(/,(?=[가-힣A-Za-z][가-힣A-Za-z\\s]*=)/)\n for (const pair of pairs) {\n const eqIdx = pair.indexOf(\"=\")\n if (eqIdx > 0) {\n const key = pair.slice(0, eqIdx).trim()\n const val = pair.slice(eqIdx + 1).trim()\n values[key] = val\n }\n }\n }\n } else {\n process.stderr.write(`[kordoc] 채울 필드를 지정해주세요 (-f 또는 -j 옵션)\\n`)\n process.exit(1)\n }\n\n // 필드별 값 서식 결합 — MCP fill_form(formats)과 동일 의미론 (form/match.js FillInput)\n let inputs: Record<string, FillInput> = values\n if (opts.formats) {\n let formatMap: Record<string, string>\n try {\n formatMap = JSON.parse(String(opts.formats))\n } catch {\n process.stderr.write(`[kordoc] --formats 는 JSON 객체여야 합니다 (라벨→포맷)\\n`)\n process.exit(1)\n }\n inputs = Object.fromEntries(Object.entries(values).map(([k, v]) => {\n const format = formatMap[k]\n return [k, format ? { value: v, format } : v]\n }))\n }\n\n // 출력 포맷 결정 — 확장자 오버라이드가 명시 --format 과 충돌하면 경고 후 확장자 우선\n let outputFormat = opts.format as string\n if (opts.output) {\n const ext = extname(opts.output).toLowerCase()\n const explicitFormat = command.getOptionValueSource(\"format\") === \"cli\" || program.getOptionValueSource(\"format\") === \"cli\"\n const before = outputFormat\n if (ext === \".hwpx\") outputFormat = outputFormat === \"markdown\" ? \"hwpx-preserve\" : outputFormat\n else if (ext === \".md\") outputFormat = \"markdown\"\n if (explicitFormat && before !== outputFormat) {\n process.stderr.write(`[kordoc] ⚠️ --format ${before} 가 출력 확장자(${ext})와 충돌합니다 — 확장자 기준 ${outputFormat} 로 진행\\n`)\n }\n }\n\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 ───\n if (outputFormat === \"hwpx-preserve\") {\n const format = detectFormat(arrayBuffer)\n let isHwpx = format === \"hwpx\"\n if (isHwpx) {\n const zipFormat = await detectZipFormat(arrayBuffer)\n isHwpx = zipFormat === \"hwpx\"\n }\n if (!isHwpx) {\n if (!opts.silent) process.stderr.write(`[kordoc] HWPX가 아니므로 hwpx 모드로 전환합니다\\n`)\n outputFormat = \"hwpx\"\n } else {\n const hwpxResult = opts.requireUnique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(arrayBuffer, vals, blocked))\n : { ...(await fillHwpx(arrayBuffer, inputs)), rejected: [] as string[] }\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${hwpxResult.filled.length}개 필드 채움 (원본 스타일 보존)\\n`)\n if (hwpxResult.rejected.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${hwpxResult.rejected.join(\", \")}\\n`)\n }\n if (hwpxResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${hwpxResult.unmatched.join(\", \")}\\n`)\n }\n }\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxResult.buffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxResult.buffer))\n }\n return\n }\n }\n\n // ─── 일반 경로: parse → fill → output ─── (양식 입력란 보존, #47)\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true, layoutTables: \"keep\" })\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n\n const formInfo = extractFormFields(result.blocks)\n if (!opts.silent) {\n process.stderr.write(`[kordoc] 서식 필드 ${formInfo.fields.length}개 감지 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)\\n`)\n }\n\n const fillResult = opts.requireUnique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked))\n : { ...fillFormFields(result.blocks, inputs), rejected: [] as string[] }\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${fillResult.filled.length}개 필드 채움\\n`)\n if (fillResult.rejected.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${fillResult.rejected.join(\", \")}\\n`)\n }\n if (fillResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${fillResult.unmatched.join(\", \")}\\n`)\n }\n }\n\n const markdown = blocksToMarkdown(fillResult.blocks)\n\n if (outputFormat === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxBuffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxBuffer))\n }\n } else {\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), markdown, \"utf-8\")\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else if (opts.mask) {\n // 채운 값(주민번호·연락처 등)이 터미널 로그에 남지 않게 본문 대신 안내 (MCP mask_values와 동일 취지)\n process.stdout.write(`⚠️ --mask 활성 — 개인정보 노출 방지를 위해 본문을 출력하지 않습니다. -o 로 파일 저장 후 확인하세요.\\n`)\n } else {\n process.stdout.write(markdown + \"\\n\")\n }\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"seal <file>\")\n .description('도장/서명 이미지를 앵커 문구 위에 부유 배치 (표/페이지 불확장) — kordoc seal 신청서.hwpx --image 도장.png --anchor \"(인)\" -o 결과.hwpx')\n .requiredOption(\"--image <path>\", \"도장/서명 이미지 (투명 배경 PNG 권장)\")\n .option(\"--anchor <text>\", \"앵커 문구\", \"(인)\")\n .option(\"-n, --occurrence <num>\", \"같은 앵커가 여럿일 때 0-based 선택\", \"0\")\n .option(\"--size-mm <num>\", \"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\")\n .option(\"--mode <mode>\", \"overlap(문구 위 겹침) | right(오른쪽 옆) | auto\", \"auto\")\n .option(\"--dx <mm>\", \"x 미세조정 mm\", \"0\")\n .option(\"--dy <mm>\", \"y 미세조정 mm\", \"0\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <입력>.sealed.hwpx)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const { placeSealHwpx, detectFormat } = await import(\"../index.js\")\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const mode = String(opts.mode).toLowerCase()\n if (![\"overlap\", \"right\", \"auto\"].includes(mode)) {\n process.stderr.write(`[kordoc] --mode 는 overlap/right/auto 중 하나여야 합니다\\n`)\n process.exit(1)\n }\n const buf = new Uint8Array(readFileSync(resolve(file)))\n if (detectFormat(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer) !== \"hwpx\") {\n process.stderr.write(`[kordoc] seal 은 HWPX 전용입니다 (HWP 5.x 바이너리는 미지원)\\n`)\n process.exit(1)\n }\n const imgPath = resolve(opts.image)\n const imgSize = statSync(imgPath).size\n if (imgSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB)\\n`)\n process.exit(1)\n }\n const image = new Uint8Array(readFileSync(imgPath))\n const ext = extname(opts.image).slice(1).toLowerCase() || \"png\"\n // 숫자 플래그 엄격 검증 — 비숫자가 NaN→0 무증상 강제, 음수 occurrence가 truthy로\n // 통과하던 것 차단 (MCP zod와 동등, v4.0.6: --size-mm만 검증하던 것을 전 숫자 플래그로)\n const parseNum = (flag: string, raw: unknown, { min, allowNeg = false }: { min?: number; allowNeg?: boolean } = {}): number => {\n const n = Number(raw)\n if (!Number.isFinite(n) || (!allowNeg && n < 0) || (min !== undefined && n < min)) {\n process.stderr.write(`[kordoc] ${flag} 값이 잘못됐습니다: ${raw}${allowNeg ? \"\" : \" (0 이상 숫자)\"}\\n`)\n process.exit(1)\n }\n return n\n }\n let sizeMm: number | undefined\n if (opts.sizeMm != null) {\n const n = Number(opts.sizeMm)\n if (!Number.isFinite(n) || n <= 0) {\n process.stderr.write(`[kordoc] --size-mm 은 양수여야 합니다: ${opts.sizeMm}\\n`)\n process.exit(1)\n }\n sizeMm = n\n }\n const result = await placeSealHwpx(\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer,\n [{\n anchor: opts.anchor,\n occurrence: parseNum(\"--occurrence\", opts.occurrence),\n image,\n ext: ext as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\",\n sizeMm,\n mode: mode as \"overlap\" | \"right\" | \"auto\",\n dxMm: parseNum(\"--dx\", opts.dx, { allowNeg: true }),\n dyMm: parseNum(\"--dy\", opts.dy, { allowNeg: true }),\n }],\n )\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".sealed.hwpx\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(result.buffer))\n if (!silent) {\n for (const p of result.placed) {\n process.stderr.write(`[kordoc] 도장 배치: \"${p.anchor}\" #${p.occurrence} → ${p.mode} (${p.posXMm}mm, ${p.posYMm}mm, ${p.sizeMm}mm) [${p.entry}]\\n`)\n for (const w of p.warnings ?? []) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n process.stderr.write(`[kordoc] → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"patch <original> <edited>\")\n .description(\"서식 보존 라운드트립 패치 — 편집된 마크다운을 원본 HWPX/HWP에 in-place 반영 (kordoc patch 원본.hwpx 편집.md -o 출력.hwpx). 미적용(skip) 편집이 있으면 exit 2\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <원본>.patched.hwpx|.hwp)\")\n .option(\"--no-verify\", \"패치 후 재파싱 자동 검증 생략\")\n .option(\"--json\", \"결과(적용 수·건너뛴 편집·검증 잔차)를 JSON 으로 stdout 출력 — --silent 와 함께 써도 나온다\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (original: string, edited: string, opts) => {\n try {\n const { patchHwpx, patchHwp, detectFormat } = await import(\"../index.js\")\n // 루트 커맨드의 동명 옵션(-o/--silent)이 서브커맨드 옵션을 가로채는 commander 동작 보완\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const originalBuf = new Uint8Array(readFileSync(resolve(original)))\n const editedMarkdown = readFileSync(resolve(edited), \"utf-8\")\n\n const format = detectFormat(originalBuf.buffer as ArrayBuffer)\n const result = format === \"hwp\"\n ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n if (!result.success || !result.data) {\n if (opts.json) process.stdout.write(JSON.stringify({ success: false, error: result.error ?? \"알 수 없는 오류\", applied: result.applied, skipped: result.skipped }, null, 2) + \"\\n\")\n process.stderr.write(`[kordoc] 패치 실패: ${result.error ?? \"알 수 없는 오류\"}\\n`)\n process.exit(1)\n }\n\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\n const outPath = resolve(output ?? original.replace(/\\.hwpx?$/i, \"\") + \".patched\" + ext)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.data)\n\n if (opts.json) {\n // 외부 도구가 부분 적용(skip)·검증 잔차를 사용자에게 알릴 수 있게 — --silent 로는 사유가 통째로 사라졌다\n process.stdout.write(JSON.stringify({\n success: true, output: outPath, applied: result.applied, skipped: result.skipped,\n ...(result.verification ? { verification: result.verification.stats } : {}),\n }, null, 2) + \"\\n\")\n }\n if (!silent && !opts.json) {\n process.stderr.write(`[kordoc] ${result.applied}개 변경 적용 (원본 서식 보존) → ${outPath}\\n`)\n for (const s of result.skipped) {\n process.stderr.write(`[kordoc] ⚠️ SKIP: ${s.reason}${s.before ? ` | ${s.before}` : \"\"}\\n`)\n }\n if (result.verification) {\n const v = result.verification.stats\n const residual = v.added + v.removed + v.modified\n process.stderr.write(residual === 0\n ? `[kordoc] ✓ 검증: 편집 마크다운과 재파싱 결과 완전 일치 (${v.unchanged}블록)\\n`\n : `[kordoc] ⚠️ 검증 잔차: 수정 ${v.modified}, 추가 ${v.added}, 삭제 ${v.removed} (미지원 변경은 skip 목록 참조)\\n`)\n }\n }\n if (result.skipped.length > 0) process.exitCode = 2\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"compare <a> <b>\")\n .description(\"두 문서 비교 — 추가·삭제·변경 블록 (HWP↔HWPX 등 형식이 달라도 됨, 신구대조표용). 차이가 있으면 exit 1\")\n .option(\"--json\", \"비교 결과(stats·diffs)를 JSON 으로 stdout 출력\")\n .action(async (a: string, b: string, opts) => {\n try {\n const { compare } = await import(\"../index.js\")\n const read = (p: string): ArrayBuffer => { const buf = readFileSync(resolve(p)); return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer }\n const result = await compare(read(a), read(b))\n const { stats, diffs } = result\n if (opts.json) process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\n else {\n process.stdout.write(`추가 ${stats.added} · 삭제 ${stats.removed} · 변경 ${stats.modified} · 동일 ${stats.unchanged}\\n`)\n for (const d of diffs) {\n if (d.type === \"unchanged\") continue\n const mark = d.type === \"added\" ? \"+\" : d.type === \"removed\" ? \"-\" : \"~\"\n const text = (blk?: { text?: string; table?: unknown }) => (blk?.text ?? (blk?.table ? \"[표]\" : \"\")).replace(/\\s+/g, \" \").slice(0, 160)\n if (d.type === \"modified\") process.stdout.write(`~ ${text(d.before)}\\n → ${text(d.after)}\\n`)\n else process.stdout.write(`${mark} ${text(d.after ?? d.before)}\\n`)\n }\n }\n process.exit(stats.added + stats.removed + stats.modified > 0 ? 1 : 0)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(2)\n }\n })\n\n program\n .command(\"validate <file>\")\n .description(\"HWPX 구조 검증 — ZIP·mimetype·필수 파일·XML 웰폼드·secCnt·manifest 참조 (한컴독스 거부 요인 사전 차단)\")\n .option(\"--json\", \"결과를 JSON으로 stdout에 출력\")\n .action(async (file: string, opts) => {\n try {\n const { validateHwpx } = await import(\"../index.js\")\n const buf = new Uint8Array(readFileSync(resolve(file)))\n const result = await validateHwpx(buf)\n if (opts.json) {\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\n } else if (result.ok) {\n process.stderr.write(`[kordoc] ✓ 구조 검증 통과 (엔트리 ${result.entryCount}개): ${file}\\n`)\n } else {\n process.stderr.write(`[kordoc] ✗ 구조 문제 ${result.issues.length}건: ${file}\\n`)\n for (const i of result.issues) {\n process.stderr.write(`[kordoc] - ${i.path ? `${i.path}: ` : \"\"}${i.message}\\n`)\n }\n }\n if (!result.ok) process.exit(1)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n // 공문서 프리셋 별칭(한글/영문) → 내부 preset 키 — gongmun.ts와 공용(PRESET_ALIAS)\n}\n","/** kordoc CLI 명령 — 생성·검수 — generate·profile·lint·redact */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, dirname, resolve } from \"path\"\nimport { checkTableNumbers, numberBlocksFromIR, numberBlocksFromMarkdown } from \"../hwpx/number-lint.js\"\nimport { extractLevelStyles } from \"../hwpx/level-styles.js\"\nimport { parseMarkdownToBlocks } from \"../hwpx/md-runs.js\"\nimport { detectFormat, markdownToHwpx, hwpxToProfile, PRESET_ALIAS, unknownFontWarnings, incompatibleGongmunWarnings, lintGongmunText, gongmunLintWarnings, lintMuncheText, muncheLintWarnings, usesGaejosikMunche } from \"../index.js\"\nimport { parseFormatProfileJson } from \"../hwpx/profile-io.js\"\nimport { loadGenerationImages } from \"../shared/generate-images.js\"\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS, parseLevelsSpec, levelFontRecord } from \"../hwpx/gongmun-surface.js\"\nimport type { FormatProfile } from \"../hwpx/gen-profile.js\"\nimport { toArrayBuffer, sanitizeError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerGenerateCommands(program: Command): void {\n program\n .command(\"generate <markdown>\")\n .alias(\"gen\")\n .description(\"마크다운 → 공문서 HWPX 생성 — kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 (markdown에 '-' 지정 시 stdin)\")\n .option(\"-o, --output <path>\", \"출력 HWPX 경로 (기본: <입력>.hwpx)\")\n .option(\"--preset <name>\", \"공문서 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)·개조식(gaejosik — 표지·목차·장헤더 자동)·업무보고(ministry — 중앙부처 업무보고: 장 띠·절 숫자칸·소제목 박스·① 항목 띠·성과 요약박스·별첨 띠)·서울방침(bangchim — 서울시 방침서: 제목표·파랑 부제·요약박스·[Ⅰ] 장 상자·절 띠·❶ 과제)·보도자료(press)\", \"기안문\")\n .option(\"--font <type>\", \"본문 글꼴: myeongjo(함초롬바탕) 또는 gothic(맑은 고딕)\")\n .option(\"--pt <size>\", \"본문 글자 크기(pt)\")\n .option(\"--line-spacing <percent>\", \"본문 줄간격(%)\")\n .option(\"--profile <path>\", \"서식 프로필 JSON (kordoc profile로 추출) — 참조 문서의 표 테두리·음영·열폭·셀 글꼴 재현\")\n .option(\"--org <name>\", \"표지 기관명 (표지를 켜는 프리셋 공통)\")\n .option(\"--date <date>\", \"표지 날짜 (기본 오늘 — 'YYYY. M. D.')\")\n .option(\"--toc\", \"목차 페이지 강제 켜기 (개조식 외 프리셋에서도 h2 목록으로 생성)\")\n .option(\"--no-toc\", \"목차 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\n .option(\"--cover\", \"표지 페이지 강제 켜기 (개조식 외 프리셋에서도 첫 h1을 표지로)\")\n .option(\"--no-cover\", \"표지 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\n .option(\"--approval <labels>\", \"결재란 직위 라벨 (쉼표 구분, 예: 담당,팀장,과장) — 문서 최상단 우측\")\n .option(\"--page-numbers\", \"쪽번호 강제 켜기 (하단 중앙 '- 1 -')\")\n .option(\"--no-page-numbers\", \"쪽번호 끄기 (개조식·보고서·계획서 기본 켜짐)\")\n .option(\"--end-mark\", \"본문 끝 '끝.' 표시 강제 켜기\")\n .option(\"--no-end-mark\", \"'끝.' 표시 끄기 (기안문 기본 켜짐)\")\n .option(\"--no-body-title-box\", \"본문 첫 페이지 제목 반복 박스 끄기 (개조식+표지 기본 켜짐)\")\n .option(\"--chapter-fit\", \"개조식 장 헤더 제목 칸을 글자 폭에 맞춤 (기본: 본문 폭까지)\")\n .option(\"--h2-marker <type>\", \"h2 장 제목 표기: band(로마자 채움 칸 + 제목 띠 표 — 보고서·계획서 기본)·roman(Ⅰ. 텍스트)·number(1. — 통지 기본)·box(장 없이 □ 대항목)·none\")\n .option(\"--band-color <hex>\", \"띠 제목 번호칸 채움색 #RRGGBB (기본 #003366 — 실측 최다. 교육청형 밝은 띠: #DFE6F7)\")\n .option(\"--band-text-color <hex>\", \"띠 제목 번호 글자색 #RRGGBB (기본 #FFFFFF — 밝은 띠면 #000000)\")\n .option(\"--summary <text>\", \"보고서 요약 박스 (제목표 아래 음영 상자 — 마크다운 제목 직후 인용문(>)으로도 지정)\")\n .option(\"--doc-info <spec>\", \"보고서 표지 문서정보표: docNum=스마트도시과-123,date=2026. 9. 6.,disclosure=공개,policyNo= (--cover와 함께)\")\n .option(\"--dept <name>\", \"표지 부서명 (기관명 아래 괄호)\")\n .option(\"--checklist [na]\", \"서울 사전 검토항목 점검표(보고서·계획서·서울방침) — 값 없으면 빈 서식, 해당없음 문항 번호를 주면(6,7,8) 나머지는 검토완료\")\n .option(\"--cover-label <text>\", \"표지 우상단 취급 표시 — '대외주의'·'비공개' 빨간 테두리 박스 (업무보고 프리셋 실측)\")\n .option(\"--fonts <spec>\", \"요소별 글꼴 오버라이드: body=나눔명조,heading=나눔고딕,ref=한양중고딕,table=맑은 고딕\")\n .option(\"--sizes <spec>\", \"개조식 요소별 크기(pt): dae=16,cham=13,table=12,coverTitle=30 …\")\n .option(\"--levels <spec>\", \"항목부호 단계별 위계 타이포: 0=HY견고딕/17/bold,1=한컴돋움/15/bold,2=휴먼명조/14 (depth 0~7, 숫자=pt·bold·plain·글꼴명)\")\n .option(\"--levels-from <hwpx>\", \"견본 HWPX 에서 항목부호 단계별 글꼴·크기·굵기를 배워 적용 (kordoc levels 와 같은 추출, --levels 로 준 단계가 우선)\")\n .option(\"--bullet2 <char>\", \"2단계 항목부호: ㅇ(이응 — 기안문·공고문 실측 지배) 또는 ○(원 — 보고서 양식)\")\n .option(\"--suppress-single\", \"단일 형제 항목 부호 생략 (편람 규정 — 기본은 하나여도 부호 부여)\")\n .option(\"--doc-head <spec>\", \"기안문 두문표: org=기관명,slogan=원훈,to=수신처,title=제목 (별지 제1호서식·서울 실결재 6행 표)\")\n .option(\"--doc-foot <spec>\", \"기안문 결문표: sender=발신명의,drafter=주무관 홍길동,reviewer=과장 김철수,approver=국장 박영희,cooperator=협조자,docNum=시행(과-번호 (날짜)),receive=접수,zip=우편번호,address=주소,site=홈페이지,phone=전화,fax=전송,email=메일,disclosure=공개구분\")\n .option(\"--report-info <text>\", \"보고서 담당자 행(제목표 아래) / 기안문 우상단 보고정보 행 — 예: '(2026. 7. 11., 과장 홍길동, ☎02-120)'\")\n .option(\"--notice-head <spec>\", \"공고문 두문·결문: no=공고 제2026-1호,date=2026년 7월 11일,sender=행정안전부장관\")\n .option(\"--press-head <spec>\", \"보도자료 머리: release=보도시점,distribute=배포일,dept=담당부서,manager=담당자,phone=연락처\")\n .option(\"--press-sub <items>\", \"보도자료 부제 (세미콜론 구분, 제목 아래 '- … -')\")\n .option(\"--plain\", \"공문서 모드 끄기 (범용 마크다운 변환)\")\n .option(\"--paper <size>\", \"용지: A4·A3·B4·B5·Letter 또는 '210x297'(mm)\")\n .option(\"--landscape\", \"용지 가로 방향\")\n .option(\"--columns <n>\", \"다단 개수 (1~8)\")\n .option(\"--header <text>\", \"머리말 텍스트 (모든 쪽, 인라인 마크다운 허용)\")\n .option(\"--footer <text>\", \"꼬리말 텍스트\")\n .option(\"--image-dir <dir>\", \"마크다운 이미지 참조(![](x.png))를 이 디렉토리에서 읽어 실데이터 임베드\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (markdown: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const plain: boolean = opts.plain ?? rootOpts.plain\n\n // 입력: '-' 이면 stdin, 아니면 파일\n let md: string\n let baseName = \"document\"\n if (markdown === \"-\") {\n md = readFileSync(0, \"utf-8\")\n } else {\n const inPath = resolve(markdown)\n md = readFileSync(inPath, \"utf-8\")\n baseName = basename(inPath).replace(/\\.(md|markdown|txt)$/i, \"\")\n }\n\n // 공문서 옵션 구성 — 값 검증(열거)과 조립은 gongmun-surface SSOT, 여기는\n // commander 표면 사정(kv 파싱·--no-x 기본값)을 중립 입력으로 정돈하는 어댑터만\n let gongmun: import(\"../index.js\").GongmunOptions | undefined\n if (!plain) {\n const preset = PRESET_ALIAS[String(opts.preset).trim()]\n if (!preset) {\n process.stderr.write(`[kordoc] 알 수 없는 프리셋: ${opts.preset} (기안문/보고서/계획서/통지/회의록/개조식/업무보고/서울방침/보도자료)\\n`)\n process.exit(1)\n }\n const enumCheck = <T extends readonly string[]>(flag: string, value: unknown, allowed: T): (typeof allowed)[number] | undefined => {\n if (value === undefined) return undefined\n if (!allowed.includes(String(value))) {\n process.stderr.write(`[kordoc] ${flag} 는 ${allowed.join(\"/\")}\\n`)\n process.exit(1)\n }\n return value as (typeof allowed)[number]\n }\n // 견본 HWPX 단계별 서식 — 대표값이 정해진 단계·속성만 (--levels 가 우선)\n let learnedLevels: Record<string, { font?: string; pt?: number; bold?: boolean }> | undefined\n if (opts.levelsFrom) {\n const learned = await extractLevelStyles(toArrayBuffer(readFileSync(resolve(String(opts.levelsFrom)))))\n learnedLevels = learned.levels\n if (!silent) process.stderr.write(learned.spec\n ? `[kordoc] 견본 단계별 서식: ${learned.spec}\\n`\n : `[kordoc] ⚠️ 견본에서 단계별 대표 서식을 정하지 못함 (단계마다 표본 3개 이상·한 값 60% 이상 필요) — 엔진 기본값 사용\\n`)\n }\n // \"key=value,key=value\" 스펙 파싱 — 값의 '='는 보존(첫 '='만 분리). 쉼표는\n // 구분자라 값에 못 들어감 — '=' 없는 조각(잘린 값의 꼬리 등)은 무증상 드랍\n // 대신 경고로 노출 (v4.0.6: 두문 title 값 유실이 조용히 지나가던 것 봉합)\n const parseKv = (spec: string, flag: string): Record<string, string> => {\n const out: Record<string, string> = {}\n for (const piece of spec.split(\",\")) {\n const p = piece.trim()\n if (!p) continue\n const eq = p.indexOf(\"=\")\n const key = eq > 0 ? p.slice(0, eq).trim() : \"\"\n const value = eq > 0 ? p.slice(eq + 1).trim() : \"\"\n if (!key || !value) {\n process.stderr.write(`[kordoc] ${flag}: 'key=value' 형식이 아닌 조각 무시 — \"${p}\" (값에 쉼표는 쓸 수 없습니다)\\n`)\n continue\n }\n out[key] = value\n }\n return out\n }\n const pressKv = opts.pressHead ? parseKv(String(opts.pressHead), \"--press-head\") : {}\n gongmun = buildGongmunOptions({\n preset,\n font: enumCheck(\"--font\", opts.font, BODY_FONTS),\n bodyPt: opts.pt ? Number(opts.pt) : undefined,\n lineSpacing: opts.lineSpacing ? Number(opts.lineSpacing) : undefined,\n org: opts.org, date: opts.date,\n cover: opts.cover, toc: opts.toc,\n approval: opts.approval ? String(opts.approval).split(\",\").map((s: string) => s.trim()).filter(Boolean) : undefined,\n pageNumbers: opts.pageNumbers, endMark: opts.endMark,\n // --no-body-title-box 단독 플래그 — commander 기본 true는 \"미지정\"으로 정돈\n bodyTitleBox: opts.bodyTitleBox === false ? false : undefined,\n chapterFit: opts.chapterFit,\n h2Marker: enumCheck(\"--h2-marker\", opts.h2Marker, H2_MARKERS),\n bandColor: opts.bandColor, bandTextColor: opts.bandTextColor,\n fonts: opts.fonts ? parseKv(String(opts.fonts), \"--fonts\") : undefined,\n sizes: opts.sizes\n ? Object.fromEntries(\n Object.entries(parseKv(String(opts.sizes), \"--sizes\")).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v as number)),\n )\n : undefined,\n levels: opts.levels || learnedLevels\n ? { ...learnedLevels, ...(opts.levels ? parseLevelsSpec(String(opts.levels)) : {}) }\n : undefined,\n bullet2: enumCheck(\"--bullet2\", opts.bullet2, BULLET2_CHARS),\n suppressSingle: opts.suppressSingle ? true : undefined,\n docHead: opts.docHead ? parseKv(String(opts.docHead), \"--doc-head\") : undefined,\n docFoot: opts.docFoot ? parseKv(String(opts.docFoot), \"--doc-foot\") : undefined,\n reportInfo: opts.reportInfo ? String(opts.reportInfo) : undefined,\n summary: opts.summary ? String(opts.summary) : undefined,\n docInfo: opts.docInfo ? parseKv(String(opts.docInfo), \"--doc-info\") : undefined,\n checklist: opts.checklist === undefined ? undefined : opts.checklist === true ? true : { na: String(opts.checklist).split(\",\").map((x) => Number(x.trim())).filter((x) => x !== 0) },\n dept: opts.dept ? String(opts.dept) : undefined,\n coverLabel: opts.coverLabel ? String(opts.coverLabel) : undefined,\n noticeHead: opts.noticeHead ? parseKv(String(opts.noticeHead), \"--notice-head\") : undefined,\n press: opts.pressHead || opts.pressSub\n ? {\n release: pressKv.release, distribute: pressKv.distribute,\n sub: opts.pressSub ? String(opts.pressSub).split(\";\").map((s: string) => s.trim()).filter(Boolean) : undefined,\n contact: pressKv.dept || pressKv.manager || pressKv.phone ? { dept: pressKv.dept, manager: pressKv.manager, phone: pressKv.phone } : undefined,\n }\n : undefined,\n })\n }\n\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행\n if (gongmun?.fonts && !silent) {\n for (const w of unknownFontWarnings(gongmun.fonts)) process.stderr.write(`[kordoc] ${w}\\n`)\n }\n if (gongmun?.levels && !silent) {\n for (const w of unknownFontWarnings(levelFontRecord(gongmun.levels))) process.stderr.write(`[kordoc] ${w}\\n`)\n }\n // 프리셋 비호환 옵션 경고 (v4.0.6) — 조용한 폐기 대신 노출, 생성은 진행\n if (gongmun && !silent) {\n for (const w of incompatibleGongmunWarnings(gongmun)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n // 공문서 표기법 검수 (편람 기준, 조언용) — 생성은 진행, stderr 경고만\n if (gongmun && !silent) {\n for (const w of gongmunLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n // 개조식 문체 검수 — 보고서·계획서·개조식 프리셋만. 기안문(경어)·통지·보도자료는\n // 문체 관행이 달라 적용하지 않는다 (범위를 좁히는 것이 오탐을 막는다)\n if (gongmun && !silent && usesGaejosikMunche(gongmun.preset)) {\n for (const w of muncheLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n }\n\n // 서식 프로필 (이슈 #41) — 경계 zod 검증 후 라이브러리에 전달 (MCP와 공유 스키마)\n let profile: FormatProfile | undefined\n if (opts.profile) {\n profile = parseFormatProfileJson(readFileSync(resolve(String(opts.profile)), \"utf-8\"))\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 적용: 표 ${profile.tables.length}개 (${opts.profile})\\n`)\n }\n\n // 페이지 옵션 (v4.5.0) — 용지·방향·다단·머리말/꼬리말\n let page: import(\"../index.js\").PageOptions | undefined\n if (opts.paper || opts.landscape || opts.columns || opts.header || opts.footer) {\n let size: import(\"../index.js\").PageOptions[\"size\"]\n if (opts.paper) {\n const wh = /^(\\d+(?:\\.\\d+)?)x(\\d+(?:\\.\\d+)?)$/i.exec(String(opts.paper).trim())\n size = wh ? { widthMm: Number(wh[1]), heightMm: Number(wh[2]) } : (String(opts.paper) as \"A4\")\n }\n page = {\n ...(size !== undefined ? { size } : {}),\n ...(opts.landscape ? { orientation: \"landscape\" as const } : {}),\n ...(opts.columns ? { columns: Number(opts.columns) } : {}),\n ...(opts.header ? { header: String(opts.header) } : {}),\n ...(opts.footer ? { footer: String(opts.footer) } : {}),\n }\n }\n // MCP와 같은 Unicode·실경로 검증을 적용한다.\n let imageBytes: Record<string, Uint8Array> | undefined\n if (opts.imageDir) {\n const dir = resolve(String(opts.imageDir))\n const loaded = await loadGenerationImages(md, dir)\n imageBytes = loaded.images\n if (!silent) {\n process.stderr.write(`[kordoc] 이미지 임베드: ${Object.keys(imageBytes ?? {}).length}개 (${dir})\\n`)\n for (const warning of loaded.warnings) process.stderr.write(`[kordoc] ⚠ ${warning}\\n`)\n }\n }\n\n const genWarnings: string[] = []\n const buf = await markdownToHwpx(md, gongmun || profile || page || imageBytes\n ? {\n ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}),\n ...(page ? { page } : {}), ...(imageBytes ? { images: imageBytes } : {}),\n warnings: genWarnings,\n }\n : undefined)\n if (!silent) for (const w of genWarnings) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\n const outPath = resolve(output ?? (markdown === \"-\" ? `${baseName}.hwpx` : markdown.replace(/\\.(md|markdown|txt)$/i, \"\") + \".hwpx\"))\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(buf))\n\n if (!silent) {\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\n process.stderr.write(`[kordoc] HWPX 생성 (${mode}) → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"levels <file>\")\n .description(\"견본 HWPX 의 항목부호 단계별 글꼴·크기·굵기 추출 — generate --levels 값과 단계별 분포·서식 편차 (kordoc levels 견본.hwpx, generate --levels-from 으로 바로 적용)\")\n .option(\"--json\", \"추출 결과(levels·spec·stats·deviations)를 JSON 으로 stdout 출력\")\n .action(async (file: string, opts) => {\n try {\n const r = await extractLevelStyles(toArrayBuffer(readFileSync(resolve(file))))\n if (opts.json) {\n process.stdout.write(JSON.stringify(r, null, 2) + \"\\n\")\n return\n }\n if (!r.scheme) {\n process.stderr.write(`[kordoc] ${r.note ?? \"항목부호(□·ㅇ·- 또는 1.·가.)로 시작하는 문단이 없음\"}\\n`)\n return\n }\n process.stdout.write(`${r.spec || \"(대표값 없음 — 단계마다 표본 3개 이상·한 값 60% 이상 필요)\"}\\n`)\n for (const st of r.stats.filter(x => x.scheme === r.scheme)) {\n const top = (m: Record<string, number>) => Object.entries(m).sort((a, b) => b[1] - a[1]).map(([k, n]) => `${k}×${n}`).join(\" \")\n process.stderr.write(` ${st.depth}단계 ${st.markers.join(\"\")} 표본 ${st.samples} — 글꼴 ${top(st.font)} · 크기 ${top(st.pt)} · 굵게 ${top(st.bold)}\\n`)\n }\n if (r.deviations.length) process.stderr.write(`[kordoc] 서식 편차 ${r.deviations.length}건 — kordoc lint ${file} --styles 로 확인\\n`)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"profile <file>\")\n .description(\"HWPX 표 서식 프로필 추출 — 참조 문서의 표 테두리·음영·열폭·셀 글꼴을 JSON으로 (generate --profile로 재현) — kordoc profile 참조.hwpx -o 서식.json\")\n .option(\"-o, --output <path>\", \"출력 JSON 경로 (기본: <입력>.profile.json)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const absPath = resolve(file)\n const profile = await hwpxToProfile(readFileSync(absPath))\n const outPath = resolve(output ?? absPath.replace(/\\.hwpx$/i, \"\") + \".profile.json\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, JSON.stringify(profile, null, 2))\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 추출: 표 ${profile.tables.length}개 → ${outPath}\\n`)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"lint <file>\")\n .description(\"공문서 표기법 검수 — 날짜·시간·금액·붙임 등 행정업무운영 편람 표기법 (md/txt 또는 HWPX·HWP·PDF 등 문서, '-'=stdin). error 있으면 exit 1\")\n .option(\"--json\", \"JSON 출력\")\n .option(\"--munche\", \"개조식 문체 검수 병행 — 서술형 종결·당위·수사·항목 길이 (보고서·계획서 원고용)\")\n .option(\"--numbers\", \"본문 수치 ↔ 표 수치 대조 병행 — 표 가까이 본문의 수치가 그 표에 있는지 (확인 목록, exit 코드에는 영향 없음)\")\n .option(\"--styles\", \"단계별 서식 편차 병행 (HWPX) — 같은 항목부호 단계인데 글꼴·크기·굵기가 대표값과 다른 문단 (exit 코드에는 영향 없음)\")\n .action(async (file: string, opts) => {\n try {\n const raw = file === \"-\" ? readFileSync(0) : readFileSync(resolve(file))\n // 문서 파일은 파싱한 본문 마크다운을 검사한다 — UTF-8 텍스트로 읽으면 압축 바이트가 본문으로 둔갑해\n // 위반 수백~수천 건이 쏟아졌다(\"보고서.hwpx\" 실측 1,193건)\n const ab = raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength) as ArrayBuffer\n const kind = detectFormat(ab)\n let text: string\n let irBlocks: Parameters<typeof numberBlocksFromIR>[0] | undefined\n if (kind === \"unknown\") text = raw.toString(\"utf-8\")\n else {\n const { parse } = await import(\"../index.js\")\n const parsed = await parse(ab, file === \"-\" ? undefined : { filePath: resolve(file) })\n if (!parsed.success) {\n process.stderr.write(`[kordoc] 오류: ${kind} 문서를 읽지 못했습니다 — ${parsed.error}\\n`)\n process.exit(1)\n }\n text = parsed.markdown\n irBlocks = parsed.blocks\n }\n const findings = lintGongmunText(text, { document: true, parsed: kind !== \"unknown\" })\n // 문체 검수는 옵트인 — 축이 다르고(표기법 vs 종결·수사), 개조식이 아닌 원고에는\n // 적용하면 안 되기 때문에 기본 동작은 종전 그대로 둔다\n const munche = opts.munche ? lintMuncheText(text) : []\n const styles = opts.styles && kind === \"hwpx\" ? (await extractLevelStyles(ab)).deviations : undefined\n if (opts.styles && kind !== \"hwpx\") process.stderr.write(`[kordoc] --styles 는 HWPX 문서만 — 건너뜀\\n`)\n const numbers = opts.numbers\n ? checkTableNumbers(irBlocks ? numberBlocksFromIR(irBlocks) : numberBlocksFromMarkdown(parseMarkdownToBlocks(text)))\n : undefined\n const errors = findings.filter((f) => f.severity === \"error\").length\n + munche.filter((f) => f.severity === \"error\").length\n if (opts.json) {\n const total = findings.length + munche.length\n process.stdout.write(JSON.stringify(\n { findings, ...(opts.munche ? { munche } : {}), ...(numbers ? { numbers } : {}), ...(styles ? { styles } : {}), summary: { total, errors, ok: errors === 0 } }, null, 2) + \"\\n\")\n } else {\n // 사람용 리포트는 stderr — 기계용(--json)만 stdout (validate와 채널 일관)\n process.stderr.write(`[kordoc] 표기법 검수: 위반 ${findings.length}건 (error ${findings.filter((f) => f.severity === \"error\").length}, warning ${findings.filter((f) => f.severity !== \"error\").length})\\n`)\n for (const f of findings) {\n process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\n }\n if (styles) {\n process.stderr.write(`[kordoc] 단계별 서식 편차: ${styles.length}건\\n`)\n const show = (st: { font?: string; pt?: number; bold?: boolean }) => [st.font, st.pt === undefined ? undefined : `${st.pt}pt`, st.bold === undefined ? undefined : st.bold ? \"굵게\" : \"보통\"].filter(Boolean).join(\"/\")\n for (const d of styles) process.stderr.write(` ${d.depth}단계 \"${d.text}\" — ${show(d.got)} (대표 ${show(d.expected)})\\n`)\n }\n if (numbers) {\n process.stderr.write(`[kordoc] 수치 대조: 표 가까이 본문 수치 ${numbers.checked}개 중 표에서 못 찾은 ${numbers.review.length}개 (확인 필요)\\n`)\n for (const r of numbers.review) process.stderr.write(` \"${r.match}\" — ${r.context}\\n`)\n }\n if (opts.munche) {\n const me = munche.filter((f) => f.severity === \"error\").length\n process.stderr.write(`[kordoc] 문체 검수: 위반 ${munche.length}건 (error ${me}, warning ${munche.length - me})\\n`)\n for (const f of munche) {\n process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\n }\n }\n }\n process.exit(errors > 0 ? 1 : 0)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"redact <files...>\")\n .description(\"개인정보 서식 보존 마스킹 — 주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허(--rules 로 인명·주소 opt-in)를 탐지해 HWPX/HWP는 원본 서식 그대로 같은 길이로 가린 파일(본문·표·머리말/꼬리말·각주·글상자·미리보기·메타데이터 포함), 그 외 포맷(PDF 등)은 원본을 건드리지 않고 마스킹된 마크다운만 출력. 자동 검출 보조 도구이므로 결과는 반드시 사람이 최종 확인하세요 (이미지 속 글자는 탐지 불가)\")\n .option(\"--rules <csv>\", \"적용 룰 (기본: rrn,phone,email,card,account,brn,passport,driver — crn(법인등록번호),ip,name(인명),address(주소)는 opt-in)\")\n .option(\"--mask-char <ch>\", \"마스크 문자 1글자 (기본: ●)\")\n .option(\"-o, --output <path>\", \"출력 경로 (단일 파일 시)\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\n .option(\"--dry-run\", \"탐지 리포트만 출력, 파일 미생성\")\n .option(\"--json\", \"리포트를 JSON으로 stdout 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (files: string[], opts) => {\n const { ALL_REDACT_RULES, DEFAULT_REDACT_RULES, redactText } = await import(\"../redact.js\")\n const { redactDocument } = await import(\"../redact-doc.js\")\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n // 루트 명령도 -d/--out-dir 를 정의해 먼저 삼킨다 — -o 와 같은 방식으로 양쪽을 본다\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const KNOWN_RULES = new Set<string>(ALL_REDACT_RULES)\n const rules = opts.rules\n ? String(opts.rules).split(\",\").map((r: string) => r.trim()).filter(Boolean)\n : [...DEFAULT_REDACT_RULES]\n const badRule = rules.find((r: string) => !KNOWN_RULES.has(r))\n if (badRule) {\n process.stderr.write(`[kordoc] 알 수 없는 룰: ${badRule} (허용: ${[...KNOWN_RULES].join(\", \")})\\n`)\n process.exit(1)\n }\n const maskChar: string = opts.maskChar ?? \"●\"\n try { redactText(\"\", { maskChar }) } catch (err) {\n process.stderr.write(`[kordoc] ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n if (output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\n // 파일 이름에도 PII 가 있을 수 있다 — 결과 파일 이름·메시지·JSON 에는 가린 이름을 쓴다\n // (디렉토리 이름은 그대로). 윈도가 파일 이름에 못 쓰는 마스크 문자(* ?)는 ●로\n const nameMask = /[*?]/.test(maskChar) ? \"●\" : maskChar\n const maskName = (name: string): string => {\n // 파일 이름은 _ 로 낱말을 잇는다(\"민원_010-2345-6789\") — 탐지만 공백으로 보고 같은 자리를 가린다\n const probe = name.replace(/_/g, \" \")\n const out = [...name]\n for (const h of redactText(probe, { rules: rules as never, maskChar: nameMask }).hits) {\n for (let k = 0; k < h.length; k++) if (h.masked[k] !== probe[h.index + k]) out[h.index + k] = nameMask\n }\n return out.join(\"\")\n }\n const shown = (p: string): string => resolve(dirname(p), maskName(basename(p)))\n const inputs = files.map((f) => resolve(f))\n const sameFile = (a: string, b: string): boolean => {\n if (a === b) return true\n try {\n const sa = statSync(a), sb = statSync(b)\n return sa.ino === sb.ino && sa.dev === sb.dev // 대소문자 무시 파일시스템·하드링크\n } catch { return false }\n }\n const written = new Set<string>()\n /** 기본 출력 경로 — 입력 파일·이번 실행의 다른 출력과 겹치면 -2, -3 … 을 붙인다 */\n const defaultOut = (absPath: string, ext: string): string => {\n const stem = maskName(basename(absPath)).replace(/\\.[^.]+$/, \"\")\n const dir = resolve(outDir ?? dirname(absPath))\n for (let n = 1; ; n++) {\n const p = resolve(dir, `${stem}${n > 1 ? `-${n}` : \"\"}.redacted${ext}`)\n if (!written.has(p) && !inputs.some((i) => sameFile(i, p))) return p\n }\n }\n const MAX_LINES = 200\n const jsonReports: unknown[] = []\n for (const absPath of inputs) {\n const fileName = maskName(basename(absPath))\n if (output && files.length === 1 && !opts.dryRun && sameFile(absPath, resolve(output))) {\n process.stderr.write(`[kordoc] ERROR: ${fileName} — 출력 경로가 입력 파일과 같습니다. 원본을 덮어쓰지 않습니다 — 다른 -o 경로를 지정하세요\\n`)\n process.exitCode = 1\n continue\n }\n try {\n const buffer = readFileSync(absPath)\n const r = await redactDocument(toArrayBuffer(buffer), {\n rules: rules as never, maskChar, filePath: absPath, dryRun: opts.dryRun,\n })\n // 리포트 기준: HWPX/HWP 는 파일 안 위치(본문·머리말·미리보기 …), 그 외 포맷은 본문 마크다운\n const listed = r.fileHits.length > 0\n ? r.fileHits.map((h) => ({ rule: h.rule, masked: h.masked, at: `${h.where} @ ${h.part}` }))\n : r.markdownHits.map((h) => ({ rule: h.rule, masked: h.masked, at: \"\" }))\n const byRule = new Map<string, number>()\n for (const h of listed) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\n const ruleSummary = [...byRule.entries()].map(([k, v]) => `${k} ${v}건`).join(\", \") || \"0건\"\n const failed = r.residual.length > 0 || r.unscanned.length > 0\n\n let outPath: string | null = null\n let note = \"\"\n // HWPX/HWP 는 결과 바이트가 원본과 다르면 저장 (탐지 0건이어도 미할당 영역을 비웠으면 저장),\n // 그 외 포맷은 본문에서 찾은 게 있을 때 마스킹된 마크다운을 저장\n const save = r.data ? r.changed : r.markdownHits.length > 0\n if (!opts.dryRun && save) {\n const ext = r.data ? (r.format === \"hwp\" ? \".hwp\" : \".hwpx\") : \".md\"\n outPath = output && files.length === 1 ? resolve(output) : defaultOut(absPath, ext)\n mkdirSync(dirname(outPath), { recursive: true })\n if (r.data) writeFileSync(outPath, r.data)\n else {\n writeFileSync(outPath, r.markdown, \"utf-8\")\n note = ` (${r.format} 원본은 수정하지 않음 — 마스킹된 마크다운만 출력)`\n }\n written.add(outPath)\n } else if (!opts.dryRun && r.data && listed.length > 0) {\n note = \" (❌ 파일에서 가린 곳이 없어 출력하지 않음)\"\n }\n if (failed && process.exitCode !== 1) process.exitCode = 2 // 실패(1)가 우선\n if (opts.json) {\n jsonReports.push({\n file: shown(absPath), format: r.format, rules, hits: r.markdownHits, fileHits: r.fileHits,\n residual: r.residual, unscanned: r.unscanned, warnings: r.warnings, output: outPath,\n })\n }\n if (!silent) {\n process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` → ${outPath}` : opts.dryRun ? \" (dry-run)\" : \"\"}${note}\\n`)\n // 같은 값·같은 위치는 한 줄로 (미리보기·메타데이터에 같은 번호가 반복되는 경우), 너무 길면 자른다\n const grouped = new Map<string, number>()\n for (const h of listed) {\n const key = ` - [${h.rule}] ${h.masked}${h.at ? ` (${h.at})` : \"\"}`\n grouped.set(key, (grouped.get(key) ?? 0) + 1)\n }\n const lines = [...grouped].map(([line, n]) => `${line}${n > 1 ? ` ×${n}` : \"\"}`)\n for (const line of lines.slice(0, MAX_LINES)) process.stderr.write(`${line}\\n`)\n if (lines.length > MAX_LINES) process.stderr.write(` … 외 ${lines.length - MAX_LINES}줄 (전체는 --json)\\n`)\n if (r.residual.length > 0) {\n process.stderr.write(`[kordoc] ❌ 마스킹 후 재검사에서 PII ${r.residual.length}건이 남아 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요:\\n`)\n for (const h of r.residual.slice(0, MAX_LINES)) process.stderr.write(` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})\\n`)\n if (r.residual.length > MAX_LINES) process.stderr.write(` … 외 ${r.residual.length - MAX_LINES}건 (전체는 --json)\\n`)\n }\n if (r.unscanned.length > 0) {\n process.stderr.write(`[kordoc] ❌ 글자를 검사하지 못한 곳이 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요: ${r.unscanned.join(\", \")}\\n`)\n }\n for (const w of r.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n }\n if (opts.json) process.stdout.write(JSON.stringify(files.length === 1 ? jsonReports[0] ?? null : jsonReports, null, 2) + \"\\n\")\n })\n}\n","/**\n * 본문 수치 ↔ 표 수치 대조 (`kordoc lint --numbers`) — 표를 소개·요약하는 본문의 수치가 그 표에 같은 숫자로 있는지 본다.\n * 정확한 대응 검증이 아니라 \"표와 어긋난 숫자는 아닌지\" 1차 점검이고, 결과는 오류가 아니라 확인 목록이다.\n * 문서 전체의 본문 수치를 다 대조하면 서술용 수치가 대부분 걸려(보도자료·업무계획 45개 중 34개) 범위를 좁힌다:\n * - 표 앞뒤 NEAR 블록 안의 본문만, 숫자가 MIN_TABLE_NUMBERS 개 이상인 표만\n * - 그 표에 같은 단위가 나오는 수치만 — 칸에 단위가 붙은 숫자(\"4대\"·\"218억원\"), 또는 \"(단위: 억원)\" 같은 표 단위\n * 표기가 있으면 그 표의 모든 숫자와 짝짓는다. 날짜·차수·순번 단위는 대조하지 않는다\n * - 기준값 표현(\"60% 이상\"·\"목표인 40%\"·\"1조원 내외\")은 표에 없는 게 정상이라 대조하지 않는다\n * - 찾을 때는 앞뒤 FIND_WINDOW 블록의 표를 다 보고, 소수점이 있거나 세 자리 이상인 수는 단위 없이 적힌 칸(\"(25.7)\" 비중\n * 열)과도 같은 수로 본다 — 행 번호처럼 우연히 겹치는 흔한 수(11)는 단위가 맞아야 한다\n * (코퍼스 HWP·HWPX 200건: 확인 목록 22건 → 2건. 빠진 20건은 기준값이거나 바로 아래 다른 표·단위 없는 비중 칸에 있던 값,\n * 남은 2건은 같은 보도자료 두 벌의 \"4.56조원\" 으로 문서의 어느 표에도 없다)\n * 착안·임계값: hwp-auto-docfit number_check.py (MIT, THIRD_PARTY/hwp-auto-docfit.LICENSE, 22개 문서 실측)\n */\n\n/** 대조 입력 블록 — 표는 칸 글 행렬, 그 밖은 글 */\nexport interface NumberCheckBlock {\n type: \"table\" | \"text\"\n text?: string\n rows?: string[][]\n}\n\nexport interface NumberReview {\n /** 걸린 본문 수치 (\"218억원\") */\n match: string\n /** 그 수치가 든 본문 (앞 80자) */\n context: string\n}\n\nconst UNIT = String.raw`억\\s?원|조\\s?원|백만\\s?원|천만\\s?원|천\\s?원|만\\s?원|원|%p|%p|%|%|명|건|개소|곳|대|가구|세대|톤|㎡|㎢|km|㎞`\nconst NUM = String.raw`\\d{1,3}(?:,\\d{3})+(?:\\.\\d+)?|\\d+(?:\\.\\d+)?`\n/** 단위 뒤에 글자가 이어지면 단어의 일부(\"대부분\"의 \"대\")다 — 끝이거나, 글자가 아니거나, 조사 하나로 끝날 때만 단위 */\nconst UNIT_END = String.raw`(?=$|[^가-힣A-Za-z]|(?:으로|에서|까지|부터|보다|이며|이고|은|는|이|가|을|를|의|에|로|과|와|도|만|씩)(?![가-힣A-Za-z]))`\nconst VALUE_UNIT = new RegExp(String.raw`(?<![\\d.,])(${NUM})\\s?(${UNIT})${UNIT_END}`, \"g\")\nconst BARE_NUMBER = new RegExp(String.raw`(?<![\\d.])(${NUM})`, \"g\")\nconst TABLE_UNIT_NOTE = new RegExp(String.raw`[((]\\s*(?:단위\\s*[::]\\s*)?(${UNIT})\\s*[))]|단위\\s*[::]\\s*(${UNIT})`, \"g\")\nconst MIN_TABLE_NUMBERS = 5\n/** 기준·목표값 — 수치 바로 뒤 \"이상·이하·초과·미만·내외·수준\", 또는 앞 8자 안의 \"목표·기준·상한·하한\" */\nconst THRESHOLD_AFTER = /^\\s?(?:이상|이하|초과|미만|내외|수준|안팎|가량|정도)/\nconst THRESHOLD_BEFORE = /(?:목표|기준|상한|하한|최소|최대|약)[^\\d]{0,8}$/\nconst NEAR = 3\nconst FIND_WINDOW = 10\n\nconst normNumber = (v: string): string => {\n const s = v.replace(/,/g, \"\")\n return s.includes(\".\") ? s.replace(/0+$/, \"\").replace(/\\.$/, \"\") : s\n}\nconst normUnit = (u: string): string => u.replace(/\\s/g, \"\").replace(/%/g, \"%\")\n\n/** 표의 단위별 숫자 집합과 전체 숫자 수 */\nfunction tableNumbers(rows: string[][]): { byUnit: Map<string, Set<string>>; all: Set<string>; count: number } {\n const all = new Set<string>()\n for (const row of rows) for (const cell of row) for (const m of (cell ?? \"\").matchAll(BARE_NUMBER)) all.add(normNumber(m[1]))\n const byUnit = new Map<string, Set<string>>()\n const add = (unit: string, values: Iterable<string>): void => {\n const set = byUnit.get(unit) ?? new Set<string>()\n for (const v of values) set.add(v)\n byUnit.set(unit, set)\n }\n for (const row of rows) {\n for (const cell of row) {\n for (const m of (cell ?? \"\").matchAll(VALUE_UNIT)) add(normUnit(m[2]), [normNumber(m[1])])\n for (const m of (cell ?? \"\").matchAll(TABLE_UNIT_NOTE)) add(normUnit(m[1] ?? m[2]), all)\n }\n }\n return { byUnit, all, count: all.size }\n}\n\n/** 표 가까이의 본문 수치 가운데 그 표에서 찾지 못한 것 */\nexport function checkTableNumbers(blocks: NumberCheckBlock[]): { checked: number; review: NumberReview[] } {\n const tables = blocks.flatMap((b, i) => {\n if (b.type !== \"table\" || !b.rows) return []\n const t = tableNumbers(b.rows)\n return t.count >= MIN_TABLE_NUMBERS ? [{ i, byUnit: t.byUnit, all: t.all }] : []\n })\n let checked = 0\n const review: NumberReview[] = []\n blocks.forEach((b, i) => {\n if (b.type !== \"text\" || !b.text) return\n const near = tables.filter(t => Math.abs(t.i - i) <= NEAR)\n if (!near.length) return\n const seen = new Set<string>()\n for (const m of b.text.matchAll(VALUE_UNIT)) {\n const at = m.index!, end = at + m[0].length\n if (THRESHOLD_AFTER.test(b.text.slice(end)) || THRESHOLD_BEFORE.test(b.text.slice(Math.max(0, at - 12), at))) continue\n const key = m[0].replace(/\\s/g, \"\")\n if (seen.has(key)) continue\n seen.add(key)\n const unit = normUnit(m[2])\n if (!near.some(t => t.byUnit.has(unit))) continue\n checked++\n const value = normNumber(m[1])\n const distinctive = value.includes(\".\") || value.replace(/^0+/, \"\").length >= 3\n const found = tables.some(t => Math.abs(t.i - i) <= FIND_WINDOW\n && (t.byUnit.get(unit)?.has(value) || (distinctive && t.all.has(value))))\n if (!found) {\n review.push({ match: `${m[1]}${m[2]}`, context: b.text.replace(/\\s+/g, \" \").trim().slice(0, 80) })\n }\n }\n })\n return { checked, review }\n}\n\n/** 파싱한 문서 IR → 대조 블록 (표는 칸 글, 문단·제목·목록은 글. 칸 안 표는 겉 표 칸 글로만 본다) */\nexport function numberBlocksFromIR(blocks: Array<{ type: string; text?: string; table?: { cells: Array<Array<{ text: string } | undefined>> } }>): NumberCheckBlock[] {\n return blocks.flatMap((b): NumberCheckBlock[] => {\n if (b.type === \"table\" && b.table) return [{ type: \"table\", rows: b.table.cells.map(row => row.map(c => c?.text ?? \"\")) }]\n return b.text ? [{ type: \"text\", text: b.text }] : []\n })\n}\n\n/** 마크다운 원고 블록 → 대조 블록 */\nexport function numberBlocksFromMarkdown(blocks: Array<{ type: string; text?: string; rows?: string[][] }>): NumberCheckBlock[] {\n return blocks.flatMap((b): NumberCheckBlock[] => {\n if (b.type === \"table\" && b.rows) return [{ type: \"table\", rows: b.rows }]\n return b.text ? [{ type: \"text\", text: b.text }] : []\n })\n}\n","/**\n * 견본 HWPX 의 항목부호 단계별 서식 — 기관마다 □·ㅇ·- (또는 1. 가. 1)) 단계의 글꼴·크기·굵기 관행이 달라, 그 기관 문서\n * 한 벌에서 배워 generate 의 단계별 위계 타이포(GongmunOptions.levels, `--levels`)로 넘긴다. 같은 단계인데 서식이 다른\n * 문단(편차)도 함께 낸다(`kordoc lint --styles`).\n *\n * 문단 단계는 생성 엔진과 같은 부호 해석(outline.parseLeadingMarker)으로, 서식은 부호 뒤 첫 글자가 든 글자 모양으로 잰다.\n * 칸이 여럿인 데이터 표 안 문단은 표 서식(작은 글씨 '-' 항목 등)이라 빼고, 본문을 담는 1×1 틀 상자 안 문단은 남긴다.\n * 대표값은 단계·속성마다 표본 MIN_SAMPLES 개 이상이고 한 값이 MIN_SHARE 이상일 때만 정한다 — 섞여 쓴 속성은 비워 엔진\n * 기본을 따르게 한다. □·ㅇ·- 계열과 법정 계열 가운데 표본이 많은 쪽을 문서의 계열로 본다.\n * 착안·임계값: hwp-auto-docfit style_unify.py·document_review.py (MIT, THIRD_PARTY/hwp-auto-docfit.LICENSE)\n */\n\nimport JSZip from \"jszip\"\nimport type { Element as XmlElement } from \"@xmldom/xmldom\"\nimport { extractHwpxStyles } from \"./styles.js\"\nimport { resolveSectionPaths } from \"./zip-sections.js\"\nimport { parseLeadingMarker } from \"./outline.js\"\nimport { createXmlParser, readZipEntry } from \"./parser-shared.js\"\nimport { KordocError, stripDtd, precheckZipSize } from \"../utils.js\"\nimport { detectFormat } from \"../detect.js\"\nimport type { GongmunLevelStyle } from \"./gongmun.js\"\n\nconst MIN_SAMPLES = 3\nconst MIN_SHARE = 0.6\n\n/** 한 문단의 단계 서식 표본 */\ninterface LevelSample {\n scheme: \"box\" | \"legal\"\n depth: number\n marker: string\n text: string\n font?: string\n pt?: number\n bold: boolean\n}\n\nexport interface LevelStat {\n scheme: \"box\" | \"legal\"\n depth: number\n /** 이 단계에 쓰인 부호 (등장 순) */\n markers: string[]\n samples: number\n /** 속성별 값 → 문단 수 */\n font: Record<string, number>\n pt: Record<string, number>\n bold: Record<string, number>\n}\n\nexport interface LevelDeviation {\n depth: number\n /** 문단 앞 40자 */\n text: string\n got: GongmunLevelStyle\n expected: GongmunLevelStyle\n}\n\nexport interface LevelStyleReport {\n /** 표본을 잴 수 없었던 사유 (글자 모양 정의가 없는 HWPX 등) */\n note?: string\n /** 문서의 부호 계열 — 표본 없으면 null */\n scheme: \"box\" | \"legal\" | null\n /** 대표값이 정해진 단계·속성만 (generate levels 입력) */\n levels: Record<string, GongmunLevelStyle>\n /** `--levels` 문자열 (\"0=HY견고딕/17/bold,1=…\") — 대표값이 없으면 \"\" */\n spec: string\n stats: LevelStat[]\n /** 대표값과 다른 문단 (문서 계열만) */\n deviations: LevelDeviation[]\n}\n\nconst local = (n: { nodeName: string }): string => n.nodeName.replace(/^.*:/, \"\")\n\n/** <hp:t> 글 — 탭 요소는 \"\\t\" (항목부호 뒤는 공백이 아니라 탭인 문서가 많다: \"□<hp:tab/>\" + \"첫째 대항목\") */\nfunction runText(t: XmlElement): string {\n let out = \"\"\n for (let n = t.firstChild; n; n = n.nextSibling) {\n if (n.nodeType === 3) out += n.nodeValue ?? \"\"\n else if (n.nodeType === 1 && local(n) === \"tab\") out += \"\\t\"\n }\n return out\n}\n\n/** 칸이 여럿인 표 안 문단 — 가장 가까운 표의 행·열 수로 (1×1 틀 상자는 본문으로 본다) */\nfunction inDataTable(p: XmlElement): boolean {\n for (let n = p.parentNode as XmlElement | null; n; n = n.parentNode as XmlElement | null) {\n if (n.nodeType === 1 && local(n) === \"tbl\") {\n const el = n\n return Number(el.getAttribute(\"rowCnt\") ?? 1) * Number(el.getAttribute(\"colCnt\") ?? 1) > 1\n }\n }\n return false\n}\n\n/** 글자 모양 id → 한글 글꼴명 — 한컴 HWPX 는 글꼴을 번호(<hh:fontRef hangul=\"1\">)로 가리키고 이름은 글꼴 목록\n * (<hh:fontface lang=\"HANGUL\"><hh:font id face>)에 둔다 */\nfunction hangulFaces(headerXml: string): Map<string, string> {\n const doc = createXmlParser().parseFromString(stripDtd(headerXml), \"text/xml\")\n const faces = new Map<string, string>()\n const fontfaces = doc.getElementsByTagNameNS(\"*\", \"fontface\")\n for (let i = 0; i < fontfaces.length; i++) {\n if (fontfaces[i].getAttribute(\"lang\") !== \"HANGUL\") continue\n const fonts = fontfaces[i].getElementsByTagNameNS(\"*\", \"font\")\n for (let k = 0; k < fonts.length; k++) faces.set(fonts[k].getAttribute(\"id\") ?? \"\", fonts[k].getAttribute(\"face\") ?? \"\")\n }\n const out = new Map<string, string>()\n const charPrs = doc.getElementsByTagNameNS(\"*\", \"charPr\")\n for (let i = 0; i < charPrs.length; i++) {\n const ref = charPrs[i].getElementsByTagNameNS(\"*\", \"fontRef\")[0]\n const face = ref ? faces.get(ref.getAttribute(\"hangul\") ?? \"\") : undefined\n if (face) out.set(charPrs[i].getAttribute(\"id\") ?? \"\", face)\n }\n return out\n}\n\n/** 견본 HWPX → 단계별 대표 서식과 편차 */\nexport async function extractLevelStyles(buffer: ArrayBuffer): Promise<LevelStyleReport> {\n const format = detectFormat(buffer)\n if (format !== \"hwpx\") throw new KordocError(`단계별 서식은 HWPX 견본에서만 잽니다 (감지된 포맷: ${format}) — 한글에서 HWPX 로 저장해 넘기세요`)\n precheckZipSize(buffer)\n const zip = await JSZip.loadAsync(buffer)\n const decompressed = { total: 0 }\n const styles = await extractHwpxStyles(zip, decompressed)\n const header = zip.file(\"Contents/header.xml\") ?? zip.file(\"Contents/head.xml\")\n const faces = header ? hangulFaces(await readZipEntry(header, \"text\", decompressed.total)) : new Map<string, string>()\n const samples: LevelSample[] = []\n for (const path of await resolveSectionPaths(zip)) {\n const file = zip.file(path)\n if (!file) continue\n const xml = await readZipEntry(file, \"text\", decompressed.total)\n decompressed.total += xml.length * 2\n const doc = createXmlParser().parseFromString(stripDtd(xml), \"text/xml\")\n const paras = doc.getElementsByTagNameNS(\"*\", \"p\")\n for (let i = 0; i < paras.length; i++) {\n const p = paras[i]\n if (inDataTable(p)) continue\n // 문단 직속 run 만 — 칸 안 문단은 그 문단이 따로 잡힌다\n const runs: Array<{ text: string; charPr: string | null }> = []\n for (let c = p.firstChild; c; c = c.nextSibling) {\n if (c.nodeType !== 1 || local(c) !== \"run\") continue\n const el = c as unknown as Element\n let text = \"\"\n const ts = el.getElementsByTagNameNS(\"*\", \"t\")\n for (let k = 0; k < ts.length; k++) if (ts[k].parentNode === el) text += runText(ts[k] as unknown as XmlElement)\n runs.push({ text, charPr: el.getAttribute(\"charPrIDRef\") })\n }\n const text = runs.map(r => r.text).join(\"\")\n const lm = parseLeadingMarker(text)\n if ((lm.kind !== \"box\" && lm.kind !== \"legal\") || !lm.rest) continue\n // 부호 뒤 첫 글자가 든 run 의 글자 모양\n const at = text.indexOf(lm.rest)\n let pos = 0, charPr: string | null = null\n for (const r of runs) {\n if (at < pos + r.text.length) { charPr = r.charPr; break }\n pos += r.text.length\n }\n const cp = charPr ? styles.charProperties.get(charPr) : undefined\n if (!cp) continue\n 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 })\n }\n }\n const report = summarize(samples)\n return styles.charProperties.size === 0 ? { ...report, note: \"글자 모양 정의(header.xml charPr)가 없어 서식을 잴 수 없음\" } : report\n}\n\nconst tally = (values: Array<string | undefined>): Record<string, number> => {\n const out: Record<string, number> = {}\n for (const v of values) if (v !== undefined) out[v] = (out[v] ?? 0) + 1\n return out\n}\n/** 표본 MIN_SAMPLES 이상·점유 MIN_SHARE 이상인 값 */\nconst dominant = (counts: Record<string, number>, total: number): string | undefined => {\n const [value, n] = Object.entries(counts).sort((a, b) => b[1] - a[1])[0] ?? []\n return value !== undefined && total >= MIN_SAMPLES && n! >= total * MIN_SHARE ? value : undefined\n}\n\nfunction summarize(samples: LevelSample[]): LevelStyleReport {\n const box = samples.filter(s => s.scheme === \"box\").length, legal = samples.length - box\n const scheme = samples.length === 0 ? null : box >= legal ? \"box\" : \"legal\"\n const stats: LevelStat[] = []\n const levels: Record<string, GongmunLevelStyle> = {}\n for (const sch of [\"box\", \"legal\"] as const) {\n for (const depth of [...new Set(samples.filter(s => s.scheme === sch).map(s => s.depth))].sort((a, b) => a - b)) {\n const group = samples.filter(s => s.scheme === sch && s.depth === depth)\n const st: LevelStat = {\n scheme: sch, depth, markers: [...new Set(group.map(s => s.marker))], samples: group.length,\n font: tally(group.map(s => s.font)), pt: tally(group.map(s => s.pt?.toString())), bold: tally(group.map(s => String(s.bold))),\n }\n stats.push(st)\n if (sch !== scheme) continue\n const font = dominant(st.font, group.length), pt = dominant(st.pt, group.length), bold = dominant(st.bold, group.length)\n const style: GongmunLevelStyle = { ...(font ? { font } : {}), ...(pt ? { pt: Number(pt) } : {}), ...(bold ? { bold: bold === \"true\" } : {}) }\n if (Object.keys(style).length) levels[depth] = style\n }\n }\n const deviations: LevelDeviation[] = []\n for (const s of samples) {\n const want = s.scheme === scheme ? levels[s.depth] : undefined\n if (!want) continue\n const got: GongmunLevelStyle = { font: s.font, pt: s.pt, bold: s.bold }\n if ((want.font !== undefined && want.font !== s.font) || (want.pt !== undefined && want.pt !== s.pt) || (want.bold !== undefined && want.bold !== s.bold)) {\n deviations.push({ depth: s.depth, text: s.text.slice(0, 40), got, expected: want })\n }\n }\n const spec = Object.entries(levels).map(([d, st]) =>\n `${d}=${[st.font, st.pt, st.bold === undefined ? undefined : st.bold ? \"bold\" : \"plain\"].filter(v => v !== undefined).join(\"/\")}`).join(\",\")\n return { scheme, levels, spec, stats, deviations }\n}\n","/** kordoc CLI 명령 — 렌더 — render·crop·tables·render-worker */\n\nimport { readFileSync, writeFileSync, mkdirSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport { parse } from \"../index.js\"\nimport { VERSION, toArrayBuffer, sanitizeError, KordocError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerRenderCommands(program: Command): void {\n program\n .command(\"render <file>\")\n .description(\"레이아웃 보존 렌더 — HWPX·HWP(5.x)를 SVG(기본, HWPX 는 전체 페이지 세로 스택)·HTML·PNG·JPEG·PDF로. 한컴 저장본은 조판 캐시 그대로, 캐시 없는 생성본·편집본은 순수 TS 조판(reflow, 기본 켬) — kordoc render 문서.hwpx -o 문서.svg / --format png --pages 2-4 -d ./pages / --format pdf -o 문서.pdf\")\n .option(\"-o, --output <path>\", \"출력 경로 (단일 산출: svg 스택·html·pdf·한 쪽 png/jpeg. 기본: <입력>.<확장자>)\")\n .option(\"-d, --out-dir <dir>\", \"페이지별 산출 디렉토리 (svg/png/jpeg 여러 쪽 → page_001.png …)\")\n .option(\"--format <fmt>\", \"svg(기본) | html | png | jpeg | pdf\")\n .option(\"--pages <range>\", \"렌더할 페이지 (1-based: 3 / 1-3 / 1,3,7-9)\")\n .option(\"--max-width <px>\", \"래스터 최대 폭 px (기본 1400)\")\n .option(\"--title <text>\", \"HTML/PDF 문서 제목\")\n .option(\"--browser <path>\", \"PDF 용 Chromium 실행 파일 (기본: PUPPETEER_EXECUTABLE_PATH 또는 자동 탐지)\")\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\n .option(\"--no-reflow\", \"순수 TS 조판 끄기 (조판 캐시 없는 문서가 빈 페이지로 나올 수 있음)\")\n .option(\"--reflow\", \"순수 TS 조판 켜기 — 기본값과 같다 (옛 안내 호환, #97)\")\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep(어절) | charAll(글자)\", \"keep\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n // 루트 --format(markdown 기본) 이 서브커맨드 뒤 --format 을 흡수한다(cli-options 회귀) — 기본값이 아니면 그 값을 쓴다\n const fmt: string = opts.format ?? (rootOpts.format && rootOpts.format !== \"markdown\" ? rootOpts.format : \"svg\")\n const pages: string | undefined = opts.pages ?? rootOpts.pages\n if (![\"svg\", \"html\", \"png\", \"jpeg\", \"pdf\"].includes(fmt)) throw new KordocError(`--format 은 svg|html|png|jpeg|pdf 중 하나: ${fmt}`)\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\n const absPath = resolve(file)\n const stem = file.replace(/\\.hwpx?$/i, \"\")\n if (fmt === \"svg\" && !outDir && !pages && !/\\.hwp$/i.test(absPath)) {\n // 종전 동작(HWPX) — 전체 페이지 세로 스택 SVG 한 파일. HWP5 는 통합 렌더러(페이지별)\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n const buffer = readFileSync(absPath)\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\n const outPath = resolve(output ?? stem + \".svg\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n if (!silent) {\n process.stderr.write(`[kordoc] 렌더 (${result.pageCount}페이지, ${result.width}x${result.height}pt, 텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables}) → ${outPath}\\n`)\n for (const w of result.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n return\n }\n const { renderDocument } = await import(\"../render/index.js\")\n const { scene, assets } = await renderDocument(absPath, {\n format: fmt as \"svg\" | \"html\" | \"png\" | \"jpeg\" | \"pdf\", pages, highlights, reflow: opts.reflow, reflowMode: opts.reflowMode,\n maxWidthPx: opts.maxWidth ? Number(opts.maxWidth) : undefined, title: opts.title, browserExecutablePath: opts.browser,\n })\n const ext = fmt === \"jpeg\" ? \"jpg\" : fmt\n const written: string[] = []\n if (fmt === \"html\" || fmt === \"pdf\" || (assets.length === 1 && !outDir)) {\n const outPath = resolve(output ?? stem + \".\" + ext)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, assets[0].data)\n written.push(outPath)\n } else {\n if (!outDir) throw new KordocError(`페이지 ${assets.length}장 산출은 --out-dir 이 필요합니다 (한 쪽만 내려면 --pages 로 선택)`)\n mkdirSync(resolve(outDir), { recursive: true })\n for (const a of assets) {\n const outPath = resolve(outDir, `page_${String(a.page).padStart(3, \"0\")}.${ext}`)\n writeFileSync(outPath, a.data)\n written.push(outPath)\n }\n }\n if (!silent) {\n process.stderr.write(`[kordoc] 렌더 ${fmt} (${scene.pages.length}페이지 중 ${assets.length}건, 텍스트 ${scene.stats.texts}·이미지 ${scene.stats.images}·표 ${scene.stats.tables}·도형 ${scene.stats.shapes}) → ${written.length === 1 ? written[0] : resolve(outDir!)}\\n`)\n for (const w of scene.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n } catch (err) {\n // exit(1) 을 바로 부르면 파이프 stderr 가 유실된다 — exitCode 로 정상 종료\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"crop <file>\")\n .description(\"렌더 영역 잘라내기 — 표·이미지·문단·도형을 페이지 이미지에서 crop (HWPX·HWP) — kordoc crop 문서.hwpx --target table -d ./regions\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (필수) — <유형>_<번호>_page_<쪽>.png + regions.json\")\n .option(\"--target <types>\", \"유형(쉼표): table | image | paragraph | shape\", \"table\")\n .option(\"--format <fmt>\", \"png(기본) | jpeg\")\n .option(\"--pages <range>\", \"대상 페이지 (1-based)\")\n .option(\"--padding <pt>\", \"bbox 둘레 여백 pt\", \"0\")\n .option(\"--max-width <px>\", \"페이지 래스터 최대 폭 px (crop 해상도, 기본 1400)\")\n .option(\"--no-reflow\", \"순수 TS 조판 끄기\")\n .option(\"--reflow\", \"순수 TS 조판 켜기 — 기본값과 같다 (옛 안내 호환)\")\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep | charAll\", \"keep\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const fmt: string = opts.format ?? (rootOpts.format && rootOpts.format !== \"markdown\" ? rootOpts.format : \"png\")\n const pages: string | undefined = opts.pages ?? rootOpts.pages\n if (![\"png\", \"jpeg\"].includes(fmt)) throw new KordocError(`--format 은 png|jpeg 중 하나: ${fmt}`)\n if (!outDir) throw new KordocError(\"--out-dir 이 필요합니다 (crop 은 파일 여러 개를 냅니다)\")\n const types = String(opts.target).split(\",\").map((t: string) => t.trim()).filter(Boolean)\n for (const t of types) if (![\"table\", \"image\", \"paragraph\", \"shape\"].includes(t)) throw new KordocError(`--target 유형 오류: ${t}`)\n const { extractRenderedRegions } = await import(\"../render/index.js\")\n const regions = await extractRenderedRegions(resolve(file), {\n types: types as Array<\"table\" | \"image\" | \"paragraph\" | \"shape\">, format: fmt as \"png\" | \"jpeg\", pages,\n paddingPt: Number(opts.padding) || 0, maxWidthPx: opts.maxWidth ? Number(opts.maxWidth) : undefined, reflow: opts.reflow, reflowMode: opts.reflowMode,\n })\n const dir = resolve(outDir)\n mkdirSync(dir, { recursive: true })\n const ext = fmt === \"jpeg\" ? \"jpg\" : \"png\"\n const manifest = regions.map(r => {\n const name = `${r.region.id.replace(\"-\", \"_\")}_page_${String(r.page).padStart(3, \"0\")}.${ext}`\n writeFileSync(resolve(dir, name), r.data)\n return { file: name, id: r.region.id, type: r.region.type, sourceId: r.region.sourceId, parentId: r.region.parentId, page: r.page, bbox: r.bbox, widthPx: r.widthPx, heightPx: r.heightPx }\n })\n writeFileSync(resolve(dir, \"regions.json\"), JSON.stringify(manifest, null, 2))\n if (!silent) process.stderr.write(`[kordoc] crop ${regions.length}건 (${types.join(\",\")}) → ${dir}\\n`)\n } catch (err) {\n // exit(1) 을 바로 부르면 파이프 stderr 가 유실된다 — exitCode 로 정상 종료\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"tables <file>\")\n .description(\"표 추출·분류 — 의미표/레이아웃(조직도 등)/불확실 분류 JSON + 선택적 시각 crop (HWPX·HWP) — kordoc tables 문서.hwpx --visual non-tabular-and-uncertain -d ./tables\")\n .option(\"-o, --output <path>\", \"JSON 출력 경로 (기본 stdout; -d 지정 시 <out-dir>/tables.json)\")\n .option(\"-d, --out-dir <dir>\", \"crop 저장 디렉토리 (--visual 지정 시 필수)\")\n .option(\"--visual <policy>\", \"crop 대상: none(기본) | non-tabular | non-tabular-and-uncertain | all\", \"none\")\n .option(\"--crop-format <fmt>\", \"png(기본) | jpeg\", \"png\")\n .option(\"--padding <pt>\", \"crop 여백 pt\", \"0\")\n .option(\"--cells\", \"JSON 에 셀 텍스트 격자 포함\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const outDir: string | undefined = opts.outDir ?? rootOpts.outDir\n const silent: boolean = opts.silent ?? rootOpts.silent\n const policy = String(opts.visual)\n if (![\"none\", \"non-tabular\", \"non-tabular-and-uncertain\", \"all\"].includes(policy)) throw new KordocError(`--visual 은 none|non-tabular|non-tabular-and-uncertain|all: ${policy}`)\n if (policy !== \"none\" && !outDir) throw new KordocError(\"--visual 은 crop 파일을 내므로 --out-dir 이 필요합니다\")\n const cropFmt = String(opts.cropFormat)\n if (![\"png\", \"jpeg\"].includes(cropFmt)) throw new KordocError(`--crop-format 은 png|jpeg: ${cropFmt}`)\n const { extractTables } = await import(\"../table/visual.js\")\n const tables = await extractTables(resolve(file), { policy: policy as \"none\" | \"non-tabular\" | \"non-tabular-and-uncertain\" | \"all\", format: cropFmt as \"png\" | \"jpeg\", paddingPt: Number(opts.padding) || 0 })\n const dir = outDir ? resolve(outDir) : undefined\n if (dir) mkdirSync(dir, { recursive: true })\n const ext = cropFmt === \"jpeg\" ? \"jpg\" : \"png\"\n const report = tables.map(t => {\n const crops = t.crops.map(c => {\n const name = `${t.id.replace(/[^\\w.-]/g, \"_\")}_page_${String(c.page).padStart(3, \"0\")}.${ext}`\n if (dir) writeFileSync(resolve(dir, name), c.data)\n return { file: dir ? name : undefined, page: c.page, bbox: c.bbox }\n })\n return {\n id: t.id, sourceId: t.sourceId, page: t.page, classification: t.classification,\n table: { rows: t.table.rows, cols: t.table.cols, hasHeader: t.table.hasHeader, caption: t.table.caption, ...(opts.cells ? { cells: t.table.cells.map(r => r.map(c => c.text)) } : {}) },\n regions: t.regions, crops, warnings: t.warnings,\n }\n })\n const json = JSON.stringify(report, null, 2)\n const jsonPath = output ? resolve(output) : dir ? resolve(dir, \"tables.json\") : undefined\n if (jsonPath) { mkdirSync(dirname(jsonPath), { recursive: true }); writeFileSync(jsonPath, json + \"\\n\") }\n else process.stdout.write(json + \"\\n\")\n if (!silent) {\n const kinds = report.reduce<Record<string, number>>((m, r) => { m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1; return m }, {})\n process.stderr.write(`[kordoc] 표 ${report.length}개 (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(\", \")}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}건${jsonPath ? ` → ${jsonPath}` : \"\"}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n })\n\n program\n .command(\"render-worker\")\n .description(\"persistent 렌더 워커 — stdin NDJSON 요청 → 조판 SVG 파일 출력 (프로세스 유지, 콜드스타트 제거)\")\n .action(async () => {\n // 프로토콜(NDJSON, 한 줄=한 요청/응답):\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"out\":\"a.svg\",\"reflow\":true,\"highlight\":[\"term\"]}\n // 응답 {\"id\":1,\"ok\":true,\"out\":\"a.svg\",\"width\":..,\"height\":..,\"pageCount\":..,\"stats\":{..},\"warnings\":[..]}\n // {\"cmd\":\"quit\"} 로 종료. 모듈은 최초 1회만 로드 → 이후 요청은 콜드스타트 없음.\n const { createInterface } = await import(\"node:readline\")\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n const rl = createInterface({ input: process.stdin })\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o) + \"\\n\")\n write({ ready: true, version: VERSION })\n for await (const line of rl) {\n const t = line.trim()\n if (!t) continue\n let req: { id?: number; cmd?: string; file?: string; out?: string; reflow?: boolean; reflowMode?: string; highlight?: string[] }\n // 비JSON 라인도 응답은 낸다 — 무음 삼킴이면 id 대기 클라이언트가 영구 행\n try { req = JSON.parse(t) } catch { write({ ok: false, error: \"잘못된 JSON 라인\" }); continue }\n if (req === null || typeof req !== \"object\") { write({ ok: false, error: \"JSON 객체가 아닙니다\" }); continue }\n if (req.cmd === \"quit\") { rl.close(); break }\n const id = req.id\n try {\n if (!req.file || !req.out) throw new Error(\"file·out 필수\")\n const buffer = readFileSync(resolve(req.file))\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), {\n highlights: req.highlight, reflow: req.reflow, reflowMode: req.reflowMode as \"keep\" | \"charAll\" | undefined,\n })\n const outPath = resolve(req.out)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n write({ id, ok: true, out: outPath, width: result.width, height: result.height, pageCount: result.pageCount, stats: result.stats, warnings: result.warnings })\n } catch (err) {\n write({ id, ok: false, error: sanitizeError(err) })\n }\n }\n })\n}\n","/** kordoc CLI 명령 — 서버·설정·모델 — mcp·setup·check-formula-models·check-ocr-models·models */\n\nimport { sanitizeError } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\nexport function registerSystemCommands(program: Command): void {\n program\n .command(\"mcp\")\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\n .action(async () => {\n const { startMcpServer } = await import(\"../mcp.js\")\n await startMcpServer()\n })\n\n program\n .command(\"setup\")\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\n .action(async () => {\n const { runSetup } = await import(\"../setup.js\")\n await runSetup()\n })\n\n program\n .command(\"check-formula-models\")\n .description(\"PDF 수식 OCR 모델(MFD + MFR + tokenizer, ~155MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\n .action(async (opts) => {\n try {\n const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import(\n \"../pdf/formula/index.js\"\n )\n const dir = getFormulaModelsDir()\n if (opts.statusOnly) {\n const status = await getFormulaModelStatus()\n process.stdout.write(\n JSON.stringify(\n {\n modelsDir: dir,\n allReady: status.every((s) => s.verified),\n models: status.map((s) => ({\n name: s.spec.name,\n filename: s.spec.filename,\n sizeMb: s.spec.sizeMb,\n exists: s.exists,\n verified: s.verified,\n invalidReason: s.invalidReason,\n path: s.localPath,\n })),\n },\n null,\n 2,\n ) + \"\\n\",\n )\n return\n }\n process.stderr.write(`[kordoc-formula] 캐시 디렉토리: ${dir}\\n`)\n await ensureFormulaModels((p) => {\n if (p.phase === \"download\" && p.total) {\n const pct = Math.floor((p.downloaded / p.total) * 100)\n process.stderr.write(\n `\\r[kordoc-formula] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\n )\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\n } else if (p.phase === \"verify\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} SHA-256 검증 중...\\n`)\n } else if (p.phase === \"done\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 준비 완료\\n`)\n } else if (p.phase === \"skip\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 이미 존재 (skip)\\n`)\n }\n })\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] 수식 모델 준비 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"check-ocr-models\")\n .description(\"텍스트 OCR 모델(PP-OCRv5 korean det+rec, ~18MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\n .action(async (opts) => {\n try {\n const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import(\"../ocr/models.js\")\n const dir = getOcrModelsDir()\n if (opts.statusOnly) {\n const status = await getOcrModelStatus()\n process.stdout.write(\n JSON.stringify(\n {\n modelsDir: dir,\n allReady: status.every((s) => s.verified),\n models: status.map((s) => ({\n name: s.spec.name,\n filename: s.spec.filename,\n sizeMb: s.spec.sizeMb,\n exists: s.exists,\n verified: s.verified,\n invalidReason: s.invalidReason,\n path: s.localPath,\n })),\n },\n null,\n 2,\n ) + \"\\n\",\n )\n return\n }\n process.stderr.write(`[kordoc-ocr] 캐시 디렉토리: ${dir}\\n`)\n await ensureOcrModels((p) => {\n if (p.phase === \"download\" && p.total) {\n const pct = Math.floor((p.downloaded / p.total) * 100)\n process.stderr.write(\n `\\r[kordoc-ocr] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\n )\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\n } else if (p.phase === \"verify\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} SHA-256 검증 중...\\n`)\n } else if (p.phase === \"done\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 준비 완료\\n`)\n } else if (p.phase === \"skip\") {\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 이미 존재 (skip)\\n`)\n }\n })\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] OCR 모델 준비 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n program\n .command(\"models\")\n .description(\"OCR/수식 모델 오프라인 사이드로드 — 폐쇄망 반입용 내보내기/가져오기 (SHA-256 검증)\")\n .option(\"--status\", \"캐시에 설치된 모델 상태를 JSON 으로 출력\")\n .option(\"--export <dir>\", \"로컬 캐시 → 번들 디렉토리로 내보내기 (온라인 PC에서 실행)\")\n .option(\"--import <dir>\", \"번들 디렉토리 → 로컬 캐시로 설치 (내부망 PC에서 실행)\")\n .action(async (opts) => {\n try {\n const { exportModels, importModels, modelCacheStatus } = await import(\"../shared/model-bundle.js\")\n if (opts.status) {\n process.stdout.write(JSON.stringify(await modelCacheStatus(), null, 2) + \"\\n\")\n return\n }\n const dir = opts.export ?? opts.import\n if (!dir) {\n process.stderr.write(\"[kordoc] --status / --export <dir> / --import <dir> 중 하나가 필요합니다\\n\")\n process.exit(1)\n }\n if (opts.export && opts.import) {\n process.stderr.write(\"[kordoc] --export 와 --import 는 함께 쓸 수 없습니다\\n\")\n process.exit(1)\n }\n const result = opts.export ? await exportModels(dir) : await importModels(dir)\n for (const f of result.files) {\n const mark = f.status === \"copied\" ? \"+\" : f.status === \"invalid\" ? \"!\" : \"-\"\n process.stderr.write(` ${mark} ${f.group}/${f.filename}${f.reason ? ` — ${f.reason}` : \"\"}\\n`)\n }\n const verb = opts.export ? \"내보내기\" : \"설치\"\n const copied = result.files.filter((f) => f.status === \"copied\").length\n process.stderr.write(\n `[kordoc-models] ${verb} ${result.ok ? `완료 (${copied}개)` : \"실패 — 위 ! / - 항목 확인\"}: ${dir}\\n`,\n )\n if (!result.ok) process.exit(1)\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] 모델 사이드로드 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n}\n","/** kordoc CLI 명령: 상주 파싱 워커 (parse-worker) */\n\nimport { readFileSync, statSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { parse } from \"../index.js\"\nimport type { ParseOptions, ParseResult } from \"../types.js\"\nimport { VERSION, toArrayBuffer, sanitizeError, classifyError, routeConsoleToStderr } from \"../utils.js\"\nimport type { Command } from \"commander\"\n\n/** 요청·응답 필드가 바뀌면 올린다. 호스트가 ready 줄로 호환을 판단한다 */\nexport const PARSE_WORKER_PROTOCOL = 1\n\n/** CLI 와 같은 입력 상한 */\nconst MAX_FILE_BYTES = 500 * 1024 * 1024\n\ninterface ParseWorkerRequest {\n id?: number\n cmd?: string\n file?: string\n /** false 면 이미지 바이트를 싣지 않는다 (ParseOptions.images) */\n images?: boolean\n /** \"off\"(기본) | \"auto\"(OCR 필요 페이지만) | \"force\"(전 페이지) */\n ocr?: \"off\" | \"auto\" | \"force\"\n formulaOcr?: boolean\n password?: string | null\n}\n\n/** 이미지 바이트는 --format json 과 같게 base64 로 */\nconst bytesToBase64 = (_key: string, value: unknown): unknown =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n\nasync function parseOne(req: ParseWorkerRequest & { file: string }): Promise<ParseResult> {\n const absPath = resolve(req.file)\n try {\n const size = statSync(absPath).size\n if (size > MAX_FILE_BYTES) {\n return { success: false, fileType: \"unknown\", error: `파일이 너무 큽니다 (${(size / 1024 / 1024).toFixed(1)}MB)`, code: \"PARSE_ERROR\" }\n }\n const options: ParseOptions = { filePath: absPath }\n if (req.images === false) options.images = false\n if (req.ocr === \"force\") options.ocr = \"force\"\n else if (req.ocr === \"auto\") options.ocr = true\n if (req.formulaOcr) options.formulaOcr = true\n if (req.password) options.password = req.password\n return await parse(toArrayBuffer(readFileSync(absPath)), options)\n } catch (err) {\n return { success: false, fileType: \"unknown\", error: sanitizeError(err), code: classifyError(err) }\n }\n}\n\nexport function registerWorkerCommands(program: Command): void {\n program\n .command(\"parse-worker\")\n .description(\"상주 파싱 워커: stdin NDJSON 요청 → 한 줄 JSON 응답 (프로세스 유지, 파일마다 node 를 새로 띄우는 비용 제거)\")\n .action(async () => {\n // 프로토콜(NDJSON, 한 줄 = 한 메시지):\n // 시작 {\"ready\":true,\"version\":\"4.14.3\",\"protocol\":1}\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"images\":false,\"ocr\":\"off\",\"formulaOcr\":false,\"password\":null}\n // 응답 {\"id\":1,\"rss\":123456789,\"result\":{…}}: result 는 --format json 과 같은 ParseResult (실패도 success:false 로)\n // {\"id\":1,\"error\":\"…\"}: 요청 자체가 잘못됐을 때\n // {\"cmd\":\"quit\"} 또는 stdin 닫힘으로 종료. rss 는 호스트가 워커 교체 시점을 정하는 데 쓴다.\n // pdfjs 등이 console 로 찍는 경고가 stdout 프로토콜 줄을 깨지 않게 stderr 로 돌린다\n routeConsoleToStderr()\n const { createInterface } = await import(\"node:readline\")\n const rl = createInterface({ input: process.stdin, crlfDelay: Infinity })\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o, bytesToBase64) + \"\\n\")\n write({ ready: true, version: VERSION, protocol: PARSE_WORKER_PROTOCOL })\n for await (const line of rl) {\n const t = line.trim()\n if (!t) continue\n let req: ParseWorkerRequest\n // 비JSON 라인도 응답은 낸다. 무음 삼킴이면 id 를 기다리는 호스트가 영구 대기\n try { req = JSON.parse(t) } catch { write({ error: \"잘못된 JSON 라인\" }); continue }\n if (req === null || typeof req !== \"object\") { write({ error: \"JSON 객체가 아닙니다\" }); continue }\n if (req.cmd === \"quit\") break\n const id = req.id\n if (typeof req.file !== \"string\" || !req.file) { write({ id, error: \"file 필수\" }); continue }\n const result = await parseOne({ ...req, file: req.file })\n try {\n write({ id, rss: process.memoryUsage.rss(), result })\n } catch (err) {\n // 직렬화 한계(이미지 수백 장 base64 등, #65)는 실패 JSON 계약으로\n write({ id, rss: process.memoryUsage.rss(), result: { success: false, fileType: result.fileType, error: sanitizeError(err), code: classifyError(err) } })\n }\n }\n rl.close()\n // 파이프 stdout 은 맥·윈도에서 비동기라 바로 exit 하면 마지막 응답이 잘린다. 다 비운 뒤 끝낸다.\n // pdfjs 등이 남긴 핸들이 있어도 워커는 끝낸다 (호스트가 죽어 stdin 이 닫힌 경우의 고아 방지)\n await new Promise<void>((done) => process.stdout.write(\"\", () => done()))\n process.exit(0)\n })\n}\n"],"mappings":"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","names":["statSync","basename","resolve","resolve","basename","statSync","output","basename","program","basename","resolve","readFileSync","writeFileSync","mkdirSync","statSync","basename","resolve","program","resolve","statSync","readFileSync","basename","result","formInfo","mkdirSync","writeFileSync","detectFormat","readFileSync","writeFileSync","mkdirSync","statSync","basename","dirname","resolve","text","program","readFileSync","resolve","basename","mkdirSync","dirname","writeFileSync","parse","statSync","readFileSync","writeFileSync","mkdirSync","dirname","resolve","program","resolve","readFileSync","mkdirSync","dirname","writeFileSync","program","readFileSync","statSync","resolve","resolve","statSync","readFileSync","program"]}