kordoc 4.2.9 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +922 -885
- package/dist/{-ECUCTQTR.js → -DYHT3HWH.js} +28 -20
- package/dist/{chunk-J2RZ444H.js → chunk-3FFPHTXD.js} +1 -1
- package/dist/chunk-3FFPHTXD.js.map +1 -0
- package/dist/{chunk-27Z4PUZZ.js → chunk-4DBCUF3C.js} +38 -7
- package/dist/chunk-4DBCUF3C.js.map +1 -0
- package/dist/{chunk-5RPYBC2Q.js → chunk-6GBLFQMA.js} +1 -1
- package/dist/chunk-6GBLFQMA.js.map +1 -0
- package/dist/{chunk-VEHC4EJL.js → chunk-6RAYTNQT.js} +5 -5
- package/dist/chunk-6RAYTNQT.js.map +1 -0
- package/dist/{chunk-GEPINOL6.js → chunk-6XPXIG57.js} +2 -2
- package/dist/chunk-6XPXIG57.js.map +1 -0
- package/dist/{chunk-7ZARSBQ3.js → chunk-7MFO4TKP.js} +4 -3
- package/dist/chunk-7MFO4TKP.js.map +1 -0
- package/dist/{chunk-PATPZTH7.cjs → chunk-AL34DGS5.cjs} +6 -6
- package/dist/chunk-AL34DGS5.cjs.map +1 -0
- package/dist/{chunk-LXE7OR6N.js → chunk-ARXNKC5D.js} +3 -3
- package/dist/chunk-ARXNKC5D.js.map +1 -0
- package/dist/{chunk-6GM2QLM3.cjs → chunk-AUOEZKJE.cjs} +21 -21
- package/dist/chunk-AUOEZKJE.cjs.map +1 -0
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-3TSTZGCJ.js → chunk-DRQUAYNT.js} +4 -3
- package/dist/chunk-DRQUAYNT.js.map +1 -0
- package/dist/{chunk-G3DMDTZI.js → chunk-DRZUJ2RK.js} +1511 -1135
- package/dist/chunk-DRZUJ2RK.js.map +1 -0
- package/dist/{chunk-NIISBGSR.js → chunk-EFVAY5VE.js} +71 -29
- package/dist/chunk-EFVAY5VE.js.map +1 -0
- package/dist/{chunk-3PLF5UIS.js → chunk-EZHW3RNQ.js} +37 -6
- package/dist/chunk-EZHW3RNQ.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-MHMVFI2N.js → chunk-GSMPTZC7.js} +4 -4
- package/dist/chunk-GSMPTZC7.js.map +1 -0
- package/dist/{chunk-GZ7W64QU.cjs → chunk-JFV7QT5T.cjs} +4 -3
- package/dist/chunk-JFV7QT5T.cjs.map +1 -0
- package/dist/{chunk-4ZWKFDUC.cjs → chunk-LPQWKQQQ.cjs} +44 -13
- package/dist/chunk-LPQWKQQQ.cjs.map +1 -0
- package/dist/{chunk-H7OWEYH2.cjs → chunk-MGGU3ZRK.cjs} +1 -1
- package/dist/chunk-MGGU3ZRK.cjs.map +1 -0
- package/dist/chunk-MOL7MDBG.js +0 -0
- package/dist/{chunk-XU4VWOKL.js → chunk-NMWXBJ5B.js} +4 -3
- package/dist/chunk-NMWXBJ5B.js.map +1 -0
- package/dist/{chunk-DZIXKL7E.js → chunk-O5EK52TG.js} +1 -1
- package/dist/chunk-O5EK52TG.js.map +1 -0
- package/dist/{chunk-KTPZYXN2.js → chunk-SPKBIFSK.js} +2 -2
- package/dist/chunk-SPKBIFSK.js.map +1 -0
- package/dist/{chunk-STYN45MS.js → chunk-US4WFSIQ.js} +4 -4
- package/dist/chunk-US4WFSIQ.js.map +1 -0
- package/dist/{chunk-WTT2KJOM.js → chunk-VXMLENCV.js} +14 -10
- package/dist/chunk-VXMLENCV.js.map +1 -0
- package/dist/{chunk-7FCNOKOR.js → chunk-W34QSJFF.js} +1 -1
- package/dist/chunk-W34QSJFF.js.map +1 -0
- package/dist/{chunk-YR4PF56B.js → chunk-WFOQFJI4.js} +2 -2
- package/dist/chunk-WFOQFJI4.js.map +1 -0
- package/dist/{chunk-NNDVFNMJ.js → chunk-YNJDNP44.js} +1 -1
- package/dist/chunk-YNJDNP44.js.map +1 -0
- package/dist/{chunk-LM7C6HI2.js → chunk-ZSL6MQVE.js} +1 -1
- package/dist/chunk-ZSL6MQVE.js.map +1 -0
- package/dist/chunks-Q7T4SQGW.js +10 -0
- package/dist/cli.js +75 -39
- package/dist/cli.js.map +1 -1
- package/dist/{formula-SXC6LRRC.js → formula-7ZPC54JO.js} +2 -2
- package/dist/formula-7ZPC54JO.js.map +1 -0
- package/dist/{formula-KSNAEBZ2.js → formula-EQRHSMYW.js} +2 -2
- package/dist/formula-EQRHSMYW.js.map +1 -0
- package/dist/{formula-SB3NHDUM.cjs → formula-IWV5IJ3Y.cjs} +8 -8
- package/dist/formula-IWV5IJ3Y.cjs.map +1 -0
- package/dist/{image-ocr-PS7XCV6K.js → image-ocr-G2LYTEUH.js} +8 -6
- package/dist/image-ocr-G2LYTEUH.js.map +1 -0
- package/dist/{image-ocr-KZTNJ62U.js → image-ocr-R44RYDBU.js} +10 -8
- package/dist/image-ocr-R44RYDBU.js.map +1 -0
- package/dist/{image-ocr-J5656BEE.cjs → image-ocr-XEJFXH6M.cjs} +13 -11
- package/dist/image-ocr-XEJFXH6M.cjs.map +1 -0
- package/dist/index.cjs +1993 -1845
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -4
- package/dist/index.d.ts +75 -4
- package/dist/index.js +2128 -1980
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +123 -78
- package/dist/mcp.js.map +1 -1
- package/dist/{models-KA4GLQK5.js → models-6VMAVZR6.js} +3 -3
- package/dist/page-range-737B4EZW.js +0 -0
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-A34NAYKA.js → parser-2G245MMN.js} +6 -6
- package/dist/parser-2G245MMN.js.map +1 -0
- package/dist/{parser-WNFWMBSL.js → parser-W3POOYQQ.js} +8 -8
- package/dist/parser-W3POOYQQ.js.map +1 -0
- package/dist/{parser-CSYU3CAW.cjs → parser-W3ZGQUCQ.cjs} +25 -25
- package/dist/parser-W3ZGQUCQ.cjs.map +1 -0
- package/dist/pdf-ocr-3GDTJSHF.js +15 -0
- package/dist/pdf-ocr-N7IU23UV.cjs +13 -0
- package/dist/pdf-ocr-N7IU23UV.cjs.map +1 -0
- package/dist/pdf-ocr-U7MEGNBZ.js +12 -0
- package/dist/{profile-io-43MF52H6.js → profile-io-72R3B7KO.js} +3 -3
- package/dist/{rasterize-OG7KXBJS.js → rasterize-GNJQVURE.js} +2 -2
- package/dist/rasterize-GNJQVURE.js.map +1 -0
- package/dist/{redact-7ILEAUTS.js → redact-W5K3ILQH.js} +2 -2
- package/dist/render-6OW6U4L4.js +10 -0
- package/dist/seal-GTNLVBJX.js +10 -0
- package/dist/{setup-GUQT5ELJ.js → setup-I4I75QJU.js} +1 -1
- package/dist/setup-I4I75QJU.js.map +1 -0
- package/dist/{watch-SOHQMZN2.js → watch-2ADAJLIJ.js} +12 -14
- package/dist/watch-2ADAJLIJ.js.map +1 -0
- package/package.json +101 -98
- package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
- package/templates//352/260/204/354/235/264/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +9 -0
- package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/204/234/354/213/235.hwpx +0 -0
- package/templates//354/235/274/353/260/230/352/270/260/354/225/210/353/254/270_/354/230/210/354/213/234/352/260/222.json +25 -0
- package/dist/chunk-27Z4PUZZ.js.map +0 -1
- package/dist/chunk-3PLF5UIS.js.map +0 -1
- package/dist/chunk-3TSTZGCJ.js.map +0 -1
- package/dist/chunk-4ZWKFDUC.cjs.map +0 -1
- package/dist/chunk-5RPYBC2Q.js.map +0 -1
- package/dist/chunk-6GM2QLM3.cjs.map +0 -1
- package/dist/chunk-7FCNOKOR.js.map +0 -1
- package/dist/chunk-7ZARSBQ3.js.map +0 -1
- package/dist/chunk-DZIXKL7E.js.map +0 -1
- package/dist/chunk-G3DMDTZI.js.map +0 -1
- package/dist/chunk-GEPINOL6.js.map +0 -1
- package/dist/chunk-GZ7W64QU.cjs.map +0 -1
- package/dist/chunk-H7OWEYH2.cjs.map +0 -1
- package/dist/chunk-J2RZ444H.js.map +0 -1
- package/dist/chunk-KTPZYXN2.js.map +0 -1
- package/dist/chunk-LM7C6HI2.js.map +0 -1
- package/dist/chunk-LXE7OR6N.js.map +0 -1
- package/dist/chunk-MHMVFI2N.js.map +0 -1
- package/dist/chunk-NIISBGSR.js.map +0 -1
- package/dist/chunk-NNDVFNMJ.js.map +0 -1
- package/dist/chunk-PATPZTH7.cjs.map +0 -1
- package/dist/chunk-STYN45MS.js.map +0 -1
- package/dist/chunk-TCJRGFYY.js +0 -280
- package/dist/chunk-TCJRGFYY.js.map +0 -1
- package/dist/chunk-VEHC4EJL.js.map +0 -1
- package/dist/chunk-WTT2KJOM.js.map +0 -1
- package/dist/chunk-XU4VWOKL.js.map +0 -1
- package/dist/chunk-YR4PF56B.js.map +0 -1
- package/dist/chunks-VFIMYK36.js +0 -10
- package/dist/detect-FX2ZHKZP.js +0 -26
- package/dist/formula-KSNAEBZ2.js.map +0 -1
- package/dist/formula-SB3NHDUM.cjs.map +0 -1
- package/dist/formula-SXC6LRRC.js.map +0 -1
- package/dist/image-ocr-J5656BEE.cjs.map +0 -1
- package/dist/image-ocr-KZTNJ62U.js.map +0 -1
- package/dist/image-ocr-PS7XCV6K.js.map +0 -1
- package/dist/parser-A34NAYKA.js.map +0 -1
- package/dist/parser-CSYU3CAW.cjs.map +0 -1
- package/dist/parser-WNFWMBSL.js.map +0 -1
- package/dist/pdf-ocr-KBMWPG2L.js +0 -12
- package/dist/pdf-ocr-NPZG67FN.js +0 -15
- package/dist/pdf-ocr-O44DAGTY.cjs +0 -13
- package/dist/pdf-ocr-O44DAGTY.cjs.map +0 -1
- package/dist/rasterize-OG7KXBJS.js.map +0 -1
- package/dist/render-336CJHAS.js +0 -10
- package/dist/seal-TM2XCE2R.js +0 -10
- package/dist/seal-TM2XCE2R.js.map +0 -1
- package/dist/setup-GUQT5ELJ.js.map +0 -1
- package/dist/watch-SOHQMZN2.js.map +0 -1
- /package/dist/{-ECUCTQTR.js.map → -DYHT3HWH.js.map} +0 -0
- /package/dist/{chunks-VFIMYK36.js.map → chunks-Q7T4SQGW.js.map} +0 -0
- /package/dist/{detect-FX2ZHKZP.js.map → models-6VMAVZR6.js.map} +0 -0
- /package/dist/{models-KA4GLQK5.js.map → pdf-ocr-3GDTJSHF.js.map} +0 -0
- /package/dist/{pdf-ocr-KBMWPG2L.js.map → pdf-ocr-U7MEGNBZ.js.map} +0 -0
- /package/dist/{pdf-ocr-NPZG67FN.js.map → profile-io-72R3B7KO.js.map} +0 -0
- /package/dist/{profile-io-43MF52H6.js.map → redact-W5K3ILQH.js.map} +0 -0
- /package/dist/{redact-7ILEAUTS.js.map → render-6OW6U4L4.js.map} +0 -0
- /package/dist/{render-336CJHAS.js.map → seal-GTNLVBJX.js.map} +0 -0
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\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, hwpxToProfile, PRESET_ALIAS, unknownFontWarnings, incompatibleGongmunWarnings, lintGongmunText, gongmunLintWarnings } from \"./index.js\"\nimport type { FillInput } from \"./index.js\"\nimport { parseFormatProfileJson } from \"./hwpx/profile-io.js\"\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS } from \"./hwpx/gongmun-surface.js\"\nimport type { ParseOptions } from \"./types.js\"\nimport type { FormatProfile } from \"./hwpx/gen-profile.js\"\nimport { VERSION, toArrayBuffer, sanitizeError } from \"./utils.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(\"-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(\"--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(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\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 // -o는 단일 파일 전용 — 다중 파일에서 무음 무시되지 않게 경고\n if (opts.output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\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\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 process.exitCode = 1\n continue\n }\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n const format = detectFormat(arrayBuffer)\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.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.inlineImages) parseOptions.inlineImages = true\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\n if (!result.success) {\n process.stderr.write(` FAIL\\n`)\n process.stderr.write(` → ${result.error}\\n`)\n process.exitCode = 1\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 시 이미지 참조 경로에 images/ 접두사 추가 (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀)\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\n if (opts.outDir && result.images?.length && !imagesInlined) {\n markdown = markdown\n .replace(/!\\[image\\]\\(image_/g, \"\n .replace(/(<img\\b[^>]*\\bsrc=\")image_/g, \"$1images/image_\")\n }\n let output: string\n if (opts.format === \"json\") {\n output = JSON.stringify(result, (_key, value) =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n , 2)\n } else if (opts.format === \"chunks\") {\n const { blocksToChunks } = await import(\"./chunks.js\")\n output = JSON.stringify(blocksToChunks(result.blocks), 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\")\n mkdirSync(imgDir, { recursive: true })\n for (const img of result.images) {\n writeFileSync(resolve(imgDir, img.filename), img.data)\n }\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir}\\n`)\n }\n\n if (opts.output && files.length === 1) {\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 const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, outExt))\n writeFileSync(outPath, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\n saveImages(opts.outDir)\n } else {\n process.stdout.write(output + \"\\n\")\n }\n } catch (err) {\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n }\n })\n\nprogram\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\nprogram\n .command(\"fill <template>\")\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx\")\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(\"--require-unique\", \"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 (반복 라벨 양식 오염 방지)\")\n .option(\"--mask\", \"채운 값 미노출 — 출력 파일 없이 markdown을 stdout으로 낼 때 본문 대신 안내만 표시\")\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (template: string, 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 const absPath = resolve(template)\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\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n\n if (!opts.silent) process.stderr.write(`[kordoc] ${basename(absPath)} 파싱 중...\\n`)\n\n // --dry-run: 필드 목록만 출력 — 서식 입력란(빈 후행 열)이 목록에 나오도록 보존 (#47)\n if (opts.dryRun) {\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true })\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n const formInfo = extractFormFields(result.blocks)\n if (formInfo.fields.length === 0) {\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\n process.exit(1)\n }\n process.stdout.write(JSON.stringify(formInfo, null, 2) + \"\\n\")\n return\n }\n\n // 필드 값 파싱\n let values: Record<string, string> = {}\n if (opts.json) {\n const jsonPath = resolve(opts.json)\n const jsonContent = readFileSync(jsonPath, \"utf-8\")\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 })\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\nprogram\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\nprogram\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\nprogram\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\nprogram\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 — 표지·목차·장헤더 자동)·보도자료(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(\"--h2-marker <type>\", \"h2 섹션 제목 말머리: box(□ — 보고서·계획서 기본)·number(1. — 공고문 관행)·none\")\n .option(\"--fonts <spec>\", \"요소별 글꼴 오버라이드: body=나눔명조,heading=나눔고딕,ref=한양중고딕,table=맑은 고딕\")\n .option(\"--sizes <spec>\", \"개조식 요소별 크기(pt): dae=16,cham=13,table=12,coverTitle=30 …\")\n .option(\"--bullet2 <char>\", \"2단계 항목부호: ㅇ(이응 — 기안문·공고문 실측 지배) 또는 ○(원 — 보고서 양식)\")\n .option(\"--suppress-single\", \"단일 형제 항목 부호 생략 (편람 규정 — 기본은 하나여도 부호 부여)\")\n .option(\"--doc-head <spec>\", \"기안문 두문: org=행정안전부,to=수신처,title=제목 (별지 제1호서식)\")\n .option(\"--doc-foot <spec>\", \"기안문 결문: sender=장관명의,drafter=기안자,reviewer=검토자,approver=결재권자,docNum=시행번호,phone=전화,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(\"--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\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 (!opts.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 h2Marker: enumCheck(\"--h2-marker\", opts.h2Marker, H2_MARKERS),\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 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 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 // 프리셋 비호환 옵션 경고 (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 // 서식 프로필 (이슈 #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 const buf = await markdownToHwpx(md, gongmun || profile ? { ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}) } : undefined)\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\nprogram\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\nprogram\n .command(\"lint <file>\")\n .description(\"공문서 표기법 검수 — 날짜·시간·금액·붙임 등 행정업무운영 편람 표기법 (md/txt, '-'=stdin). error 있으면 exit 1\")\n .option(\"--json\", \"JSON 출력\")\n .action((file: string, opts) => {\n try {\n const text = file === \"-\" ? readFileSync(0, \"utf-8\") : readFileSync(resolve(file), \"utf-8\")\n const findings = lintGongmunText(text)\n const errors = findings.filter((f) => f.severity === \"error\").length\n if (opts.json) {\n process.stdout.write(JSON.stringify({ findings, summary: { total: findings.length, errors, ok: errors === 0 } }, null, 2) + \"\\n\")\n } else {\n // 사람용 리포트는 stderr — 기계용(--json)만 stdout (validate와 채널 일관)\n process.stderr.write(`[kordoc] 표기법 검수: 위반 ${findings.length}건 (error ${errors}, warning ${findings.length - errors})\\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 }\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\nprogram\n .command(\"redact <files...>\")\n .description(\"개인정보 서식 보존 마스킹 — 주민번호·전화·이메일·카드·계좌를 탐지해 HWPX/HWP는 원본 서식 그대로 patch, 그 외 포맷은 마스킹된 마크다운 출력. 자동 검출 보조 도구이므로 결과는 반드시 사람이 최종 확인하세요 (이미지 안 텍스트는 탐지 불가)\")\n .option(\"--rules <csv>\", \"적용 룰 (기본: rrn,phone,email,card,account — passport,driver는 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 { redactMarkdown, DEFAULT_REDACT_RULES, patchHwpx, patchHwp } = 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 KNOWN_RULES = new Set([\"rrn\", \"phone\", \"email\", \"card\", \"account\", \"passport\", \"driver\"])\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 if (output && files.length > 1) {\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\n }\n const jsonReports: unknown[] = []\n for (const filePath of files) {\n const absPath = resolve(filePath)\n const fileName = basename(absPath)\n try {\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n const format = detectFormat(arrayBuffer)\n const parsed = await parse(arrayBuffer, { filePath: absPath })\n if (!parsed.success) {\n process.stderr.write(`[kordoc] FAIL: ${fileName} — ${parsed.error}\\n`)\n process.exitCode = 1\n continue\n }\n const r = redactMarkdown(parsed.markdown, { rules: rules as never, maskChar: opts.maskChar })\n const byRule = new Map<string, number>()\n for (const h of r.hits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\n const ruleSummary = [...byRule.entries()].map(([k, v]) => `${k} ${v}건`).join(\", \") || \"0건\"\n\n let outPath: string | null = null\n let patchNote = \"\"\n if (!opts.dryRun && r.hits.length > 0) {\n const patchable = format === \"hwpx\" || format === \"hwp\"\n if (patchable) {\n const original = new Uint8Array(arrayBuffer)\n const result = format === \"hwp\"\n ? await patchHwp(original, r.text)\n : await patchHwpx(original, r.text)\n if (!result.success || !result.data) {\n process.stderr.write(`[kordoc] 패치 실패: ${fileName} — ${result.error ?? \"알 수 없는 오류\"}\\n`)\n process.exitCode = 1\n continue\n }\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\n outPath = resolve(\n output && files.length === 1\n ? output\n : resolve(opts.outDir ?? dirname(absPath), fileName.replace(/\\.[^.]+$/, \"\") + \".redacted\" + ext),\n )\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.data)\n if (result.skipped.length > 0) {\n patchNote = ` (⚠️ 미적용 ${result.skipped.length}건 — 해당 위치는 원문 잔존, 수동 확인 필요)`\n process.exitCode = 2\n }\n } else {\n outPath = resolve(\n output && files.length === 1\n ? output\n : resolve(opts.outDir ?? dirname(absPath), fileName.replace(/\\.[^.]+$/, \"\") + \".redacted.md\"),\n )\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, r.text, \"utf-8\")\n patchNote = ` (${format}는 서식 보존 미지원 — 마스킹된 마크다운으로 출력)`\n }\n }\n if (opts.json) {\n jsonReports.push({ file: absPath, format, rules, hits: r.hits, output: outPath })\n }\n if (!silent) {\n process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` → ${outPath}` : opts.dryRun ? \" (dry-run)\" : \"\"}${patchNote}\\n`)\n for (const h of r.hits) process.stderr.write(` - [${h.rule}] ${h.masked}\\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\nprogram\n .command(\"render <file>\")\n .description(\"레이아웃 보존 렌더 — 한컴 저장 HWPX의 조판 캐시를 SVG로 (전체 페이지 세로 스택) — kordoc render 문서.hwpx -o 문서.svg\")\n .option(\"-o, --output <path>\", \"출력 SVG 경로 (기본: <입력>.svg)\")\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\n .option(\"--reflow\", \"조판 캐시 없는 HWPX도 순수 TS 조판으로 렌더 (markdownToHwpx 산출물·편집본)\")\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 silent: boolean = opts.silent ?? rootOpts.silent\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\n const absPath = resolve(file)\n const buffer = readFileSync(absPath)\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".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 } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\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\nprogram\n .command(\"mcp\")\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\n .action(async () => {\n const { startMcpServer } = await import(\"./mcp.js\")\n await startMcpServer()\n })\n\nprogram\n .command(\"setup\")\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\n .action(async () => {\n const { runSetup } = await import(\"./setup.js\")\n await runSetup()\n })\n\nprogram\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\nprogram\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\nprogram.parse()\n"],"mappings":"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","names":["result","formInfo","detectFormat"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\r\n\r\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\r\nimport { basename, dirname, resolve, extname } from \"path\"\r\nimport { Command } from \"commander\"\r\nimport { parse, detectFormat, detectZipFormat, fillFormFields, extractFormFields, blocksToMarkdown, markdownToHwpx, fillHwpx, fillWithUniqueGuard, hwpxToProfile, PRESET_ALIAS, unknownFontWarnings, incompatibleGongmunWarnings, lintGongmunText, gongmunLintWarnings, extractClickHereFields, BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate } from \"./index.js\"\r\nimport type { FillInput } from \"./index.js\"\r\nimport { parseFormatProfileJson } from \"./hwpx/profile-io.js\"\r\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS } from \"./hwpx/gongmun-surface.js\"\r\nimport type { ParseOptions } from \"./types.js\"\r\nimport type { FormatProfile } from \"./hwpx/gen-profile.js\"\r\nimport { VERSION, toArrayBuffer, sanitizeError } from \"./utils.js\"\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name(\"kordoc\")\r\n .description(\"모두 파싱해버리겠다 — HWP, HWPX, PDF, XLSX, DOCX, 이미지(PNG/JPG/WebP) → Markdown\")\r\n .version(VERSION)\r\n .argument(\"<files...>\", \"변환할 파일 경로 (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP — 이미지는 OCR 자동 적용)\")\r\n .option(\"-o, --output <path>\", \"출력 파일 경로 (단일 파일 시)\")\r\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\r\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위 (예: 1-3, 1,3,5)\")\r\n .option(\"--format <type>\", \"출력 형식: markdown (기본), json, chunks (RAG용 구조 청크 JSON — 헤딩·개조식 위계 breadcrumb + 표 독립 청크)\", \"markdown\")\r\n .option(\"--no-header-footer\", \"PDF 머리글/바닥글 자동 제거 끄기 (기본: 제거함)\")\r\n .option(\"--formula-ocr\", \"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드)\")\r\n .option(\"--ocr\", \"스캔/이미지 PDF 텍스트 OCR (내장 PP-OCRv5 korean, 첫 사용 시 모델 ~18MB 자동 다운로드 — OCR 필요 페이지만 인식)\")\r\n .option(\"--ocr-force\", \"전 페이지 강제 OCR (텍스트층이 있어도 무시하고 재인식)\")\r\n .option(\"--dedupe-headers\", \"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의)\")\r\n .option(\"--keep-empty-cols\", \"표 오른쪽 끝 빈 열(서식 입력란) 보존 (#47, 기본 off: 후행 빈 열 트림)\")\r\n .option(\"--keep-empty-paragraphs\", \"빈 문단 보존 — 본문은 빈 paragraph 블록, 표 셀은 빈 줄로 (#57, 기본 off: 빈 문단 제거)\")\r\n .option(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (files: string[], opts) => {\r\n const validFormats = [\"markdown\", \"json\", \"chunks\"]\r\n if (!validFormats.includes(opts.format)) {\r\n process.stderr.write(`[kordoc] 지원하지 않는 형식: ${opts.format} (markdown, json, chunks)\\n`)\r\n process.exit(1)\r\n }\r\n // -o는 단일 파일 전용 — 다중 파일에서 무음 무시되지 않게 경고\r\n if (opts.output && files.length > 1) {\r\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\r\n }\r\n for (let fi = 0; fi < files.length; fi++) {\r\n const filePath = files[fi]\r\n const absPath = resolve(filePath)\r\n const fileName = basename(absPath)\r\n const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : \"\"\r\n\r\n try {\r\n const fileSize = statSync(absPath).size\r\n if (fileSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`\\n[kordoc] SKIP: ${fileName} — 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n const buffer = readFileSync(absPath)\r\n const arrayBuffer = toArrayBuffer(buffer)\r\n const format = detectFormat(arrayBuffer)\r\n\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`)\r\n }\r\n\r\n const parseOptions: ParseOptions = { filePath: absPath }\r\n if (opts.pages) parseOptions.pages = opts.pages as string\r\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\r\n if (opts.formulaOcr) parseOptions.formulaOcr = true\r\n if (opts.ocrForce) parseOptions.ocr = \"force\"\r\n else if (opts.ocr) parseOptions.ocr = true\r\n if (opts.dedupeHeaders) parseOptions.dedupeRunningHeaders = true\r\n if (opts.keepEmptyCols) parseOptions.keepTrailingEmptyCols = true\r\n if (opts.keepEmptyParagraphs) parseOptions.keepEmptyParagraphs = true\r\n if (opts.inlineImages) parseOptions.inlineImages = true\r\n if (!opts.silent) {\r\n parseOptions.onProgress = (current: number, total: number) => {\r\n process.stderr.write(`\\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`)\r\n }\r\n }\r\n const result = await parse(arrayBuffer, parseOptions)\r\n\r\n if (!result.success) {\r\n process.stderr.write(` FAIL\\n`)\r\n process.stderr.write(` → ${result.error}\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n\r\n if (!opts.silent) process.stderr.write(` OK\\n`)\r\n\r\n let markdown = result.markdown\r\n // 이미지 인라인은 HWP5 경로에서만 실제로 일어난다(parser.ts). 그 외 포맷(HWPX/DOCX 등)은\r\n // --inline-images 를 줘도 인라인되지 않으므로, 이미지 저장/경로접두사를 생략하면 참조가\r\n // 깨지고(dangling) 바이트가 유실된다 → 실제 인라인된 경우에만 생략한다.\r\n const imagesInlined = opts.inlineImages && result.fileType === \"hwp\"\r\n // --out-dir 시 이미지 참조 경로에 images/ 접두사 추가 (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀)\r\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\r\n if (opts.outDir && result.images?.length && !imagesInlined) {\r\n markdown = markdown\r\n .replace(/!\\[image\\]\\(image_/g, \"\r\n .replace(/(<img\\b[^>]*\\bsrc=\")image_/g, \"$1images/image_\")\r\n }\r\n let output: string\r\n if (opts.format === \"json\") {\r\n output = JSON.stringify(result, (_key, value) =>\r\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\r\n , 2)\r\n } else if (opts.format === \"chunks\") {\r\n const { blocksToChunks } = await import(\"./chunks.js\")\r\n output = JSON.stringify(blocksToChunks(result.blocks), null, 2)\r\n } else {\r\n output = markdown\r\n }\r\n\r\n // 이미지 저장 (--out-dir 또는 --output 시) — 실제 인라인된 경우(HWP5)에만 미저장, 그 외엔 저장 유지\r\n const saveImages = (dir: string) => {\r\n if (!result.images?.length || imagesInlined) return\r\n const imgDir = resolve(dir, \"images\")\r\n mkdirSync(imgDir, { recursive: true })\r\n for (const img of result.images) {\r\n writeFileSync(resolve(imgDir, img.filename), img.data)\r\n }\r\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir}\\n`)\r\n }\r\n\r\n if (opts.output && files.length === 1) {\r\n writeFileSync(opts.output, output, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(` → ${opts.output}\\n`)\r\n saveImages(resolve(opts.output, \"..\"))\r\n } else if (opts.outDir) {\r\n mkdirSync(opts.outDir, { recursive: true })\r\n const outExt = opts.format === \"json\" ? \".json\" : opts.format === \"chunks\" ? \".chunks.json\" : \".md\"\r\n const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, outExt))\r\n writeFileSync(outPath, output, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\r\n saveImages(opts.outDir)\r\n } else {\r\n process.stdout.write(output + \"\\n\")\r\n }\r\n } catch (err) {\r\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\r\n process.exitCode = 1\r\n }\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"watch <dir>\")\r\n .description(\"디렉토리 감시 — 새 문서 자동 변환\")\r\n .option(\"--webhook <url>\", \"결과 전송 웹훅 URL\")\r\n .option(\"-d, --out-dir <dir>\", \"변환 결과 출력 디렉토리\")\r\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위\")\r\n .option(\"--format <type>\", \"출력 형식: markdown 또는 json\", \"markdown\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (dir: string, opts, command: Command) => {\r\n // 루트 커맨드의 동명 옵션(-d/--out-dir·-p/--pages·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n opts.outDir ??= rootOpts.outDir\r\n opts.pages ??= rootOpts.pages\r\n opts.silent ??= rootOpts.silent\r\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\r\n opts.format = rootOpts.format\r\n }\r\n const { watchDirectory } = await import(\"./watch.js\")\r\n await watchDirectory({\r\n dir,\r\n outDir: opts.outDir,\r\n webhook: opts.webhook,\r\n format: opts.format,\r\n pages: opts.pages,\r\n silent: opts.silent,\r\n })\r\n })\r\n\r\nprogram\r\n .command(\"fill [file]\")\r\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx / 내장 기안문 서식은 kordoc fill --template gian\")\r\n .option(\"-f, --fields <pairs>\", \"채울 필드 (key=value 쉼표 구분 또는 JSON)\")\r\n .option(\"-j, --json <path>\", \"채울 필드 JSON 파일 경로\")\r\n .option(\"-o, --output <path>\", \"출력 파일 경로 (확장자로 포맷 결정: .md, .hwpx)\")\r\n .option(\"--format <type>\", \"출력 포맷: hwpx-preserve (기본, 원본 스타일 보존), hwpx, markdown\", \"hwpx-preserve\")\r\n .option(\"--formats <json>\", \"필드별 값 서식 JSON (라벨→포맷) — 예: '{\\\"날짜\\\":\\\"yy.mm.dd\\\",\\\"주민등록번호\\\":\\\"rrn:masked\\\"}'\")\r\n .option(\"--template <name>\", \"내장 표준 서식 사용 (파일 경로 불필요): gian(일반기안문) | gian-simple(간이기안문). 위치 인자 'templates:일반기안문' 표기도 동일\")\r\n .option(\"--list-templates\", \"내장 표준 서식 목록 + 누름틀 필드 나열\")\r\n .option(\"--require-unique\", \"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 (반복 라벨 양식 오염 방지)\")\r\n .option(\"--mask\", \"채운 값 미노출 — 출력 파일 없이 markdown을 stdout으로 낼 때 본문 대신 안내만 표시\")\r\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string | undefined, opts, command: Command) => {\r\n try {\r\n // 루트 커맨드의 동명 옵션(-o/--output·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n opts.output ??= rootOpts.output\r\n opts.silent ??= rootOpts.silent\r\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\r\n opts.format = rootOpts.format\r\n }\r\n\r\n // --list-templates: 내장 서식 목록 + 누름틀 필드\r\n if (opts.listTemplates) {\r\n const list = []\r\n for (const t of BUILTIN_TEMPLATES) {\r\n const fields = await extractClickHereFields(readBuiltinTemplate(t))\r\n list.push({ id: t.id, aliases: t.aliases, title: t.title, fields: fields.map(f => f.name) })\r\n }\r\n process.stdout.write(JSON.stringify(list, null, 2) + \"\\n\")\r\n return\r\n }\r\n\r\n // 입력 소스 결정 — 내장 템플릿(--template 또는 'templates:이름' 위치 인자) 우선\r\n const templateName = opts.template ?? (file && /^templates?:/i.test(file) ? file : undefined)\r\n let arrayBuffer: ArrayBuffer\r\n let inputName: string\r\n if (templateName) {\r\n const t = resolveBuiltinTemplate(templateName)\r\n if (!t) {\r\n process.stderr.write(`[kordoc] 알 수 없는 내장 템플릿: ${templateName} (사용 가능: ${BUILTIN_TEMPLATES.map(x => `${x.id}(${x.aliases[0]})`).join(\", \")})\\n`)\r\n process.exit(1)\r\n }\r\n arrayBuffer = readBuiltinTemplate(t)\r\n inputName = t.file\r\n } else if (file) {\r\n const absPath = resolve(file)\r\n const fileSize = statSync(absPath).size\r\n if (fileSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`[kordoc] 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\r\n process.exit(1)\r\n }\r\n arrayBuffer = toArrayBuffer(readFileSync(absPath))\r\n inputName = basename(absPath)\r\n } else {\r\n process.stderr.write(`[kordoc] 서식 파일 경로 또는 --template 을 지정해주세요 (목록: kordoc fill --list-templates)\\n`)\r\n process.exit(1)\r\n return\r\n }\r\n\r\n if (!opts.silent) process.stderr.write(`[kordoc] ${inputName} 파싱 중...\\n`)\r\n\r\n // --dry-run: 필드 목록만 출력 — 서식 입력란(빈 후행 열)이 목록에 나오도록 보존 (#47)\r\n if (opts.dryRun) {\r\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true })\r\n if (!result.success) {\r\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\r\n process.exit(1)\r\n }\r\n const formInfo = extractFormFields(result.blocks)\r\n // 누름틀(CLICK_HERE) 필드도 함께 나열 — 표준 서식은 라벨 표 없이 누름틀만 있을 수 있다\r\n const clickHereFields = detectFormat(arrayBuffer) === \"hwpx\"\r\n ? await extractClickHereFields(arrayBuffer)\r\n : []\r\n if (formInfo.fields.length === 0 && clickHereFields.length === 0) {\r\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\r\n process.exit(1)\r\n }\r\n process.stdout.write(JSON.stringify(\r\n clickHereFields.length > 0 ? { ...formInfo, clickHereFields } : formInfo,\r\n null, 2,\r\n ) + \"\\n\")\r\n return\r\n }\r\n\r\n // 필드 값 파싱\r\n let values: Record<string, string> = {}\r\n if (opts.json) {\r\n const jsonPath = resolve(opts.json)\r\n const jsonContent = readFileSync(jsonPath, \"utf-8\")\r\n values = JSON.parse(jsonContent)\r\n } else if (opts.fields) {\r\n const fieldsStr: string = opts.fields\r\n if (fieldsStr.startsWith(\"{\")) {\r\n values = JSON.parse(fieldsStr)\r\n } else {\r\n // \"key1=value1,key2=value2\" 파싱 — 값에 쉼표가 있을 수 있으므로\r\n // '=' 앞의 키를 기준으로 분리 (쉼표+한글/영문+= 패턴)\r\n const pairs = fieldsStr.split(/,(?=[가-힣A-Za-z][가-힣A-Za-z\\s]*=)/)\r\n for (const pair of pairs) {\r\n const eqIdx = pair.indexOf(\"=\")\r\n if (eqIdx > 0) {\r\n const key = pair.slice(0, eqIdx).trim()\r\n const val = pair.slice(eqIdx + 1).trim()\r\n values[key] = val\r\n }\r\n }\r\n }\r\n } else {\r\n process.stderr.write(`[kordoc] 채울 필드를 지정해주세요 (-f 또는 -j 옵션)\\n`)\r\n process.exit(1)\r\n }\r\n\r\n // 필드별 값 서식 결합 — MCP fill_form(formats)과 동일 의미론 (form/match.js FillInput)\r\n let inputs: Record<string, FillInput> = values\r\n if (opts.formats) {\r\n let formatMap: Record<string, string>\r\n try {\r\n formatMap = JSON.parse(String(opts.formats))\r\n } catch {\r\n process.stderr.write(`[kordoc] --formats 는 JSON 객체여야 합니다 (라벨→포맷)\\n`)\r\n process.exit(1)\r\n }\r\n inputs = Object.fromEntries(Object.entries(values).map(([k, v]) => {\r\n const format = formatMap[k]\r\n return [k, format ? { value: v, format } : v]\r\n }))\r\n }\r\n\r\n // 출력 포맷 결정 — 확장자 오버라이드가 명시 --format 과 충돌하면 경고 후 확장자 우선\r\n let outputFormat = opts.format as string\r\n if (opts.output) {\r\n const ext = extname(opts.output).toLowerCase()\r\n const explicitFormat = command.getOptionValueSource(\"format\") === \"cli\" || program.getOptionValueSource(\"format\") === \"cli\"\r\n const before = outputFormat\r\n if (ext === \".hwpx\") outputFormat = outputFormat === \"markdown\" ? \"hwpx-preserve\" : outputFormat\r\n else if (ext === \".md\") outputFormat = \"markdown\"\r\n if (explicitFormat && before !== outputFormat) {\r\n process.stderr.write(`[kordoc] ⚠️ --format ${before} 가 출력 확장자(${ext})와 충돌합니다 — 확장자 기준 ${outputFormat} 로 진행\\n`)\r\n }\r\n }\r\n\r\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 ───\r\n if (outputFormat === \"hwpx-preserve\") {\r\n const format = detectFormat(arrayBuffer)\r\n let isHwpx = format === \"hwpx\"\r\n if (isHwpx) {\r\n const zipFormat = await detectZipFormat(arrayBuffer)\r\n isHwpx = zipFormat === \"hwpx\"\r\n }\r\n if (!isHwpx) {\r\n if (!opts.silent) process.stderr.write(`[kordoc] HWPX가 아니므로 hwpx 모드로 전환합니다\\n`)\r\n outputFormat = \"hwpx\"\r\n } else {\r\n const hwpxResult = opts.requireUnique\r\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(arrayBuffer, vals, blocked))\r\n : { ...(await fillHwpx(arrayBuffer, inputs)), rejected: [] as string[] }\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${hwpxResult.filled.length}개 필드 채움 (원본 스타일 보존)\\n`)\r\n if (hwpxResult.rejected.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${hwpxResult.rejected.join(\", \")}\\n`)\r\n }\r\n if (hwpxResult.unmatched.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${hwpxResult.unmatched.join(\", \")}\\n`)\r\n }\r\n }\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), Buffer.from(hwpxResult.buffer))\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else {\r\n process.stdout.write(Buffer.from(hwpxResult.buffer))\r\n }\r\n return\r\n }\r\n }\r\n\r\n // ─── 일반 경로: parse → fill → output ─── (양식 입력란 보존, #47)\r\n const result = await parse(arrayBuffer, { keepTrailingEmptyCols: true })\r\n if (!result.success) {\r\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\r\n process.exit(1)\r\n }\r\n\r\n const formInfo = extractFormFields(result.blocks)\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] 서식 필드 ${formInfo.fields.length}개 감지 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)\\n`)\r\n }\r\n\r\n const fillResult = opts.requireUnique\r\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked))\r\n : { ...fillFormFields(result.blocks, inputs), rejected: [] as string[] }\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${fillResult.filled.length}개 필드 채움\\n`)\r\n if (fillResult.rejected.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 모호 라벨 거부(2곳+ 매칭): ${fillResult.rejected.join(\", \")}\\n`)\r\n }\r\n if (fillResult.unmatched.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${fillResult.unmatched.join(\", \")}\\n`)\r\n }\r\n }\r\n\r\n const markdown = blocksToMarkdown(fillResult.blocks)\r\n\r\n if (outputFormat === \"hwpx\") {\r\n const hwpxBuffer = await markdownToHwpx(markdown)\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), Buffer.from(hwpxBuffer))\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else {\r\n process.stdout.write(Buffer.from(hwpxBuffer))\r\n }\r\n } else {\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), markdown, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else if (opts.mask) {\r\n // 채운 값(주민번호·연락처 등)이 터미널 로그에 남지 않게 본문 대신 안내 (MCP mask_values와 동일 취지)\r\n process.stdout.write(`⚠️ --mask 활성 — 개인정보 노출 방지를 위해 본문을 출력하지 않습니다. -o 로 파일 저장 후 확인하세요.\\n`)\r\n } else {\r\n process.stdout.write(markdown + \"\\n\")\r\n }\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"seal <file>\")\r\n .description('도장/서명 이미지를 앵커 문구 위에 부유 배치 (표/페이지 불확장) — kordoc seal 신청서.hwpx --image 도장.png --anchor \"(인)\" -o 결과.hwpx')\r\n .requiredOption(\"--image <path>\", \"도장/서명 이미지 (투명 배경 PNG 권장)\")\r\n .option(\"--anchor <text>\", \"앵커 문구\", \"(인)\")\r\n .option(\"-n, --occurrence <num>\", \"같은 앵커가 여럿일 때 0-based 선택\", \"0\")\r\n .option(\"--size-mm <num>\", \"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\")\r\n .option(\"--mode <mode>\", \"overlap(문구 위 겹침) | right(오른쪽 옆) | auto\", \"auto\")\r\n .option(\"--dx <mm>\", \"x 미세조정 mm\", \"0\")\r\n .option(\"--dy <mm>\", \"y 미세조정 mm\", \"0\")\r\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <입력>.sealed.hwpx)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const { placeSealHwpx, detectFormat } = await import(\"./index.js\")\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const mode = String(opts.mode).toLowerCase()\r\n if (![\"overlap\", \"right\", \"auto\"].includes(mode)) {\r\n process.stderr.write(`[kordoc] --mode 는 overlap/right/auto 중 하나여야 합니다\\n`)\r\n process.exit(1)\r\n }\r\n const buf = new Uint8Array(readFileSync(resolve(file)))\r\n if (detectFormat(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer) !== \"hwpx\") {\r\n process.stderr.write(`[kordoc] seal 은 HWPX 전용입니다 (HWP 5.x 바이너리는 미지원)\\n`)\r\n process.exit(1)\r\n }\r\n const imgPath = resolve(opts.image)\r\n const imgSize = statSync(imgPath).size\r\n if (imgSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`[kordoc] 도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB)\\n`)\r\n process.exit(1)\r\n }\r\n const image = new Uint8Array(readFileSync(imgPath))\r\n const ext = extname(opts.image).slice(1).toLowerCase() || \"png\"\r\n // 숫자 플래그 엄격 검증 — 비숫자가 NaN→0 무증상 강제, 음수 occurrence가 truthy로\r\n // 통과하던 것 차단 (MCP zod와 동등, v4.0.6: --size-mm만 검증하던 것을 전 숫자 플래그로)\r\n const parseNum = (flag: string, raw: unknown, { min, allowNeg = false }: { min?: number; allowNeg?: boolean } = {}): number => {\r\n const n = Number(raw)\r\n if (!Number.isFinite(n) || (!allowNeg && n < 0) || (min !== undefined && n < min)) {\r\n process.stderr.write(`[kordoc] ${flag} 값이 잘못됐습니다: ${raw}${allowNeg ? \"\" : \" (0 이상 숫자)\"}\\n`)\r\n process.exit(1)\r\n }\r\n return n\r\n }\r\n let sizeMm: number | undefined\r\n if (opts.sizeMm != null) {\r\n const n = Number(opts.sizeMm)\r\n if (!Number.isFinite(n) || n <= 0) {\r\n process.stderr.write(`[kordoc] --size-mm 은 양수여야 합니다: ${opts.sizeMm}\\n`)\r\n process.exit(1)\r\n }\r\n sizeMm = n\r\n }\r\n const result = await placeSealHwpx(\r\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer,\r\n [{\r\n anchor: opts.anchor,\r\n occurrence: parseNum(\"--occurrence\", opts.occurrence),\r\n image,\r\n ext: ext as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\",\r\n sizeMm,\r\n mode: mode as \"overlap\" | \"right\" | \"auto\",\r\n dxMm: parseNum(\"--dx\", opts.dx, { allowNeg: true }),\r\n dyMm: parseNum(\"--dy\", opts.dy, { allowNeg: true }),\r\n }],\r\n )\r\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".sealed.hwpx\")\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, Buffer.from(result.buffer))\r\n if (!silent) {\r\n for (const p of result.placed) {\r\n process.stderr.write(`[kordoc] 도장 배치: \"${p.anchor}\" #${p.occurrence} → ${p.mode} (${p.posXMm}mm, ${p.posYMm}mm, ${p.sizeMm}mm) [${p.entry}]\\n`)\r\n for (const w of p.warnings ?? []) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\r\n }\r\n process.stderr.write(`[kordoc] → ${outPath}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"patch <original> <edited>\")\r\n .description(\"서식 보존 라운드트립 패치 — 편집된 마크다운을 원본 HWPX/HWP에 in-place 반영 (kordoc patch 원본.hwpx 편집.md -o 출력.hwpx). 미적용(skip) 편집이 있으면 exit 2\")\r\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <원본>.patched.hwpx|.hwp)\")\r\n .option(\"--no-verify\", \"패치 후 재파싱 자동 검증 생략\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (original: string, edited: string, opts) => {\r\n try {\r\n const { patchHwpx, patchHwp, detectFormat } = await import(\"./index.js\")\r\n // 루트 커맨드의 동명 옵션(-o/--silent)이 서브커맨드 옵션을 가로채는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const originalBuf = new Uint8Array(readFileSync(resolve(original)))\r\n const editedMarkdown = readFileSync(resolve(edited), \"utf-8\")\r\n\r\n const format = detectFormat(originalBuf.buffer as ArrayBuffer)\r\n const result = format === \"hwp\"\r\n ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false })\r\n : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false })\r\n if (!result.success || !result.data) {\r\n process.stderr.write(`[kordoc] 패치 실패: ${result.error ?? \"알 수 없는 오류\"}\\n`)\r\n process.exit(1)\r\n }\r\n\r\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\r\n const outPath = resolve(output ?? original.replace(/\\.hwpx?$/i, \"\") + \".patched\" + ext)\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.data)\r\n\r\n if (!silent) {\r\n process.stderr.write(`[kordoc] ${result.applied}개 변경 적용 (원본 서식 보존) → ${outPath}\\n`)\r\n for (const s of result.skipped) {\r\n process.stderr.write(`[kordoc] ⚠️ SKIP: ${s.reason}${s.before ? ` | ${s.before}` : \"\"}\\n`)\r\n }\r\n if (result.verification) {\r\n const v = result.verification.stats\r\n const residual = v.added + v.removed + v.modified\r\n process.stderr.write(residual === 0\r\n ? `[kordoc] ✓ 검증: 편집 마크다운과 재파싱 결과 완전 일치 (${v.unchanged}블록)\\n`\r\n : `[kordoc] ⚠️ 검증 잔차: 수정 ${v.modified}, 추가 ${v.added}, 삭제 ${v.removed} (미지원 변경은 skip 목록 참조)\\n`)\r\n }\r\n }\r\n if (result.skipped.length > 0) process.exitCode = 2\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"validate <file>\")\r\n .description(\"HWPX 구조 검증 — ZIP·mimetype·필수 파일·XML 웰폼드·secCnt·manifest 참조 (한컴독스 거부 요인 사전 차단)\")\r\n .option(\"--json\", \"결과를 JSON으로 stdout에 출력\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const { validateHwpx } = await import(\"./index.js\")\r\n const buf = new Uint8Array(readFileSync(resolve(file)))\r\n const result = await validateHwpx(buf)\r\n if (opts.json) {\r\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\r\n } else if (result.ok) {\r\n process.stderr.write(`[kordoc] ✓ 구조 검증 통과 (엔트리 ${result.entryCount}개): ${file}\\n`)\r\n } else {\r\n process.stderr.write(`[kordoc] ✗ 구조 문제 ${result.issues.length}건: ${file}\\n`)\r\n for (const i of result.issues) {\r\n process.stderr.write(`[kordoc] - ${i.path ? `${i.path}: ` : \"\"}${i.message}\\n`)\r\n }\r\n }\r\n if (!result.ok) process.exit(1)\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\n// 공문서 프리셋 별칭(한글/영문) → 내부 preset 키 — gongmun.ts와 공용(PRESET_ALIAS)\r\n\r\nprogram\r\n .command(\"generate <markdown>\")\r\n .alias(\"gen\")\r\n .description(\"마크다운 → 공문서 HWPX 생성 — kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 (markdown에 '-' 지정 시 stdin)\")\r\n .option(\"-o, --output <path>\", \"출력 HWPX 경로 (기본: <입력>.hwpx)\")\r\n .option(\"--preset <name>\", \"공문서 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)·개조식(gaejosik — 표지·목차·장헤더 자동)·보도자료(press)\", \"기안문\")\r\n .option(\"--font <type>\", \"본문 글꼴: myeongjo(함초롬바탕) 또는 gothic(맑은 고딕)\")\r\n .option(\"--pt <size>\", \"본문 글자 크기(pt)\")\r\n .option(\"--line-spacing <percent>\", \"본문 줄간격(%)\")\r\n .option(\"--profile <path>\", \"서식 프로필 JSON (kordoc profile로 추출) — 참조 문서의 표 테두리·음영·열폭·셀 글꼴 재현\")\r\n .option(\"--org <name>\", \"표지 기관명 (표지를 켜는 프리셋 공통)\")\r\n .option(\"--date <date>\", \"표지 날짜 (기본 오늘 — 'YYYY. M. D.')\")\r\n .option(\"--toc\", \"목차 페이지 강제 켜기 (개조식 외 프리셋에서도 h2 목록으로 생성)\")\r\n .option(\"--no-toc\", \"목차 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\r\n .option(\"--cover\", \"표지 페이지 강제 켜기 (개조식 외 프리셋에서도 첫 h1을 표지로)\")\r\n .option(\"--no-cover\", \"표지 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\r\n .option(\"--approval <labels>\", \"결재란 직위 라벨 (쉼표 구분, 예: 담당,팀장,과장) — 문서 최상단 우측\")\r\n .option(\"--page-numbers\", \"쪽번호 강제 켜기 (하단 중앙 '- 1 -')\")\r\n .option(\"--no-page-numbers\", \"쪽번호 끄기 (개조식·보고서·계획서 기본 켜짐)\")\r\n .option(\"--end-mark\", \"본문 끝 '끝.' 표시 강제 켜기\")\r\n .option(\"--no-end-mark\", \"'끝.' 표시 끄기 (기안문 기본 켜짐)\")\r\n .option(\"--no-body-title-box\", \"본문 첫 페이지 제목 반복 박스 끄기 (개조식+표지 기본 켜짐)\")\r\n .option(\"--h2-marker <type>\", \"h2 섹션 제목 말머리: box(□ — 보고서·계획서 기본)·number(1. — 공고문 관행)·none\")\r\n .option(\"--fonts <spec>\", \"요소별 글꼴 오버라이드: body=나눔명조,heading=나눔고딕,ref=한양중고딕,table=맑은 고딕\")\r\n .option(\"--sizes <spec>\", \"개조식 요소별 크기(pt): dae=16,cham=13,table=12,coverTitle=30 …\")\r\n .option(\"--bullet2 <char>\", \"2단계 항목부호: ㅇ(이응 — 기안문·공고문 실측 지배) 또는 ○(원 — 보고서 양식)\")\r\n .option(\"--suppress-single\", \"단일 형제 항목 부호 생략 (편람 규정 — 기본은 하나여도 부호 부여)\")\r\n .option(\"--doc-head <spec>\", \"기안문 두문: org=행정안전부,to=수신처,title=제목 (별지 제1호서식)\")\r\n .option(\"--doc-foot <spec>\", \"기안문 결문: sender=장관명의,drafter=기안자,reviewer=검토자,approver=결재권자,docNum=시행번호,phone=전화,email=메일,disclosure=공개구분 …\")\r\n .option(\"--report-info <text>\", \"업무보고 우상단 보고정보 행 — 예: '(2026. 7. 11., 과장 홍길동, ☎02-120)'\")\r\n .option(\"--notice-head <spec>\", \"공고문 두문·결문: no=공고 제2026-1호,date=2026년 7월 11일,sender=행정안전부장관\")\r\n .option(\"--press-head <spec>\", \"보도자료 머리: release=보도시점,distribute=배포일,dept=담당부서,manager=담당자,phone=연락처\")\r\n .option(\"--press-sub <items>\", \"보도자료 부제 (세미콜론 구분, 제목 아래 '- … -')\")\r\n .option(\"--plain\", \"공문서 모드 끄기 (범용 마크다운 변환)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (markdown: string, opts) => {\r\n try {\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n\r\n // 입력: '-' 이면 stdin, 아니면 파일\r\n let md: string\r\n let baseName = \"document\"\r\n if (markdown === \"-\") {\r\n md = readFileSync(0, \"utf-8\")\r\n } else {\r\n const inPath = resolve(markdown)\r\n md = readFileSync(inPath, \"utf-8\")\r\n baseName = basename(inPath).replace(/\\.(md|markdown|txt)$/i, \"\")\r\n }\r\n\r\n // 공문서 옵션 구성 — 값 검증(열거)과 조립은 gongmun-surface SSOT, 여기는\r\n // commander 표면 사정(kv 파싱·--no-x 기본값)을 중립 입력으로 정돈하는 어댑터만\r\n let gongmun: import(\"./index.js\").GongmunOptions | undefined\r\n if (!opts.plain) {\r\n const preset = PRESET_ALIAS[String(opts.preset).trim()]\r\n if (!preset) {\r\n process.stderr.write(`[kordoc] 알 수 없는 프리셋: ${opts.preset} (기안문/보고서/계획서/통지/회의록/개조식/보도자료)\\n`)\r\n process.exit(1)\r\n }\r\n const enumCheck = <T extends readonly string[]>(flag: string, value: unknown, allowed: T): (typeof allowed)[number] | undefined => {\r\n if (value === undefined) return undefined\r\n if (!allowed.includes(String(value))) {\r\n process.stderr.write(`[kordoc] ${flag} 는 ${allowed.join(\"/\")}\\n`)\r\n process.exit(1)\r\n }\r\n return value as (typeof allowed)[number]\r\n }\r\n // \"key=value,key=value\" 스펙 파싱 — 값의 '='는 보존(첫 '='만 분리). 쉼표는\r\n // 구분자라 값에 못 들어감 — '=' 없는 조각(잘린 값의 꼬리 등)은 무증상 드랍\r\n // 대신 경고로 노출 (v4.0.6: 두문 title 값 유실이 조용히 지나가던 것 봉합)\r\n const parseKv = (spec: string, flag: string): Record<string, string> => {\r\n const out: Record<string, string> = {}\r\n for (const piece of spec.split(\",\")) {\r\n const p = piece.trim()\r\n if (!p) continue\r\n const eq = p.indexOf(\"=\")\r\n const key = eq > 0 ? p.slice(0, eq).trim() : \"\"\r\n const value = eq > 0 ? p.slice(eq + 1).trim() : \"\"\r\n if (!key || !value) {\r\n process.stderr.write(`[kordoc] ${flag}: 'key=value' 형식이 아닌 조각 무시 — \"${p}\" (값에 쉼표는 쓸 수 없습니다)\\n`)\r\n continue\r\n }\r\n out[key] = value\r\n }\r\n return out\r\n }\r\n const pressKv = opts.pressHead ? parseKv(String(opts.pressHead), \"--press-head\") : {}\r\n gongmun = buildGongmunOptions({\r\n preset,\r\n font: enumCheck(\"--font\", opts.font, BODY_FONTS),\r\n bodyPt: opts.pt ? Number(opts.pt) : undefined,\r\n lineSpacing: opts.lineSpacing ? Number(opts.lineSpacing) : undefined,\r\n org: opts.org, date: opts.date,\r\n cover: opts.cover, toc: opts.toc,\r\n approval: opts.approval ? String(opts.approval).split(\",\").map((s: string) => s.trim()).filter(Boolean) : undefined,\r\n pageNumbers: opts.pageNumbers, endMark: opts.endMark,\r\n // --no-body-title-box 단독 플래그 — commander 기본 true는 \"미지정\"으로 정돈\r\n bodyTitleBox: opts.bodyTitleBox === false ? false : undefined,\r\n h2Marker: enumCheck(\"--h2-marker\", opts.h2Marker, H2_MARKERS),\r\n fonts: opts.fonts ? parseKv(String(opts.fonts), \"--fonts\") : undefined,\r\n sizes: opts.sizes\r\n ? Object.fromEntries(\r\n Object.entries(parseKv(String(opts.sizes), \"--sizes\")).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v as number)),\r\n )\r\n : undefined,\r\n bullet2: enumCheck(\"--bullet2\", opts.bullet2, BULLET2_CHARS),\r\n suppressSingle: opts.suppressSingle ? true : undefined,\r\n docHead: opts.docHead ? parseKv(String(opts.docHead), \"--doc-head\") : undefined,\r\n docFoot: opts.docFoot ? parseKv(String(opts.docFoot), \"--doc-foot\") : undefined,\r\n reportInfo: opts.reportInfo ? String(opts.reportInfo) : undefined,\r\n noticeHead: opts.noticeHead ? parseKv(String(opts.noticeHead), \"--notice-head\") : undefined,\r\n press: opts.pressHead || opts.pressSub\r\n ? {\r\n release: pressKv.release, distribute: pressKv.distribute,\r\n sub: opts.pressSub ? String(opts.pressSub).split(\";\").map((s: string) => s.trim()).filter(Boolean) : undefined,\r\n contact: pressKv.dept || pressKv.manager || pressKv.phone ? { dept: pressKv.dept, manager: pressKv.manager, phone: pressKv.phone } : undefined,\r\n }\r\n : undefined,\r\n })\r\n }\r\n\r\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행\r\n if (gongmun?.fonts && !silent) {\r\n for (const w of unknownFontWarnings(gongmun.fonts)) process.stderr.write(`[kordoc] ${w}\\n`)\r\n }\r\n // 프리셋 비호환 옵션 경고 (v4.0.6) — 조용한 폐기 대신 노출, 생성은 진행\r\n if (gongmun && !silent) {\r\n for (const w of incompatibleGongmunWarnings(gongmun)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\r\n }\r\n // 공문서 표기법 검수 (편람 기준, 조언용) — 생성은 진행, stderr 경고만\r\n if (gongmun && !silent) {\r\n for (const w of gongmunLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\r\n }\r\n\r\n // 서식 프로필 (이슈 #41) — 경계 zod 검증 후 라이브러리에 전달 (MCP와 공유 스키마)\r\n let profile: FormatProfile | undefined\r\n if (opts.profile) {\r\n profile = parseFormatProfileJson(readFileSync(resolve(String(opts.profile)), \"utf-8\"))\r\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 적용: 표 ${profile.tables.length}개 (${opts.profile})\\n`)\r\n }\r\n\r\n const buf = await markdownToHwpx(md, gongmun || profile ? { ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}) } : undefined)\r\n const outPath = resolve(output ?? (markdown === \"-\" ? `${baseName}.hwpx` : markdown.replace(/\\.(md|markdown|txt)$/i, \"\") + \".hwpx\"))\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, Buffer.from(buf))\r\n\r\n if (!silent) {\r\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\r\n process.stderr.write(`[kordoc] HWPX 생성 (${mode}) → ${outPath}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"profile <file>\")\r\n .description(\"HWPX 표 서식 프로필 추출 — 참조 문서의 표 테두리·음영·열폭·셀 글꼴을 JSON으로 (generate --profile로 재현) — kordoc profile 참조.hwpx -o 서식.json\")\r\n .option(\"-o, --output <path>\", \"출력 JSON 경로 (기본: <입력>.profile.json)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const absPath = resolve(file)\r\n const profile = await hwpxToProfile(readFileSync(absPath))\r\n const outPath = resolve(output ?? absPath.replace(/\\.hwpx$/i, \"\") + \".profile.json\")\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, JSON.stringify(profile, null, 2))\r\n if (!silent) process.stderr.write(`[kordoc] 서식 프로필 추출: 표 ${profile.tables.length}개 → ${outPath}\\n`)\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"lint <file>\")\r\n .description(\"공문서 표기법 검수 — 날짜·시간·금액·붙임 등 행정업무운영 편람 표기법 (md/txt, '-'=stdin). error 있으면 exit 1\")\r\n .option(\"--json\", \"JSON 출력\")\r\n .action((file: string, opts) => {\r\n try {\r\n const text = file === \"-\" ? readFileSync(0, \"utf-8\") : readFileSync(resolve(file), \"utf-8\")\r\n const findings = lintGongmunText(text)\r\n const errors = findings.filter((f) => f.severity === \"error\").length\r\n if (opts.json) {\r\n process.stdout.write(JSON.stringify({ findings, summary: { total: findings.length, errors, ok: errors === 0 } }, null, 2) + \"\\n\")\r\n } else {\r\n // 사람용 리포트는 stderr — 기계용(--json)만 stdout (validate와 채널 일관)\r\n process.stderr.write(`[kordoc] 표기법 검수: 위반 ${findings.length}건 (error ${errors}, warning ${findings.length - errors})\\n`)\r\n for (const f of findings) {\r\n process.stderr.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\r\n }\r\n }\r\n process.exit(errors > 0 ? 1 : 0)\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"redact <files...>\")\r\n .description(\"개인정보 서식 보존 마스킹 — 주민번호·전화·이메일·카드·계좌를 탐지해 HWPX/HWP는 원본 서식 그대로 patch, 그 외 포맷은 마스킹된 마크다운 출력. 자동 검출 보조 도구이므로 결과는 반드시 사람이 최종 확인하세요 (이미지 안 텍스트는 탐지 불가)\")\r\n .option(\"--rules <csv>\", \"적용 룰 (기본: rrn,phone,email,card,account — passport,driver는 opt-in)\")\r\n .option(\"--mask-char <ch>\", \"마스크 문자 1글자 (기본: ●)\")\r\n .option(\"-o, --output <path>\", \"출력 경로 (단일 파일 시)\")\r\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\r\n .option(\"--dry-run\", \"탐지 리포트만 출력, 파일 미생성\")\r\n .option(\"--json\", \"리포트를 JSON으로 stdout 출력\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (files: string[], opts) => {\r\n const { redactMarkdown, DEFAULT_REDACT_RULES, patchHwpx, patchHwp } = await import(\"./index.js\")\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const KNOWN_RULES = new Set([\"rrn\", \"phone\", \"email\", \"card\", \"account\", \"passport\", \"driver\"])\r\n const rules = opts.rules\r\n ? String(opts.rules).split(\",\").map((r: string) => r.trim()).filter(Boolean)\r\n : [...DEFAULT_REDACT_RULES]\r\n const badRule = rules.find((r: string) => !KNOWN_RULES.has(r))\r\n if (badRule) {\r\n process.stderr.write(`[kordoc] 알 수 없는 룰: ${badRule} (허용: ${[...KNOWN_RULES].join(\", \")})\\n`)\r\n process.exit(1)\r\n }\r\n if (output && files.length > 1) {\r\n process.stderr.write(`[kordoc] ⚠️ -o/--output 은 단일 파일 전용이라 무시됩니다 — 다중 파일은 -d/--out-dir 를 사용하세요\\n`)\r\n }\r\n const jsonReports: unknown[] = []\r\n for (const filePath of files) {\r\n const absPath = resolve(filePath)\r\n const fileName = basename(absPath)\r\n try {\r\n const buffer = readFileSync(absPath)\r\n const arrayBuffer = toArrayBuffer(buffer)\r\n const format = detectFormat(arrayBuffer)\r\n const parsed = await parse(arrayBuffer, { filePath: absPath })\r\n if (!parsed.success) {\r\n process.stderr.write(`[kordoc] FAIL: ${fileName} — ${parsed.error}\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n const r = redactMarkdown(parsed.markdown, { rules: rules as never, maskChar: opts.maskChar })\r\n const byRule = new Map<string, number>()\r\n for (const h of r.hits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\r\n const ruleSummary = [...byRule.entries()].map(([k, v]) => `${k} ${v}건`).join(\", \") || \"0건\"\r\n\r\n let outPath: string | null = null\r\n let patchNote = \"\"\r\n if (!opts.dryRun && r.hits.length > 0) {\r\n const patchable = format === \"hwpx\" || format === \"hwp\"\r\n if (patchable) {\r\n const original = new Uint8Array(arrayBuffer)\r\n const result = format === \"hwp\"\r\n ? await patchHwp(original, r.text)\r\n : await patchHwpx(original, r.text)\r\n if (!result.success || !result.data) {\r\n process.stderr.write(`[kordoc] 패치 실패: ${fileName} — ${result.error ?? \"알 수 없는 오류\"}\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\r\n outPath = resolve(\r\n output && files.length === 1\r\n ? output\r\n : resolve(opts.outDir ?? dirname(absPath), fileName.replace(/\\.[^.]+$/, \"\") + \".redacted\" + ext),\r\n )\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.data)\r\n if (result.skipped.length > 0) {\r\n patchNote = ` (⚠️ 미적용 ${result.skipped.length}건 — 해당 위치는 원문 잔존, 수동 확인 필요)`\r\n process.exitCode = 2\r\n }\r\n } else {\r\n outPath = resolve(\r\n output && files.length === 1\r\n ? output\r\n : resolve(opts.outDir ?? dirname(absPath), fileName.replace(/\\.[^.]+$/, \"\") + \".redacted.md\"),\r\n )\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, r.text, \"utf-8\")\r\n patchNote = ` (${format}는 서식 보존 미지원 — 마스킹된 마크다운으로 출력)`\r\n }\r\n }\r\n if (opts.json) {\r\n jsonReports.push({ file: absPath, format, rules, hits: r.hits, output: outPath })\r\n }\r\n if (!silent) {\r\n process.stderr.write(`[kordoc] ${fileName}: ${ruleSummary}${outPath ? ` → ${outPath}` : opts.dryRun ? \" (dry-run)\" : \"\"}${patchNote}\\n`)\r\n for (const h of r.hits) process.stderr.write(` - [${h.rule}] ${h.masked}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\r\n process.exitCode = 1\r\n }\r\n }\r\n if (opts.json) process.stdout.write(JSON.stringify(files.length === 1 ? jsonReports[0] ?? null : jsonReports, null, 2) + \"\\n\")\r\n })\r\n\r\nprogram\r\n .command(\"render <file>\")\r\n .description(\"레이아웃 보존 렌더 — HWPX를 SVG로 (전체 페이지 세로 스택). 한컴 저장본은 조판 캐시 그대로, 캐시 없는 생성본·편집본은 순수 TS 조판(reflow, 기본 켬) — kordoc render 문서.hwpx -o 문서.svg\")\r\n .option(\"-o, --output <path>\", \"출력 SVG 경로 (기본: <입력>.svg)\")\r\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\r\n .option(\"--no-reflow\", \"순수 TS 조판 끄기 (조판 캐시 없는 문서가 빈 페이지로 나올 수 있음)\")\r\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep(어절) | charAll(글자)\", \"keep\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\r\n const absPath = resolve(file)\r\n const buffer = readFileSync(absPath)\r\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\r\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\r\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".svg\")\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.svg, \"utf-8\")\r\n if (!silent) {\r\n process.stderr.write(`[kordoc] 렌더 (${result.pageCount}페이지, ${result.width}x${result.height}pt, 텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables}) → ${outPath}\\n`)\r\n for (const w of result.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"render-worker\")\r\n .description(\"persistent 렌더 워커 — stdin NDJSON 요청 → 조판 SVG 파일 출력 (프로세스 유지, 콜드스타트 제거)\")\r\n .action(async () => {\r\n // 프로토콜(NDJSON, 한 줄=한 요청/응답):\r\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"out\":\"a.svg\",\"reflow\":true,\"highlight\":[\"term\"]}\r\n // 응답 {\"id\":1,\"ok\":true,\"out\":\"a.svg\",\"width\":..,\"height\":..,\"pageCount\":..,\"stats\":{..},\"warnings\":[..]}\r\n // {\"cmd\":\"quit\"} 로 종료. 모듈은 최초 1회만 로드 → 이후 요청은 콜드스타트 없음.\r\n const { createInterface } = await import(\"node:readline\")\r\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\r\n const rl = createInterface({ input: process.stdin })\r\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o) + \"\\n\")\r\n write({ ready: true, version: VERSION })\r\n for await (const line of rl) {\r\n const t = line.trim()\r\n if (!t) continue\r\n let req: { id?: number; cmd?: string; file?: string; out?: string; reflow?: boolean; reflowMode?: string; highlight?: string[] }\r\n // 비JSON 라인도 응답은 낸다 — 무음 삼킴이면 id 대기 클라이언트가 영구 행\r\n try { req = JSON.parse(t) } catch { write({ ok: false, error: \"잘못된 JSON 라인\" }); continue }\r\n if (req === null || typeof req !== \"object\") { write({ ok: false, error: \"JSON 객체가 아닙니다\" }); continue }\r\n if (req.cmd === \"quit\") { rl.close(); break }\r\n const id = req.id\r\n try {\r\n if (!req.file || !req.out) throw new Error(\"file·out 필수\")\r\n const buffer = readFileSync(resolve(req.file))\r\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), {\r\n highlights: req.highlight, reflow: req.reflow, reflowMode: req.reflowMode as \"keep\" | \"charAll\" | undefined,\r\n })\r\n const outPath = resolve(req.out)\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.svg, \"utf-8\")\r\n write({ id, ok: true, out: outPath, width: result.width, height: result.height, pageCount: result.pageCount, stats: result.stats, warnings: result.warnings })\r\n } catch (err) {\r\n write({ id, ok: false, error: sanitizeError(err) })\r\n }\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"mcp\")\r\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\r\n .action(async () => {\r\n const { startMcpServer } = await import(\"./mcp.js\")\r\n await startMcpServer()\r\n })\r\n\r\nprogram\r\n .command(\"setup\")\r\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\r\n .action(async () => {\r\n const { runSetup } = await import(\"./setup.js\")\r\n await runSetup()\r\n })\r\n\r\nprogram\r\n .command(\"check-formula-models\")\r\n .description(\"PDF 수식 OCR 모델(MFD + MFR + tokenizer, ~155MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\r\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\r\n .action(async (opts) => {\r\n try {\r\n const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import(\r\n \"./pdf/formula/index.js\"\r\n )\r\n const dir = getFormulaModelsDir()\r\n if (opts.statusOnly) {\r\n const status = await getFormulaModelStatus()\r\n process.stdout.write(\r\n JSON.stringify(\r\n {\r\n modelsDir: dir,\r\n allReady: status.every((s) => s.verified),\r\n models: status.map((s) => ({\r\n name: s.spec.name,\r\n filename: s.spec.filename,\r\n sizeMb: s.spec.sizeMb,\r\n exists: s.exists,\r\n verified: s.verified,\r\n invalidReason: s.invalidReason,\r\n path: s.localPath,\r\n })),\r\n },\r\n null,\r\n 2,\r\n ) + \"\\n\",\r\n )\r\n return\r\n }\r\n process.stderr.write(`[kordoc-formula] 캐시 디렉토리: ${dir}\\n`)\r\n await ensureFormulaModels((p) => {\r\n if (p.phase === \"download\" && p.total) {\r\n const pct = Math.floor((p.downloaded / p.total) * 100)\r\n process.stderr.write(\r\n `\\r[kordoc-formula] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\r\n )\r\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\r\n } else if (p.phase === \"verify\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} SHA-256 검증 중...\\n`)\r\n } else if (p.phase === \"done\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 준비 완료\\n`)\r\n } else if (p.phase === \"skip\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 이미 존재 (skip)\\n`)\r\n }\r\n })\r\n process.stdout.write(\"ok\\n\")\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 수식 모델 준비 실패: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"check-ocr-models\")\r\n .description(\"텍스트 OCR 모델(PP-OCRv5 korean det+rec, ~18MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\r\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\r\n .action(async (opts) => {\r\n try {\r\n const { getOcrModelStatus, ensureOcrModels, getOcrModelsDir } = await import(\"./ocr/models.js\")\r\n const dir = getOcrModelsDir()\r\n if (opts.statusOnly) {\r\n const status = await getOcrModelStatus()\r\n process.stdout.write(\r\n JSON.stringify(\r\n {\r\n modelsDir: dir,\r\n allReady: status.every((s) => s.verified),\r\n models: status.map((s) => ({\r\n name: s.spec.name,\r\n filename: s.spec.filename,\r\n sizeMb: s.spec.sizeMb,\r\n exists: s.exists,\r\n verified: s.verified,\r\n invalidReason: s.invalidReason,\r\n path: s.localPath,\r\n })),\r\n },\r\n null,\r\n 2,\r\n ) + \"\\n\",\r\n )\r\n return\r\n }\r\n process.stderr.write(`[kordoc-ocr] 캐시 디렉토리: ${dir}\\n`)\r\n await ensureOcrModels((p) => {\r\n if (p.phase === \"download\" && p.total) {\r\n const pct = Math.floor((p.downloaded / p.total) * 100)\r\n process.stderr.write(\r\n `\\r[kordoc-ocr] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\r\n )\r\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\r\n } else if (p.phase === \"verify\") {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} SHA-256 검증 중...\\n`)\r\n } else if (p.phase === \"done\") {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 준비 완료\\n`)\r\n } else if (p.phase === \"skip\") {\r\n process.stderr.write(`[kordoc-ocr] ${p.spec.name} 이미 존재 (skip)\\n`)\r\n }\r\n })\r\n process.stdout.write(\"ok\\n\")\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] OCR 모델 준비 실패: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram.parse()\r\n"],"mappings":"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","names":["result","formInfo","detectFormat"]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ensureSingleModel,
|
|
10
10
|
getFormulaModelStatus,
|
|
11
11
|
getFormulaModelsDir
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YNJDNP44.js";
|
|
13
13
|
|
|
14
14
|
// src/pdf/formula/postprocess.ts
|
|
15
15
|
var TRAILING_WHITESPACE_CMDS = [
|
|
@@ -940,4 +940,4 @@ export {
|
|
|
940
940
|
getFormulaModelsDir,
|
|
941
941
|
postProcessLatex
|
|
942
942
|
};
|
|
943
|
-
//# sourceMappingURL=formula-
|
|
943
|
+
//# sourceMappingURL=formula-7ZPC54JO.js.map
|