kordoc 4.16.2 → 4.16.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -6
- package/dist/{-4G6MA4X6.js → -5XQIJN3D.js} +10 -10
- package/dist/{chunk-UTP2WCHS.js → chunk-2EJ5YSFZ.js} +4 -4
- package/dist/{chunk-IQGIT2VX.js → chunk-3ZVZPYSA.js} +5 -5
- package/dist/{chunk-TXUKTOG2.js → chunk-46H2PPG7.js} +3 -3
- package/dist/{chunk-7KNGSQU7.js → chunk-4O5XQSCT.js} +2 -2
- package/dist/{chunk-MLIS253L.js → chunk-7NYRZI2Z.js} +2 -2
- package/dist/{chunk-GO5IFOUF.js → chunk-7USPM2VT.js} +2 -2
- package/dist/{chunk-XTFN5WKS.cjs → chunk-7WV3WETF.cjs} +6 -6
- package/dist/{chunk-XTFN5WKS.cjs.map → chunk-7WV3WETF.cjs.map} +1 -1
- package/dist/{chunk-KIOQ4N37.js → chunk-AL2WM6ZZ.js} +2 -2
- package/dist/{chunk-F4NRLLY4.js → chunk-AWWFGIBA.js} +2 -2
- package/dist/{chunk-QOCS7W7R.js → chunk-D2UGAEXY.js} +9 -9
- package/dist/{chunk-P6ZDXTV6.js → chunk-ENF34XNH.js} +2 -2
- package/dist/{chunk-5KS5PWJR.js → chunk-GGGO3OH2.js} +2 -2
- package/dist/{chunk-JFLAM3MM.js → chunk-GH2JGKWP.js} +2 -2
- package/dist/{chunk-S2PL227Q.js → chunk-IE6QX3T3.js} +2 -2
- package/dist/{chunk-LEIAEWZ7.js → chunk-JIFG35UT.js} +2 -2
- package/dist/{chunk-DES2LGFZ.js → chunk-LQAKDKSF.js} +2 -2
- package/dist/{chunk-SFEQYKYJ.js → chunk-MC2SRJXO.js} +2 -2
- package/dist/{chunk-STM3ORY7.cjs → chunk-PMULUMUF.cjs} +2 -2
- package/dist/{chunk-STM3ORY7.cjs.map → chunk-PMULUMUF.cjs.map} +1 -1
- package/dist/{chunk-FSDJLAOW.js → chunk-QPJXYJIK.js} +55 -1
- package/dist/chunk-QPJXYJIK.js.map +1 -0
- package/dist/{chunk-OXLPVQYK.js → chunk-T2QHY3S5.js} +3 -3
- package/dist/{chunk-4VODJKFL.js → chunk-UCGGVNTD.js} +3 -3
- package/dist/{chunk-AUWGDP4G.js → chunk-XPYK7Z73.js} +2 -2
- package/dist/{chunk-FKUDAIJI.cjs → chunk-YJECRT5Q.cjs} +12 -12
- package/dist/{chunk-FKUDAIJI.cjs.map → chunk-YJECRT5Q.cjs.map} +1 -1
- package/dist/{chunk-WDQTFAXY.cjs → chunk-YOCFY44Z.cjs} +11 -11
- package/dist/{chunk-WDQTFAXY.cjs.map → chunk-YOCFY44Z.cjs.map} +1 -1
- package/dist/{chunk-JELRWAZC.js → chunk-YUZZNS6E.js} +2 -2
- package/dist/{chunk-CEIATRDW.cjs → chunk-Z3RFAVZ2.cjs} +3 -3
- package/dist/{chunk-CEIATRDW.cjs.map → chunk-Z3RFAVZ2.cjs.map} +1 -1
- package/dist/chunks-GBPAQ6JM.js +10 -0
- package/dist/cli.js +31 -50
- package/dist/cli.js.map +1 -1
- package/dist/{formula-EPKLPDU7.js → formula-EUX2AHXG.js} +3 -3
- package/dist/{formula-NARUOXRX.js → formula-IMEE5OJR.js} +4 -4
- package/dist/{formula-WIMV5TUX.cjs → formula-NPOU4BSO.cjs} +9 -9
- package/dist/{formula-WIMV5TUX.cjs.map → formula-NPOU4BSO.cjs.map} +1 -1
- package/dist/{image-ocr-3WJ4QH3T.js → image-ocr-CCIE3SPX.js} +7 -7
- package/dist/{image-ocr-AXWXR6JV.cjs → image-ocr-LTSQRHCN.cjs} +14 -14
- package/dist/{image-ocr-AXWXR6JV.cjs.map → image-ocr-LTSQRHCN.cjs.map} +1 -1
- package/dist/{image-ocr-5BUJQ4TK.js → image-ocr-QLW5VL4M.js} +5 -5
- package/dist/index.cjs +237 -237
- package/dist/index.js +4 -4
- package/dist/mcp.js +30 -37
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-IMBW7D2Z.js → model-bundle-VRKRVD6Z.js} +5 -5
- package/dist/{models-SY75IBOE.js → models-GSZIPSV2.js} +5 -5
- package/dist/{parser-N6476XAC.js → parser-64C45UPQ.js} +10 -10
- package/dist/{parser-ZQM3664Z.js → parser-NARS2CF7.js} +7 -7
- package/dist/{parser-2LU4EVU3.cjs → parser-U52HRNOY.cjs} +81 -81
- package/dist/{parser-2LU4EVU3.cjs.map → parser-U52HRNOY.cjs.map} +1 -1
- package/dist/pdf-ocr-4QWLMFJQ.js +18 -0
- package/dist/pdf-ocr-C7RXT5YU.cjs +16 -0
- package/dist/{pdf-ocr-GHEJVPX2.cjs.map → pdf-ocr-C7RXT5YU.cjs.map} +1 -1
- package/dist/pdf-ocr-ZYRJLOWQ.js +15 -0
- package/dist/{profile-io-GJPKCYPT.js → profile-io-PZBOSV5X.js} +3 -3
- package/dist/{rasterize-UOALJQDS.js → rasterize-DXBWM6T2.js} +3 -3
- package/dist/{redact-doc-22SYW3KH.js → redact-doc-FLMBZ53F.js} +10 -10
- package/dist/{render-MJ4H3R23.js → render-QNWUOQXJ.js} +6 -6
- package/dist/seal-NNZUQPDJ.js +10 -0
- package/dist/{setup-2URYVUEO.js → setup-3OR4QZFF.js} +3 -3
- package/dist/visual-RDGSACGE.js +20 -0
- package/dist/{watch-ALXZGTOB.js → watch-5A52FP6G.js} +11 -11
- package/package.json +1 -1
- package/dist/chunk-FSDJLAOW.js.map +0 -1
- package/dist/chunks-NUNIKS2J.js +0 -10
- package/dist/pdf-ocr-6DEE23IP.js +0 -15
- package/dist/pdf-ocr-GHEJVPX2.cjs +0 -16
- package/dist/pdf-ocr-MQTWODVU.js +0 -18
- package/dist/seal-XWMRUTI4.js +0 -10
- package/dist/visual-USPS4QRC.js +0 -20
- /package/dist/{-4G6MA4X6.js.map → -5XQIJN3D.js.map} +0 -0
- /package/dist/{chunk-UTP2WCHS.js.map → chunk-2EJ5YSFZ.js.map} +0 -0
- /package/dist/{chunk-IQGIT2VX.js.map → chunk-3ZVZPYSA.js.map} +0 -0
- /package/dist/{chunk-TXUKTOG2.js.map → chunk-46H2PPG7.js.map} +0 -0
- /package/dist/{chunk-7KNGSQU7.js.map → chunk-4O5XQSCT.js.map} +0 -0
- /package/dist/{chunk-MLIS253L.js.map → chunk-7NYRZI2Z.js.map} +0 -0
- /package/dist/{chunk-GO5IFOUF.js.map → chunk-7USPM2VT.js.map} +0 -0
- /package/dist/{chunk-KIOQ4N37.js.map → chunk-AL2WM6ZZ.js.map} +0 -0
- /package/dist/{chunk-F4NRLLY4.js.map → chunk-AWWFGIBA.js.map} +0 -0
- /package/dist/{chunk-QOCS7W7R.js.map → chunk-D2UGAEXY.js.map} +0 -0
- /package/dist/{chunk-P6ZDXTV6.js.map → chunk-ENF34XNH.js.map} +0 -0
- /package/dist/{chunk-5KS5PWJR.js.map → chunk-GGGO3OH2.js.map} +0 -0
- /package/dist/{chunk-JFLAM3MM.js.map → chunk-GH2JGKWP.js.map} +0 -0
- /package/dist/{chunk-S2PL227Q.js.map → chunk-IE6QX3T3.js.map} +0 -0
- /package/dist/{chunk-LEIAEWZ7.js.map → chunk-JIFG35UT.js.map} +0 -0
- /package/dist/{chunk-DES2LGFZ.js.map → chunk-LQAKDKSF.js.map} +0 -0
- /package/dist/{chunk-SFEQYKYJ.js.map → chunk-MC2SRJXO.js.map} +0 -0
- /package/dist/{chunk-OXLPVQYK.js.map → chunk-T2QHY3S5.js.map} +0 -0
- /package/dist/{chunk-4VODJKFL.js.map → chunk-UCGGVNTD.js.map} +0 -0
- /package/dist/{chunk-AUWGDP4G.js.map → chunk-XPYK7Z73.js.map} +0 -0
- /package/dist/{chunk-JELRWAZC.js.map → chunk-YUZZNS6E.js.map} +0 -0
- /package/dist/{chunks-NUNIKS2J.js.map → chunks-GBPAQ6JM.js.map} +0 -0
- /package/dist/{formula-EPKLPDU7.js.map → formula-EUX2AHXG.js.map} +0 -0
- /package/dist/{formula-NARUOXRX.js.map → formula-IMEE5OJR.js.map} +0 -0
- /package/dist/{image-ocr-3WJ4QH3T.js.map → image-ocr-CCIE3SPX.js.map} +0 -0
- /package/dist/{image-ocr-5BUJQ4TK.js.map → image-ocr-QLW5VL4M.js.map} +0 -0
- /package/dist/{model-bundle-IMBW7D2Z.js.map → model-bundle-VRKRVD6Z.js.map} +0 -0
- /package/dist/{models-SY75IBOE.js.map → models-GSZIPSV2.js.map} +0 -0
- /package/dist/{parser-N6476XAC.js.map → parser-64C45UPQ.js.map} +0 -0
- /package/dist/{parser-ZQM3664Z.js.map → parser-NARS2CF7.js.map} +0 -0
- /package/dist/{pdf-ocr-6DEE23IP.js.map → pdf-ocr-4QWLMFJQ.js.map} +0 -0
- /package/dist/{pdf-ocr-MQTWODVU.js.map → pdf-ocr-ZYRJLOWQ.js.map} +0 -0
- /package/dist/{profile-io-GJPKCYPT.js.map → profile-io-PZBOSV5X.js.map} +0 -0
- /package/dist/{rasterize-UOALJQDS.js.map → rasterize-DXBWM6T2.js.map} +0 -0
- /package/dist/{redact-doc-22SYW3KH.js.map → redact-doc-FLMBZ53F.js.map} +0 -0
- /package/dist/{render-MJ4H3R23.js.map → render-QNWUOQXJ.js.map} +0 -0
- /package/dist/{seal-XWMRUTI4.js.map → seal-NNZUQPDJ.js.map} +0 -0
- /package/dist/{setup-2URYVUEO.js.map → setup-3OR4QZFF.js.map} +0 -0
- /package/dist/{visual-USPS4QRC.js.map → visual-RDGSACGE.js.map} +0 -0
- /package/dist/{watch-ALXZGTOB.js.map → watch-5A52FP6G.js.map} +0 -0
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.ts","../src/mcp/tools-parse.ts","../src/mcp/shared.ts","../src/mcp/tools-form.ts","../src/mcp/tools-render.ts","../src/mcp/tools-generate.ts"],"sourcesContent":["/** kordoc MCP 서버 — Claude/Cursor에서 문서 파싱 도구로 사용. 도구 정의는 mcp/ 아래 도구군 모듈 */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { realpathSync } from \"fs\"\nimport { pathToFileURL } from \"url\"\nimport { VERSION, routeConsoleToStderr } from \"./utils.js\"\nimport { getAccessRoot, isOfflineMode } from \"./shared/offline.js\"\nimport { registerParseTools } from \"./mcp/tools-parse.js\"\nimport { registerFormTools } from \"./mcp/tools-form.js\"\nimport { registerRenderTools } from \"./mcp/tools-render.js\"\nimport { registerGenerateTools } from \"./mcp/tools-generate.js\"\n\nexport { ALLOWED_EXTENSIONS, PARSE_EXTENSIONS, IMAGE_EXTENSIONS, PROFILE_EXTENSIONS, safePath, safeOutputPath, describeError, capResponseText } from \"./mcp/shared.js\"\nexport { buildFillInputs } from \"./mcp/tools-form.js\"\n\nconst server = new McpServer({\n name: \"kordoc\",\n version: VERSION,\n})\n\nregisterParseTools(server)\nregisterFormTools(server)\nregisterRenderTools(server)\nregisterGenerateTools(server)\n\n// ─── 서버 시작 ───────────────────────────────────────\n\n/** MCP 서버 시작 (중복 호출 무해) — kordoc-mcp bin 직접 실행 시 자동, `kordoc mcp` 서브커맨드에선 CLI가 호출 */\nlet serverStarted = false\nexport async function startMcpServer(): Promise<void> {\n if (serverStarted) return\n serverStarted = true\n // stdout 은 JSON-RPC 전용 — pdfjs 등이 console 로 찍는 경고가 프레이밍을 깨지 않게 (parse-worker 와 같은 처리)\n routeConsoleToStderr()\n // 폐쇄망 배포 감사용 — 적용된 제한을 기동 시 1회 stderr 에 남긴다 (stdout 은 MCP 프로토콜 전용)\n const root = getAccessRoot()\n if (isOfflineMode() || root) {\n const flags = [isOfflineMode() ? \"offline\" : null, root ? `root=${root}` : null].filter(Boolean)\n process.stderr.write(`[kordoc-mcp] 제한 모드: ${flags.join(\", \")}\\n`)\n }\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\n// 직접 실행(kordoc-mcp bin / node dist·src mcp)이 아닌 import(테스트의 헬퍼 import)에서는\n// 자동 시작하지 않는다 — stdio 점유로 테스트 러너가 행. 판정 불가 시엔 기존 동작(자동 시작) 유지.\nlet autoStart = true\ntry {\n const entry = process.argv[1]\n if (entry && pathToFileURL(realpathSync(entry)).href !== import.meta.url) autoStart = false\n} catch { /* 판정 실패 → 자동 시작 유지 */ }\n\nif (autoStart) startMcpServer().catch((err) => { console.error(err); process.exit(1) })\n","/** kordoc MCP 도구 — 문서 읽기 — parse_document·detect_format·parse_metadata·parse_pages·parse_table·compare_documents·parse_chunks */\n\nimport { z } from \"zod\"\nimport { parse, detectFormat, detectZipFormat, detectOle2Format, blocksToMarkdown, compare } from \"../index.js\"\nimport { KordocError } from \"../utils.js\"\nimport { extractHwp5MetadataOnly } from \"../hwp5/parser.js\"\nimport { extractHwpxMetadataOnly } from \"../hwpx/parser.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { PARSE_EXTENSIONS, MAX_FILE_SIZE, safePath, describeError, capResponseText, MAX_METADATA_FILE_SIZE, readValidatedFile, detectFormatFromHeader } from \"./shared.js\"\n\nexport function registerParseTools(server: McpServer): void {\n // ─── 도구: parse_document ────────────────────────────\n\n server.tool(\n \"parse_document\",\n \"한국 문서 파일(HWP, HWPX, PDF, XLSX, DOCX)과 이미지(PNG/JPG/WebP)를 마크다운으로 변환합니다. 파일 경로를 입력하면 포맷을 자동 감지하여 텍스트를 추출합니다. 이미지는 OCR(내장 PP-OCRv5)이 자동 적용되고 표 괘선도 복원됩니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로 (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP)\"),\n ocr: z.union([z.boolean(), z.literal(\"force\")]).optional()\n .describe(\"스캔/이미지 PDF 텍스트 OCR (내장 PP-OCRv5 korean, 첫 사용 시 ~18MB 자동 다운로드). true=텍스트층이 없거나 깨진 페이지만 인식하고 정상 페이지는 그대로 둡니다. \\\"force\\\"=텍스트층이 있어도 무시하고 전 페이지 강제 재인식. parse 결과에 NEEDS_OCR 경고가 있으면 이 옵션으로 재시도하세요\"),\n remove_header_footer: z.boolean().optional()\n .describe(\"PDF 머리글/바닥글 자동 제거 (기본 true — false로 끄기, CLI --no-header-footer 대응)\"),\n formula_ocr: z.boolean().optional()\n .describe(\"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드, CLI --formula-ocr 대응)\"),\n dedupe_running_headers: z.boolean().optional()\n .describe(\"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의, CLI --dedupe-headers 대응)\"),\n keep_trailing_empty_cols: z.boolean().optional()\n .describe(\"표 오른쪽 끝 빈 열(서식 입력란) 보존 (#47, 기본 off: 후행 빈 열 트림, CLI --keep-empty-cols 대응)\"),\n keep_empty_paragraphs: z.boolean().optional()\n .describe(\"빈 문단 보존 — 본문은 빈 paragraph 블록, 표 셀은 빈 줄 (#57, 기본 off, CLI --keep-empty-paragraphs 대응)\"),\n include_field_placeholders: z.boolean().optional()\n .describe(\"미기입 누름틀 안내문도 출력 — 빈 서식 문서의 칸 용도 보존 (#92, 기본 off, CLI --include-field-placeholders 대응)\"),\n html_tables: z.boolean().optional()\n .describe(\"모든 표를 HTML 로 — 파이프 표도 HTML 표로, 태그마다 한 줄씩 들여써 냄 (기본 off, CLI --html-tables 대응)\"),\n script_tags: z.boolean().optional()\n .describe(\"위·아래첨자를 <sup>·<sub> 로 표기(\\\"10⁴ m²\\\" 가 \\\"104 m2\\\" 로 펴지지 않게) — 기본: HWPX·HWP·DOCX 켬, PDF 끔(논문·수식 PDF 는 true 권장), false 면 모두 평문. CLI --script-tags / --no-script-tags 대응\"),\n plain: z.boolean().optional()\n .describe(\"평문 Markdown — 그림 자리 표시·링크 URL·밑줄/굵게 표기를 빼고 글만 (제목·목록·표 구조는 유지, 기본 off, CLI --plain 대응)\"),\n password: z.string().optional()\n .describe(\"암호로 보호된 문서의 열기 암호 (#59, HWPX·HWP3·HWP5 지원. 파싱이 ENCRYPTED로 실패하면 이 옵션으로 재시도하세요. 한컴 DRM 보호 문서는 해당 없음)\"),\n tables: z.boolean().optional()\n .describe(\"PDF 표 감지 (기본 true — false로 끄기, CLI --no-tables 대응). 테두리 박스를 표로 오인해 읽기 순서가 뒤집히는 문서(2단 시험지 등)에서 자연 읽기순 텍스트만 뽑습니다 (#64)\"),\n },\n async ({ file_path, ocr, remove_header_footer, formula_ocr, dedupe_running_headers, keep_trailing_empty_cols, keep_empty_paragraphs, include_field_placeholders, html_tables, script_tags, plain, password, tables }) => {\n try {\n const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // 이미지는 파일 참조(image_NNN)로 둔다 — MCP 텍스트 응답에 base64 를 인라인해도\n // 모델은 data URI 를 이미지로 해석하지 못하고, 사진 한 장(≈100KB → base64 133KB)\n // 만으로 클라이언트 도구 응답 한도(Claude Code 기본 25k 토큰)를 넘겨 호출 자체가\n // 깨진다(v3.18.0 회귀). 자체 완결형 마크다운이 필요하면 CLI `--inline-images`.\n // filePath 전달 — 배포용 HWP의 COM fallback에 필요 (CLI와 동일)\n const result = await parse(buffer, {\n filePath: resolved,\n ...(ocr !== undefined ? { ocr } : {}),\n ...(remove_header_footer !== undefined ? { removeHeaderFooter: remove_header_footer } : {}),\n ...(formula_ocr ? { formulaOcr: true } : {}),\n ...(dedupe_running_headers ? { dedupeRunningHeaders: true } : {}),\n ...(keep_trailing_empty_cols ? { keepTrailingEmptyCols: true } : {}),\n ...(keep_empty_paragraphs ? { keepEmptyParagraphs: true } : {}),\n ...(include_field_placeholders ? { includeFieldPlaceholders: true } : {}),\n ...(plain ? { plain: true } : {}),\n ...(script_tags !== undefined ? { scriptTags: script_tags } : {}),\n ...(html_tables ? { htmlTables: true } : {}),\n ...(password ? { password } : {}),\n ...(tables === false ? { tables: false } : {}),\n })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const markdown = result.markdown\n\n const meta = [\n `포맷: ${result.fileType.toUpperCase()}`,\n result.pageCount ? `페이지: ${result.pageCount}` : null,\n result.metadata?.title ? `제목: ${result.metadata.title}` : null,\n result.metadata?.author ? `작성자: ${result.metadata.author}` : null,\n result.isImageBased\n ? (result.warnings?.some(w => w.code === \"OCR_APPLIED\") ? \"이미지 기반 PDF (OCR 적용)\" : \"이미지 기반 PDF (텍스트 추출 불가 — ocr: true 로 재시도 가능)\")\n : null,\n ].filter(Boolean).join(\" | \")\n\n // outline/warnings 부가 정보 추가\n const parts: string[] = [`[${meta}]`]\n\n if (result.outline && result.outline.length > 0) {\n const outlineText = result.outline.map(o => `${\" \".repeat(o.level - 1)}- ${o.text}`).join(\"\\n\")\n parts.push(`\\n📑 문서 구조:\\n${outlineText}`)\n }\n\n if (result.warnings && result.warnings.length > 0) {\n const warnText = result.warnings.map(w => `- [p${w.page || \"?\"}] ${w.message}`).join(\"\\n\")\n parts.push(`\\n⚠️ 경고:\\n${warnText}`)\n }\n\n parts.push(`\\n\\n${markdown}`)\n\n return {\n content: [{ type: \"text\", text: capResponseText(parts.join(\"\")) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: detect_format ─────────────────────────────\n\n server.tool(\n \"detect_format\",\n \"파일의 포맷을 매직 바이트와 컨테이너 내부 구조로 감지합니다 (hwpx, hwp, hwp3, hwpml, pdf, xls, xlsx, docx, pptx, image, unknown). PPTX는 감지만 지원합니다.\",\n {\n file_path: z.string().min(1).describe(\"감지할 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n let format: string = detectFormatFromHeader(resolved)\n // 16바이트 헤더로는 모든 ZIP이 'hwpx'로 나온다 — 파일을 읽어 내부 구조로\n // hwpx/xlsx/docx/pptx 세분화 (parse_metadata와 판정 일치)\n // 크기 상한은 parse_document와 동일(500MB) — 50MB 초과 ZIP 감지 실패 방지\n if (format === \"hwpx\") {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n format = await detectZipFormat(buffer)\n } else if (format === \"hwp\") {\n // OLE2 도 동일하게 세분화 — .xls(Excel 97-2003)를 'hwp'로 보고하던 누락 (parse()와 판정 일치)\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const ole2Format = detectOle2Format(buffer)\n if (ole2Format !== \"unknown\") format = ole2Format\n }\n return {\n content: [{ type: \"text\", text: `${file_path}: ${format}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_metadata ────────────────────────────\n\n server.tool(\n \"parse_metadata\",\n \"문서의 메타데이터(제목, 작성자, 날짜 등)만 빠르게 추출합니다. 전체 파싱 없이 헤더/매니페스트만 읽습니다.\",\n {\n file_path: z.string().min(1).describe(\"메타데이터를 추출할 문서 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n const format = detectFormatFromHeader(resolved)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // metadata 전용 크기 제한 (50MB)\n const { buffer } = await readValidatedFile(file_path, MAX_METADATA_FILE_SIZE, PARSE_EXTENSIONS)\n\n let metadata\n // ZIP(hwpx→xlsx/docx/pptx)·OLE2(hwp→xls) 모두 내부 구조로 세분화 — parse()와 판정 일치\n let effectiveFormat: ReturnType<typeof detectFormat> = format\n if (format === \"hwpx\") {\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat !== \"unknown\") effectiveFormat = zipFormat\n } else if (format === \"hwp\") {\n if (detectOle2Format(buffer) === \"xls\") effectiveFormat = \"xls\"\n }\n switch (effectiveFormat) {\n case \"pptx\":\n throw new KordocError(\"PPTX 파일은 지원하지 않는 파일 형식입니다.\")\n case \"hwp\":\n metadata = extractHwp5MetadataOnly(Buffer.from(buffer))\n break\n case \"hwpx\":\n metadata = await extractHwpxMetadataOnly(buffer)\n break\n case \"pdf\":\n try {\n const { extractPdfMetadataOnly } = await import(\"../pdf/parser.js\")\n metadata = await extractPdfMetadataOnly(buffer)\n } catch {\n metadata = undefined // pdfjs-dist 미설치 시 metadata 생략\n }\n break\n case \"hwp3\":\n case \"hwpml\":\n case \"xls\":\n case \"xlsx\":\n case \"docx\": {\n // 전용 metadata 추출기가 없는 포맷은 전체 파싱 후 metadata 반환\n const result = await parse(buffer)\n metadata = result.success ? result.metadata : undefined\n break\n }\n default:\n // image 등 — 헤더성 메타데이터 없음. 무음 undefined 대신 포맷만 정직하게 반환.\n metadata = undefined\n break\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({ format: effectiveFormat, ...metadata }, null, 2) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_pages ──────────────────────────────\n\n server.tool(\n \"parse_pages\",\n \"문서의 특정 페이지 범위만 파싱합니다. PDF와 한컴 저장본 HWP/HWPX는 실제 페이지 기준(metadata.pageMode=layout), 조판 캐시가 없는 생성 파일은 섹션 단위 근사(pageMode=section)입니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로\"),\n pages: z.string().min(1).describe(\"페이지 범위 (예: '1-3', '1,3,5-7')\"),\n },\n async ({ file_path, pages }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // filePath 전달 — 배포용 HWP의 COM fallback에 필요 (parse_document·parse_chunks와 동일)\n const result = await parse(buffer, { pages, filePath: resolved })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const meta = [\n `포맷: ${result.fileType.toUpperCase()}`,\n `범위: ${pages}`,\n result.pageCount ? `페이지: ${result.pageCount}` : null,\n result.metadata?.pageMode === \"section\" ? \"기준: 섹션 근사\" : null,\n ].filter(Boolean).join(\" | \")\n\n return {\n content: [{ type: \"text\", text: `[${meta}]\\n\\n${result.markdown}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_table ──────────────────────────────\n\n server.tool(\n \"parse_table\",\n \"문서에서 N번째 테이블만 추출합니다 (0-based index). 테이블이 없거나 인덱스 범위를 초과하면 오류를 반환합니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로\"),\n table_index: z.number().int().min(0).describe(\"추출할 테이블 인덱스 (0부터 시작)\"),\n },\n async ({ file_path, table_index }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n const result = await parse(buffer)\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const tableBlocks = result.blocks.filter(b => b.type === \"table\" && b.table)\n if (tableBlocks.length === 0) {\n return {\n content: [{ type: \"text\", text: `문서에 테이블이 없습니다.` }],\n isError: true,\n }\n }\n\n if (table_index >= tableBlocks.length) {\n return {\n content: [{ type: \"text\", text: `테이블 인덱스 초과: ${table_index} (총 ${tableBlocks.length}개 테이블)` }],\n isError: true,\n }\n }\n\n const tableBlock = tableBlocks[table_index]\n const tableMarkdown = blocksToMarkdown([tableBlock])\n\n return {\n content: [{ type: \"text\", text: `[테이블 #${table_index} / 총 ${tableBlocks.length}개]\\n\\n${tableMarkdown}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: compare_documents ─────────────────────────\n\n server.tool(\n \"compare_documents\",\n \"두 한국 문서 파일을 비교하여 추가/삭제/변경된 블록을 표시합니다. 신구대조표 생성에 활용됩니다. 크로스 포맷(HWP↔HWPX) 비교 가능.\",\n {\n file_path_a: z.string().min(1).describe(\"비교 원본 문서의 절대 경로\"),\n file_path_b: z.string().min(1).describe(\"비교 대상 문서의 절대 경로\"),\n },\n async ({ file_path_a, file_path_b }) => {\n try {\n const { buffer: bufA } = await readValidatedFile(file_path_a)\n const { buffer: bufB } = await readValidatedFile(file_path_b)\n\n const result = await compare(bufA, bufB)\n const { stats, diffs } = result\n\n const lines: string[] = [\n `## 문서 비교 결과`,\n `추가: ${stats.added} | 삭제: ${stats.removed} | 변경: ${stats.modified} | 동일: ${stats.unchanged}`,\n \"\",\n ]\n\n for (const d of diffs) {\n const prefix = d.type === \"added\" ? \"+\" : d.type === \"removed\" ? \"-\" : d.type === \"modified\" ? \"~\" : \" \"\n const text = d.after?.text || d.before?.text || (d.after?.table ? \"[테이블]\" : d.before?.table ? \"[테이블]\" : \"\")\n const sim = d.similarity !== undefined ? ` (${(d.similarity * 100).toFixed(0)}%)` : \"\"\n lines.push(`${prefix} ${text.substring(0, 200)}${sim}`)\n }\n\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_chunks ──────────────────────────────\n\n server.tool(\n \"parse_chunks\",\n \"문서를 RAG용 구조 청크 JSON으로 파싱합니다. 헤딩·개조식 위계(□○- / 1.·가.·1))가 breadcrumb 경로로 보존되고 표는 독립 청크로 나옵니다 — 임베딩·인덱싱 전처리용. 자르기(토큰 상한·오버랩)는 소비자 몫입니다.\",\n {\n file_path: z.string().min(1).describe(\"대상 문서의 절대 경로 (HWP/HWPX/PDF/XLSX/DOCX)\"),\n granularity: z.enum([\"section\", \"block\"]).default(\"section\").describe(\"section=같은 breadcrumb 아래 연속 텍스트 병합(기본), block=IRBlock 1개=청크 1개\"),\n include_table_cells: z.boolean().default(false).describe(\"표 청크에 셀 텍스트 2차원 배열 포함 여부\"),\n },\n async ({ file_path, granularity, include_table_cells }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const parsed = await parse(buffer, { filePath: file_path })\n if (!parsed.success) {\n return { content: [{ type: \"text\", text: `파싱 실패: ${parsed.error}` }], isError: true }\n }\n const { blocksToChunks } = await import(\"../chunks.js\")\n const chunks = blocksToChunks(parsed.blocks, { granularity, includeTableCells: include_table_cells })\n return { content: [{ type: \"text\", text: capResponseText(JSON.stringify(chunks, null, 2)) }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `청크 파싱 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 공용 — 경로·확장자 검증, 파일 읽기, 오류 문구, 응답 상한 (도구 모듈 공유) */\n\nimport { realpathSync, openSync, readSync, closeSync, lstatSync, constants } from \"fs\"\nimport { readFile, stat, realpath, open } from \"fs/promises\"\nimport { resolve, isAbsolute, extname, dirname, basename, join } from \"path\"\nimport { detectFormat } from \"../index.js\"\nimport { toArrayBuffer, sanitizeError, classifyError, KordocError } from \"../utils.js\"\nimport { assertWithinRoot } from \"../shared/offline.js\"\n\n/** 허용 파일 확장자 */\nexport const ALLOWED_EXTENSIONS = new Set([\".hwp\", \".hwpx\", \".hml\", \".pdf\", \".xls\", \".xlsx\", \".docx\"])\n/** 파싱 계열 도구(parse_*·detect_format) 입력 확장자 — 문서 + 이미지(자동 OCR).\n * 이미지 3종은 detect.ts 매직바이트 지원 범위와 동일. 쓰기·패치 계열은 ALLOWED_EXTENSIONS 유지 */\nexport const PARSE_EXTENSIONS = new Set([...ALLOWED_EXTENSIONS, \".png\", \".jpg\", \".jpeg\", \".webp\"])\n/** 도장/서명 이미지 허용 확장자 (place_seal image_path) */\nexport const IMAGE_EXTENSIONS = new Set([\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"])\n/** 서식 프로필 허용 확장자 (generate_document profile_path) */\nexport const PROFILE_EXTENSIONS = new Set([\".json\"])\n/** 최대 파일 크기 (500MB) */\nexport const MAX_FILE_SIZE = 500 * 1024 * 1024\n\n/** 경로 정규화 및 보안 검증 */\nexport function safePath(filePath: string, allowedExts: ReadonlySet<string> = ALLOWED_EXTENSIONS): string {\n if (!filePath) throw new KordocError(\"파일 경로가 비어있습니다\")\n const resolved = resolve(filePath)\n let real: string\n try {\n real = realpathSync(resolved)\n } catch (err: any) {\n if (err?.code === \"ENOENT\") throw new KordocError(`파일을 찾을 수 없습니다: ${resolved}`)\n if (err?.code === \"EACCES\" || err?.code === \"EPERM\") throw new KordocError(`파일 접근 권한이 없습니다: ${resolved}`)\n throw new KordocError(`경로 처리 오류 [${err?.code ?? \"UNKNOWN\"}]`)\n }\n if (!isAbsolute(real)) throw new KordocError(\"절대 경로만 허용됩니다\")\n assertWithinRoot(real)\n const ext = extname(real).toLowerCase()\n if (!allowedExts.has(ext)) throw new KordocError(`지원하지 않는 확장자입니다: ${ext} (허용: ${[...allowedExts].join(\", \")})`)\n return real\n}\n\n/**\n * 출력 경로 정규화 및 검증 — 확장자 allowlist + 가장 가까운 실재 조상 realpath (safePath의 쓰기 대응).\n * 종전엔 부모만 realpath 해서 KORDOC_ROOT 안 심볼릭 링크로 쓰기가 샜다(v4.14.4 리뷰 재현): 최종 경로가 밖을 가리키는\n * 링크면 writeFile 이 따라가 덮어썼고, 부모가 없으면 문자열로만 판정해 mkdir(recursive) 가 조상의 디렉토리 링크를\n * 따라가 밖에 만들었다. 그래서 최종 경로가 링크면 거부하고, 실재하는(링크 포함) 가장 가까운 조상을 realpath 로 푼 뒤\n * 남은 세그먼트를 이어 판정한다\n */\nexport function safeOutputPath(outputPath: string, allowedExts: ReadonlySet<string>): string {\n if (!outputPath) throw new KordocError(\"출력 경로가 비어있습니다\")\n const resolved = resolve(outputPath)\n const ext = extname(resolved).toLowerCase()\n if (!allowedExts.has(ext)) {\n throw new KordocError(`지원하지 않는 출력 확장자입니다: ${ext || \"(없음)\"} (허용: ${[...allowedExts].join(\", \")})`)\n }\n const entry = (p: string) => { try { return lstatSync(p) } catch { return null } }\n if (entry(resolved)?.isSymbolicLink()) throw new KordocError(`출력 경로가 심볼릭 링크입니다: ${resolved}`)\n let base = dirname(resolved)\n const rest = [basename(resolved)]\n while (!entry(base) && dirname(base) !== base) {\n rest.unshift(basename(base))\n base = dirname(base)\n }\n let real: string\n try {\n real = resolve(realpathSync(base), ...rest) // 끊긴 링크 조상은 여기서 ENOENT — 거부\n } catch (err: any) {\n throw new KordocError(`출력 경로 처리 오류 [${err?.code ?? \"UNKNOWN\"}]: ${base}`)\n }\n assertWithinRoot(real)\n return real\n}\n\n/** Recheck the output directory after asynchronous processing, then open the leaf without following a late symlink. */\nexport async function writeOutputFile(filePath: string, data: string | Uint8Array, encoding?: BufferEncoding): Promise<void> {\n const parent = await realpath(dirname(filePath))\n assertWithinRoot(parent)\n const target = join(parent, basename(filePath))\n const handle = await open(target, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW, 0o666)\n try {\n await handle.writeFile(data, encoding ? { encoding } : undefined)\n } finally {\n await handle.close()\n }\n}\n\n/**\n * MCP 오류 응답 텍스트 — KordocError는 그대로, fs 계열(ENOENT 등)은 경로 노출 없이\n * 코드별 힌트, 그 외는 classifyError 분류를 병기해 일반화 (\"문서 처리 중 오류\" 뭉개기 방지)\n */\nexport function describeError(err: unknown): string {\n if (err instanceof KordocError) return err.message\n const code = (err as NodeJS.ErrnoException)?.code\n if (typeof code === \"string\" && /^E[A-Z]+$/.test(code)) {\n const hints: Record<string, string> = {\n ENOENT: \"파일 또는 디렉토리를 찾을 수 없습니다\",\n EACCES: \"접근 권한이 없습니다\",\n EPERM: \"작업 권한이 없습니다\",\n EISDIR: \"파일이 아니라 디렉토리입니다\",\n ENOTDIR: \"경로 중간이 디렉토리가 아닙니다\",\n ENOSPC: \"디스크 공간이 부족합니다\",\n }\n return `파일 시스템 오류 [${code}]: ${hints[code] ?? \"경로와 권한을 확인하세요\"}`\n }\n const cls = classifyError(err)\n return cls === \"PARSE_ERROR\" ? sanitizeError(err) : `문서 처리 중 오류가 발생했습니다 (${cls})`\n}\n\n/** MCP 응답 본문 상한 — 사진 몇 장·대형 문서로 클라이언트 도구 응답 한도를 넘기지 않게 */\nexport const MAX_RESPONSE_CHARS = 200_000\nexport function capResponseText(text: string, maxChars = MAX_RESPONSE_CHARS): string {\n if (text.length <= maxChars) return text\n return text.slice(0, maxChars) +\n `\\n\\n… [응답이 ${maxChars.toLocaleString()}자 상한을 넘어 절단됨 (전체 ${text.length.toLocaleString()}자) — parse_pages로 페이지 범위를 나눠 읽으세요]`\n}\n\n/** 최대 파일 크기 — metadata 전용 (50MB, 전체 파싱보다 보수적) */\nexport const MAX_METADATA_FILE_SIZE = 50 * 1024 * 1024\n\n/** 파일 읽기 + 크기 검증 공통 로직 — MCP는 장수 stdio 프로세스라 비동기 I/O (이벤트루프 블로킹 방지) */\nexport async function readValidatedFile(filePath: string, maxSize = MAX_FILE_SIZE, allowedExts: ReadonlySet<string> = ALLOWED_EXTENSIONS): Promise<{ buffer: ArrayBuffer; resolved: string }> {\n const resolved = safePath(filePath, allowedExts)\n let fileSize: number\n try {\n fileSize = (await stat(resolved)).size\n } catch (err: any) {\n throw new KordocError(`파일 상태 읽기 실패 [${err?.code ?? \"UNKNOWN\"}]: ${resolved}`)\n }\n if (fileSize > maxSize) {\n throw new KordocError(`파일이 너무 큽니다: ${(fileSize / 1024 / 1024).toFixed(1)}MB (최대 ${maxSize / 1024 / 1024}MB)`)\n }\n let raw: Buffer\n try {\n raw = await readFile(resolved)\n } catch (err: any) {\n throw new KordocError(`파일 읽기 실패 [${err?.code ?? \"UNKNOWN\"}]: ${resolved}`)\n }\n return { buffer: toArrayBuffer(raw), resolved }\n}\n\n/** 파일 헤더(512바이트)만 읽어 포맷 감지 — 전체 파일 로드 불필요.\n * 16바이트로는 HWP3 매직(30B)·HWPML(<?xml…<HWPML, 최대 512B 윈도)이 안 잡힌다 */\nexport function detectFormatFromHeader(resolved: string): ReturnType<typeof detectFormat> {\n const fd = openSync(resolved, \"r\")\n try {\n const headerBuf = Buffer.alloc(512)\n const bytesRead = readSync(fd, headerBuf, 0, 512, 0)\n return detectFormat(toArrayBuffer(headerBuf.subarray(0, bytesRead)))\n } finally {\n closeSync(fd)\n }\n}\n","/** kordoc MCP 도구 — 서식·편집 — parse_form·fill_form·place_seal·patch_document·redact_document */\n\nimport { z } from \"zod\"\nimport { readFile, mkdir, stat, realpath } from \"fs/promises\"\nimport { extname, dirname } from \"path\"\nimport { parse, detectFormat, detectZipFormat, detectOle2Format, blocksToMarkdown, extractFormFields, fillFormFields, markdownToHwpx, fillHwpx, patchHwpx, patchHwp, BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate } from \"../index.js\"\nimport { fillWithUniqueGuard, type FillInput } from \"../form/match.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { IMAGE_EXTENSIONS, safePath, safeOutputPath, writeOutputFile, describeError, capResponseText, readValidatedFile } from \"./shared.js\"\n\n/** fields + formats 를 FillInput 맵으로 결합 (formats의 라벨은 fields와 동일 표기 기준) */\nexport function buildFillInputs(fields: Record<string, string>, formats?: Record<string, string>): Record<string, FillInput> {\n const out: Record<string, FillInput> = {}\n for (const [k, v] of Object.entries(fields)) {\n const format = formats?.[k]\n out[k] = format ? { value: v, format } : v\n }\n return out\n}\n\n/** 같은 파일인가 — 경로가 같거나(정규화 후) 대소문자 무시 파일시스템·하드링크로 같은 inode */\nasync function isSameFile(a: string, b: string): Promise<boolean> {\n if (a === b) return true\n try {\n const [sa, sb] = await Promise.all([stat(a), stat(b)])\n return sa.ino === sb.ino && sa.dev === sb.dev\n } catch { return false }\n}\n\nexport function registerFormTools(server: McpServer): void {\n // ─── 도구: parse_form ───────────────────────────────\n\n server.tool(\n \"parse_form\",\n \"한국 서식 문서에서 레이블-값 쌍을 구조화된 JSON으로 추출합니다. 양식/서식 문서에 최적화.\",\n {\n file_path: z.string().min(1).describe(\"서식 문서 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const { buffer } = await readValidatedFile(file_path)\n // 서식 입력란(빈 후행 열)이 필드로 잡히도록 보존 (#47)\n const result = await parse(buffer, { keepTrailingEmptyCols: true })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패: ${result.error}` }],\n isError: true,\n }\n }\n\n const form = extractFormFields(result.blocks)\n return {\n content: [{ type: \"text\", text: JSON.stringify(form, null, 2) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: fill_form ───────────────────────────────\n\n server.tool(\n \"fill_form\",\n \"한국 서식 문서의 빈칸을 채워서 새 문서로 출력합니다. hwpx-preserve를 사용하면 원본 서식(테두리, 폰트, 병합 등)을 100% 유지합니다. HWPX 누름틀(CLICK_HERE) 필드는 이름으로 정확 매칭되어 우선 채워집니다. file_path 대신 template으로 내장 정부 표준 기안문 서식을 쓸 수 있습니다 — gian(일반기안문, 별지 제1호서식: 행정기관명·수신자·경유·제목·본문·붙임·발신명의·기안자·검토자·결재권자 등 23필드) / gian-simple(간이기안문, 별지 제2호서식: 내부결재용 13필드).\",\n {\n file_path: z.string().min(1).optional().describe(\"서식 템플릿 문서의 절대 경로 (HWP, HWPX, PDF, XLSX, DOCX). template 사용 시 생략\"),\n template: z.enum([\"gian\", \"gian-simple\", \"일반기안문\", \"간이기안문\"]).optional().describe(\"내장 정부 표준 서식 이름 — file_path 대신 사용. gian=일반기안문(별지 제1호서식), gian-simple=간이기안문(별지 제2호서식)\"),\n fields: z.record(z.string(), z.string()).describe(\"채울 필드 맵 (라벨 → 값). 예: {\\\"성명\\\": \\\"홍길동\\\", \\\"전화번호\\\": \\\"010-1234-5678\\\"}\"),\n formats: z.record(z.string(), z.string()).optional().describe(\"필드별 값 서식 (라벨 → 포맷). 정준값 하나로 서식마다 다른 모양을 채울 때: date:yy.mm.dd / phone:hyphen·dot·digits / rrn:hyphen·masked / mask:###-## / 자유 패턴(yyyy년 m월 d일, ###-####-####)\"),\n require_unique: z.boolean().optional().describe(\"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 — 반복 라벨 양식에서 남의 블록 오염 방지 (배열 값은 예외)\"),\n mask_values: z.boolean().optional().describe(\"응답에 값 대신 글자수만 표시 — 개인정보 채움 시 값이 대화 로그에 남지 않게\"),\n output_format: z.enum([\"markdown\", \"hwpx\", \"hwpx-preserve\"]).default(\"hwpx-preserve\").describe(\"출력 포맷: hwpx-preserve (원본 스타일 보존, HWPX 전용), hwpx (새 HWPX 생성), markdown\"),\n output_path: z.string().optional().describe(\"출력 파일 저장 경로 (선택). 지정 시 파일로 저장, 미지정 시 텍스트로 반환\"),\n },\n async ({ file_path, template, fields, formats, require_unique, mask_values, output_format, output_path }) => {\n try {\n // 출력 경로 사전 검증 (포맷별 확장자 allowlist) — 채우기 전에 실패시킨다\n const outExts = output_format === \"markdown\" ? new Set([\".md\", \".markdown\", \".txt\"]) : new Set([\".hwpx\"])\n const outPath = output_path ? safeOutputPath(output_path, outExts) : undefined\n\n // 입력 소스 — 내장 템플릿(template) 또는 파일 경로(file_path) 중 하나\n let buffer: ArrayBuffer\n if (template) {\n const t = resolveBuiltinTemplate(template)\n if (!t) {\n return {\n content: [{ type: \"text\", text: `알 수 없는 내장 템플릿: ${template} (사용 가능: ${BUILTIN_TEMPLATES.map(x => `${x.id}(${x.aliases[0]})`).join(\", \")})` }],\n isError: true,\n }\n }\n buffer = readBuiltinTemplate(t)\n } else if (file_path) {\n buffer = (await readValidatedFile(file_path)).buffer\n } else {\n return {\n content: [{ type: \"text\", text: \"file_path 또는 template 중 하나를 지정해주세요\" }],\n isError: true,\n }\n }\n\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 (스타일 보존) ───\n if (output_format === \"hwpx-preserve\") {\n // ZIP 은 내부 구조로 세분화한 포맷을 보고한다 — PPTX 를 \"hwpx\" 로 안내하던 오해 방지 (#80).\n // 다른 포맷으로 확인될 때만 거부하고, 판별 불가(손상 ZIP 등)는 종전대로 HWPX 로 시도\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n const isHwpx = format === \"hwpx\"\n if (!isHwpx) {\n return {\n content: [{ type: \"text\", text: `hwpx-preserve는 HWPX 파일만 지원합니다 (감지된 포맷: ${format}). hwpx 또는 markdown을 사용하세요.` }],\n isError: true,\n }\n }\n\n const inputs = buildFillInputs(fields, formats)\n const hwpxResult = require_unique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(buffer, vals, blocked))\n : { ...(await fillHwpx(buffer, inputs)), rejected: [] as string[] }\n // 마스킹 verify — 채운 결과를 재파싱해 값이 실제 문서에 있는지만 확인 (값 미노출)\n let verifyLine: string | null = null\n if (mask_values && hwpxResult.filled.length > 0) {\n const reparsed = await parse(Buffer.from(hwpxResult.buffer))\n // 마크다운 이스케이프(\\*,\\|,\\~ 등)·개행/연속공백 정규화 후 비교 — rrn:masked\n // ('900315-1******')의 * 이스케이프로 생기던 결정적 false negative 방지.\n // 빈 값은 includes('')===true 로 항상 통과하던 것을 FILLED 에서 제외한다.\n const norm = (s: string): string => s.replace(/\\\\([\\\\`*_{}[\\]()#+.!|~>-])/g, \"$1\").replace(/\\s+/g, \" \")\n const normMd = reparsed.success ? norm(reparsed.markdown) : \"\"\n const okCount = reparsed.success\n ? hwpxResult.filled.filter(f => f.value !== \"\" && normMd.includes(norm(f.value))).length\n : 0\n verifyLine = `검증(마스킹): ${okCount}/${hwpxResult.filled.length} FILLED — 재파싱 대조, 값 미노출`\n }\n const summary = [\n `채워진 필드: ${hwpxResult.filled.length}개 (원본 스타일 보존)`,\n hwpxResult.rejected.length > 0 ? `모호 라벨 거부(2곳+ 매칭): ${hwpxResult.rejected.join(\", \")}` : null,\n hwpxResult.unmatched.length > 0 ? `매칭 실패: ${hwpxResult.unmatched.join(\", \")}` : null,\n verifyLine,\n ].filter(Boolean).join(\" | \")\n\n const filledList = hwpxResult.filled\n .map(f => ` - ${f.label}: ${mask_values ? `[${[...f.value].length}자]` : f.value}`).join(\"\\n\")\n\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(hwpxResult.buffer))\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n채워진 필드:\\n${filledList}\\n\\nHWPX 파일 저장 (원본 서식 유지): ${outPath}` }],\n }\n }\n\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n채워진 필드:\\n${filledList}\\n\\n⚠️ output_path를 지정하면 원본 서식이 유지된 HWPX 파일로 저장됩니다.` }],\n }\n }\n\n // ─── 일반 경로: parse → fill → output ─── (양식 입력란 보존, #47)\n const result = await parse(buffer, { keepTrailingEmptyCols: true })\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패: ${result.error}` }],\n isError: true,\n }\n }\n\n const formInfo = extractFormFields(result.blocks)\n const irInputs = buildFillInputs(fields, formats)\n const fillResult = require_unique\n ? await fillWithUniqueGuard(irInputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked))\n : { ...fillFormFields(result.blocks, irInputs), rejected: [] as string[] }\n\n if (fillResult.filled.length === 0 && formInfo.fields.length === 0) {\n return {\n content: [{ type: \"text\", text: `서식 필드를 찾을 수 없습니다. 일반 문서이거나 서식 패턴이 감지되지 않았습니다.` }],\n isError: true,\n }\n }\n\n const markdown = blocksToMarkdown(fillResult.blocks)\n // mask_values 시 채운 값(주민번호·연락처 등)이 응답(대화 로그)에 노출되지 않게\n // 본문 미리보기를 안내 문구로 대체 (sfill-8). 값은 output_path 파일에만 기록된다.\n const previewMd = mask_values\n ? \"⚠️ mask_values 활성 — 개인정보 노출 방지를 위해 본문을 응답에 포함하지 않습니다. output_path 로 파일 저장 후 확인하세요.\"\n : markdown\n const summary = [\n `채워진 필드: ${fillResult.filled.length}개`,\n fillResult.rejected.length > 0 ? `모호 라벨 거부(2곳+ 매칭): ${fillResult.rejected.join(\", \")}` : null,\n fillResult.unmatched.length > 0 ? `매칭 실패: ${fillResult.unmatched.join(\", \")}` : null,\n formInfo.fields.length > 0 ? `서식 필드: ${formInfo.fields.length}개 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)` : null,\n ].filter(Boolean).join(\" | \")\n\n if (output_format === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(hwpxBuffer))\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\nHWPX 파일 저장: ${outPath}` }],\n }\n }\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n⚠️ output_path를 지정하면 HWPX 파일로 저장됩니다. 미리보기:\\n\\n${previewMd}` }],\n }\n }\n\n // markdown\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, markdown, \"utf-8\")\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n마크다운 파일 저장: ${outPath}\\n\\n${previewMd}` }],\n }\n }\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n${previewMd}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: place_seal ─────────────────────────────\n\n server.tool(\n \"place_seal\",\n \"도장/서명 이미지를 앵커 문구(\\\"(인)\\\"·\\\"서명 또는 인\\\" 등) 위에 부유(글 앞) 배치합니다. 표/페이지를 키우지 않습니다 (HWPX 전용).\",\n {\n file_path: z.string().min(1).describe(\"대상 HWPX 문서의 절대 경로\"),\n image_path: z.string().min(1).describe(\"도장/서명 이미지 절대 경로 (투명 배경 PNG 권장)\"),\n anchor: z.string().default(\"(인)\").describe(\"앵커 문구 — 이 문구 기준으로 배치\"),\n occurrence: z.number().int().min(0).default(0).describe(\"같은 앵커가 여럿일 때 0-based 선택\"),\n size_mm: z.number().positive().optional().describe(\"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\"),\n mode: z.enum([\"overlap\", \"right\", \"auto\"]).default(\"auto\").describe(\"overlap=문구 위 겹침, right=문구 오른쪽 옆, auto=공간 있으면 right\"),\n dx_mm: z.number().optional().describe(\"x 미세조정 mm\"),\n dy_mm: z.number().optional().describe(\"y 미세조정 mm\"),\n output_path: z.string().min(1).describe(\"출력 HWPX 저장 경로\"),\n },\n async ({ file_path, image_path, anchor, occurrence, size_mm, mode, dx_mm, dy_mm, output_path }) => {\n try {\n const outPath = safeOutputPath(output_path, new Set([\".hwpx\"]))\n const { buffer } = await readValidatedFile(file_path)\n const format = detectFormat(buffer)\n if (format !== \"hwpx\") {\n return {\n content: [{ type: \"text\", text: `place_seal 은 HWPX 파일만 지원합니다 (감지된 포맷: ${format}).` }],\n isError: true,\n }\n }\n // 이미지 경로도 문서와 동일하게 검증 (realpath + 확장자 allowlist)\n const imgResolved = safePath(image_path, IMAGE_EXTENSIONS)\n const imgSize = (await stat(imgResolved)).size\n if (imgSize > 500 * 1024 * 1024) {\n return { content: [{ type: \"text\", text: `도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB) — 500MB 이하여야 합니다.` }], isError: true }\n }\n const image = new Uint8Array(await readFile(imgResolved))\n const ext = extname(imgResolved).slice(1).toLowerCase() as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\"\n const { placeSealHwpx } = await import(\"../form/seal.js\")\n const result = await placeSealHwpx(buffer, [{\n anchor, occurrence, image, ext,\n sizeMm: size_mm, mode, dxMm: dx_mm, dyMm: dy_mm,\n }])\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(result.buffer))\n const p0 = result.placed[0]\n const warnLines = (p0.warnings ?? []).map(w => `\\n⚠️ ${w}`).join(\"\")\n return {\n content: [{\n type: \"text\",\n text: `도장 배치 완료: \"${p0.anchor}\" #${p0.occurrence} → ${p0.mode} (x ${p0.posXMm}mm, y ${p0.posYMm}mm, ${p0.sizeMm}mm각, ${p0.entry})\\n저장: ${outPath}${warnLines}\\n표/페이지 불확장(글 앞 부유) — 한컴에서 위치 확인 후 dx_mm/dy_mm 로 미세조정 가능합니다.`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `도장 배치 실패: ${describeError(err)}` }],\n isError: true,\n }\n }\n },\n )\n\n // ─── 도구: patch_document ────────────────────────────\n\n server.tool(\n \"patch_document\",\n \"원본 HWPX/HWP의 서식(글꼴·표·도장칸·이미지)을 1바이트도 건드리지 않고, 편집된 마크다운의 바뀐 텍스트만 제자리 치환해 새 문서로 출력합니다. parse_document로 얻은 마크다운을 수정해 넘기세요 — 양식 빈칸 채우기·문구 수정에 적합하며 한컴 한글에서 변조 경고 없이 열립니다. (블록 추가/삭제·표 구조 변경은 미지원, 미적용 항목은 결과에 보고)\",\n {\n file_path: z.string().min(1).describe(\"원본 문서의 절대 경로 (HWPX 또는 HWP 5.x)\"),\n edited_markdown: z.string().min(1).describe(\"parse_document 출력 마크다운을 편집한 전체 마크다운. 바뀐 문단/셀 텍스트만 반영하고 블록 수·순서는 원본과 같게 유지하세요\"),\n output_path: z.string().min(1).describe(\"출력 파일 저장 절대 경로 (원본과 같은 확장자: .hwpx 또는 .hwp)\"),\n },\n async ({ file_path, edited_markdown, output_path }) => {\n try {\n const out = safeOutputPath(output_path, new Set([\".hwpx\", \".hwp\"]))\n const { buffer } = await readValidatedFile(file_path)\n // ZIP(hwpx/xlsx/docx/pptx)·OLE2(hwp/xls) 모두 내부 구조로 세분화한 포맷으로 판정·안내 (#80).\n // 다른 포맷으로 확인될 때만 거부 — 판별 불가(손상 컨테이너 등)는 종전대로 HWPX/HWP 패처가 판단한다\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n else if (format === \"hwp\") { const o = detectOle2Format(buffer); if (o !== \"unknown\") format = o }\n const isHwpx = format === \"hwpx\"\n if (!isHwpx && format !== \"hwp\") {\n return {\n content: [{ type: \"text\", text: `patch_document는 HWPX 또는 HWP 5.x만 지원합니다 (감지된 포맷: ${format}).` }],\n isError: true,\n }\n }\n\n const original = new Uint8Array(buffer)\n const result = isHwpx\n ? await patchHwpx(original, edited_markdown)\n : await patchHwp(original, edited_markdown)\n\n if (!result.success || !result.data) {\n return {\n content: [{ type: \"text\", text: `패치 실패: ${result.error ?? \"알 수 없는 오류\"}` }],\n isError: true,\n }\n }\n\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, Buffer.from(result.data))\n\n const v = result.verification?.stats\n const lossless = v ? (v.modified === 0 && v.added === 0 && v.removed === 0) : undefined\n const lines = [\n `✓ ${result.applied}개 변경 적용 (${isHwpx ? \"HWPX\" : \"HWP\"}, 원본 서식 보존) → ${out}`,\n lossless === true ? \"검증: 편집 내용과 재파싱 결과 완전 일치\" :\n lossless === false ? `검증 잔차: 수정 ${v!.modified} · 추가 ${v!.added} · 삭제 ${v!.removed} (반영 안 된 편집 있음)` : null,\n result.skipped.length > 0\n ? `미적용 ${result.skipped.length}건:\\n` + result.skipped.map(s => ` - ${s.reason}`).join(\"\\n\")\n : null,\n ].filter(Boolean)\n\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: redact_document ───────────────────────────\n\n server.tool(\n \"redact_document\",\n \"문서의 개인정보(주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허, rules 로 인명·주소 opt-in)를 탐지해 서식 보존 마스킹합니다. HWPX/HWP는 원본 서식 그대로 같은 길이로 가린 파일 — 본문·표·중첩표·머리말/꼬리말·각주·글상자·필드·미리보기(텍스트·이미지)·문서 정보(제목·작성자)까지 가리고, 저장 전 결과 파일을 다시 훑어 남은 PII를 보고합니다. 그 외 포맷(PDF·DOCX·XLSX 등)은 원본을 건드리지 않고 마스킹된 마크다운만 출력합니다. 자동 검출 보조 도구 — 결과 리포트를 사람이 최종 확인해야 하며 이미지 속 글자는 탐지하지 못합니다. 마스킹 후 render_document로 눈으로 확인하는 것을 권장합니다.\",\n {\n file_path: z.string().min(1).describe(\"대상 문서의 절대 경로\"),\n rules: z.array(z.enum([\"rrn\", \"phone\", \"email\", \"card\", \"account\", \"brn\", \"passport\", \"driver\", \"crn\", \"ip\", \"name\", \"address\"])).optional()\n .describe(\"적용 룰 (기본: rrn·phone·email·card·account·brn·passport·driver — crn(법인등록번호)·ip·name(인명, 문맥 게이트)·address(주소)는 opt-in)\"),\n mask_char: z.string().min(1).max(1).optional().describe(\"마스크 문자 1글자 (기본: ●)\"),\n output_path: z.string().min(1).optional().describe(\"출력 경로 (HWPX/HWP는 같은 확장자, 그 외는 .md) — dry_run이 아니면 필수\"),\n dry_run: z.boolean().default(false).describe(\"탐지 리포트만 반환, 파일 미생성\"),\n },\n async ({ file_path, rules, mask_char, output_path, dry_run }) => {\n try {\n const { buffer, resolved } = await readValidatedFile(file_path)\n // ZIP·OLE 내부 구조까지 세분화 — PPTX·XLS 를 hwpx·hwp 로 보고 확장자를 잘못 요구하지 않게 (#80)\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n else if (format === \"hwp\") { const o = detectOle2Format(buffer); if (o !== \"unknown\") format = o }\n const patchable = format === \"hwpx\" || format === \"hwp\"\n if (!dry_run && !output_path) {\n return { content: [{ type: \"text\", text: \"output_path가 필요합니다 (탐지만 원하면 dry_run: true).\" }], isError: true }\n }\n const outPath = !dry_run\n ? safeOutputPath(output_path!, new Set(patchable ? [format === \"hwp\" ? \".hwp\" : \".hwpx\"] : [\".md\", \".markdown\", \".txt\"]))\n : undefined\n if (outPath && await isSameFile(outPath, resolved)) {\n return { content: [{ type: \"text\", text: \"output_path가 입력 파일과 같습니다 — 원본을 덮어쓰지 않습니다. 다른 경로를 지정하세요.\" }], isError: true }\n }\n const { redactDocument } = await import(\"../redact-doc.js\")\n const r = await redactDocument(buffer, { rules, maskChar: mask_char, filePath: file_path, dryRun: dry_run })\n // HWPX/HWP 는 파일 안 위치 기준, 그 외는 본문 마크다운 기준. 명단 수천 행이면 응답이 넘치므로 자른다\n const MAX_LINES = 50\n const listed = r.fileHits.length > 0\n ? r.fileHits.map(h => ` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})`)\n : r.markdownHits.map(h => ` - [${h.rule}] ${h.masked}`)\n const byRule = new Map<string, number>()\n for (const h of r.fileHits.length > 0 ? r.fileHits : r.markdownHits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\n const grouped = new Map<string, number>()\n for (const l of listed) grouped.set(l, (grouped.get(l) ?? 0) + 1)\n const groupedLines = [...grouped].map(([l, n]) => n > 1 ? `${l} ×${n}` : l)\n const lines = [\n `탐지: ${[...byRule.values()].reduce((a, b) => a + b, 0)}건 (${[...byRule.entries()].map(([k, v]) => `${k} ${v}`).join(\", \") || \"없음\"})`,\n ...groupedLines.slice(0, MAX_LINES),\n ...(groupedLines.length > MAX_LINES ? [` … 외 ${groupedLines.length - MAX_LINES}줄`] : []),\n ]\n // HWPX/HWP 는 결과 바이트가 원본과 다르면 저장 (탐지 0건이어도 미할당 영역을 비웠으면 저장),\n // 그 외 포맷은 본문에서 찾은 게 있을 때 마스킹된 마크다운을 저장\n const save = r.data ? r.changed : r.markdownHits.length > 0\n if (!dry_run && save) {\n await mkdir(dirname(outPath!), { recursive: true })\n if (r.data) {\n await writeOutputFile(outPath!, Buffer.from(r.data))\n lines.push(`저장: ${outPath} (원본 서식 보존)`)\n } else {\n await writeOutputFile(outPath!, r.markdown, \"utf-8\")\n lines.push(`저장: ${outPath} (${r.format} 원본은 수정하지 않음 — 마스킹된 마크다운)`)\n }\n } else if (!dry_run) {\n lines.push(listed.length > 0 ? \"❌ 파일에서 가린 곳이 없어 출력 파일을 만들지 않았습니다.\" : \"탐지 0건 — 출력 파일을 만들지 않았습니다.\")\n }\n const failed = r.residual.length > 0 || r.unscanned.length > 0\n if (r.residual.length > 0) {\n lines.push(`❌ 마스킹 후 재검사에서 PII ${r.residual.length}건이 남아 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요:`)\n for (const h of r.residual.slice(0, MAX_LINES)) lines.push(` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})`)\n if (r.residual.length > MAX_LINES) lines.push(` … 외 ${r.residual.length - MAX_LINES}건`)\n }\n if (r.unscanned.length > 0) lines.push(`❌ 글자를 검사하지 못한 곳이 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요: ${r.unscanned.join(\", \")}`)\n if (!failed && r.data && save) lines.push(\"재검사: 결과 파일 전체(본문·머리말·각주·미리보기·메타데이터·미할당 영역)와 다시 읽은 본문에서 남은 PII 0건\")\n for (const w of r.warnings) lines.push(`⚠️ ${w}`)\n if (r.data && save) lines.push(\"render_document로 마스킹 결과를 눈으로 확인하세요.\")\n lines.push(\"주의: 자동 검출은 보조 수단입니다. 이미지 속 텍스트·표기 변형·이름·주소는 놓칠 수 있으니 최종 공개 전 사람 검토가 필요합니다.\")\n return { content: [{ type: \"text\", text: capResponseText(lines.join(\"\\n\")) }], ...(failed ? { isError: true } : {}) }\n } catch (err) {\n return { content: [{ type: \"text\", text: `마스킹 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 도구 — 렌더 — render_document·crop_regions·extract_tables */\n\nimport { z } from \"zod\"\nimport { mkdir } from \"fs/promises\"\nimport { dirname, join } from \"path\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { MAX_FILE_SIZE, safeOutputPath, writeOutputFile, describeError, readValidatedFile } from \"./shared.js\"\n\nexport function registerRenderTools(server: McpServer): void {\n // ─── 도구: render_document ───────────────────────────\n\n server.tool(\n \"render_document\",\n \"HWPX·HWP 문서를 실제 조판 그대로 렌더해 PNG/JPEG 이미지로 응답하거나 SVG·HTML·PDF 파일로 저장합니다. generate_document·fill_form·patch_document·place_seal 결과물을 눈으로 확인하는 용도 — 생성/수정 후 이 도구로 렌더해 깨짐·잘림·배치를 검증하고 다시 고치는 루프를 권장합니다. 한컴 저장본(HWPX·HWP 모두)은 조판 캐시로 정확히, AI 생성본(캐시 없음)은 순수 조판 엔진(reflow)으로 렌더되며 후자는 한컴 실조판의 근사입니다 (참고용 미리보기).\",\n {\n file_path: z.string().min(1).describe(\"렌더할 HWPX 또는 HWP(5.x) 파일의 절대 경로\"),\n format: z.enum([\"png\", \"jpeg\", \"svg\", \"html\", \"pdf\"]).default(\"png\").describe(\"png/jpeg=이미지로 응답에 직접 반환(output_path 는 선택) / svg·html·pdf=output_path 에 파일 저장(필수). svg 는 pages 미지정 HWPX 면 전체 세로 스택 1파일, 그 외 페이지별 파일. html=자급자족 레이아웃 HTML 1파일, pdf=Chromium 필요\"),\n output_path: z.string().min(1).optional().describe(\"결과 저장 경로 (확장자는 format 과 일치 — .png/.jpg/.svg/.html/.pdf). 페이지별 산출은 _page_NNN 접미\"),\n highlights: z.array(z.string().min(1)).optional().describe(\"형광펜 표시할 검색어 목록 — 채운 값·수정 문구 위치 확인용\"),\n reflow_mode: z.enum([\"keep\", \"charAll\"]).default(\"keep\").describe(\"reflow 줄바꿈: keep=어절 단위, charAll=글자 단위\"),\n pages: z.string().min(1).optional().describe(\"페이지 선택(1-based: '3', '1-3', '1,3,7-9') — 지정하면 페이지별 산출(이미지 응답은 최대 8쪽). HWPX png/svg 에서 미지정이면 전체를 세로 스택 1장으로\"),\n max_width_px: z.number().int().min(200).max(4000).optional().describe(\"래스터(png/jpeg) 최대 폭 px — 큰 문서 응답 부피 조절\"),\n },\n async ({ file_path, format, output_path, highlights, reflow_mode, pages, max_width_px }) => {\n try {\n const EXT: Record<string, string[]> = { png: [\".png\"], jpeg: [\".jpg\", \".jpeg\"], svg: [\".svg\"], html: [\".html\", \".htm\"], pdf: [\".pdf\"] }\n const needsFile = format === \"svg\" || format === \"html\" || format === \"pdf\"\n if (needsFile && !output_path) {\n return { content: [{ type: \"text\", text: `format: \"${format}\" 은 output_path(${EXT[format][0]})가 필수입니다 — 원문은 커서 응답에 직접 담지 않습니다.` }], isError: true }\n }\n const outPath = output_path ? safeOutputPath(output_path, new Set(EXT[format])) : undefined\n const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const isHwp5 = resolved.toLowerCase().endsWith(\".hwp\")\n if (!isHwp5 && !pages && (format === \"png\" || format === \"svg\")) {\n // 종전 동작(HWPX·pages 미지정): 전 페이지 세로 스택 1장/1파일\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n // reflow는 조판 캐시가 있으면 무시되므로 항상 켠다 — 한컴본·생성본 모두 커버\n const result = await renderHwpxToSvg(buffer, { highlights, reflow: true, reflowMode: reflow_mode })\n const summary = [\n `렌더 완료: ${result.pageCount}페이지, ${Math.round(result.width)}x${Math.round(result.height)}pt (텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables})`,\n ...result.warnings.map(w => `⚠️ ${w}`),\n ]\n if (format === \"svg\") {\n await mkdir(dirname(outPath!), { recursive: true })\n await writeOutputFile(outPath!, result.svg, \"utf-8\")\n summary.push(`저장: ${outPath}`)\n return { content: [{ type: \"text\", text: summary.join(\"\\n\") }] }\n }\n const { rasterizeSvg } = await import(\"../render/rasterize.js\")\n const raster = await rasterizeSvg(result.svg, result.width, result.height, max_width_px ? { maxWidthPx: max_width_px } : undefined)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, raster.png)\n summary.push(`저장: ${outPath}`)\n }\n summary.push(`이미지 ${raster.widthPx}x${raster.heightPx}px — 잘림·겹침·빈칸·페이지 넘침이 보이면 원인 텍스트를 수정해 다시 생성/패치하세요.`)\n return {\n content: [\n { type: \"image\", data: raster.png.toString(\"base64\"), mimeType: \"image/png\" },\n { type: \"text\", text: summary.join(\"\\n\") },\n ],\n }\n }\n // 통합 렌더러(renderDocument) — 페이지별 산출. HWP5 는 항상 이 경로\n const { renderDocument } = await import(\"../render/index.js\")\n const { scene, assets } = await renderDocument(buffer, { format, pages, highlights, reflow: true, reflowMode: reflow_mode, maxWidthPx: max_width_px })\n const summary = [\n `렌더 완료: 문서 ${scene.pages.length}페이지 중 ${assets.filter(a => a.page !== undefined).length || 1}건 (텍스트 ${scene.stats.texts}·이미지 ${scene.stats.images}·표 ${scene.stats.tables}·도형 ${scene.stats.shapes})`,\n ...scene.warnings.map(w => `⚠️ ${w}`),\n ]\n const suffixed = (p: string, page: number) => p.replace(/(\\.[^.]+)$/, `_page_${String(page).padStart(3, \"0\")}$1`)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n for (const a of assets) {\n const p = a.page === undefined || assets.length === 1 ? outPath : suffixed(outPath, a.page)\n await writeOutputFile(p, a.data as Buffer | string)\n summary.push(`저장: ${p}`)\n }\n }\n if (format === \"png\" || format === \"jpeg\") {\n const MAX_PAGES = 8\n const shown = assets.slice(0, MAX_PAGES)\n if (assets.length > MAX_PAGES) summary.push(`⚠️ ${MAX_PAGES}쪽까지만 응답에 담았습니다 — pages 를 좁히세요`)\n return {\n content: [\n ...shown.map(a => ({ type: \"image\" as const, data: (a.data as Buffer).toString(\"base64\"), mimeType: format === \"jpeg\" ? \"image/jpeg\" : \"image/png\" })),\n { type: \"text\", text: summary.join(\"\\n\") },\n ],\n }\n }\n return { content: [{ type: \"text\", text: summary.join(\"\\n\") }] }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `렌더 실패: ${describeError(err)}` }],\n isError: true,\n }\n }\n },\n )\n\n // ─── 도구: crop_regions ──────────────────────────────\n\n server.tool(\n \"crop_regions\",\n \"HWPX·HWP 문서를 렌더해 표·이미지·문단·도형 영역을 페이지 이미지에서 잘라 파일로 저장합니다(render_document 와 같은 조판 엔진, 페이지 로컬 pt bbox 를 실배율로 환산). 표가 진짜 데이터표인지 조직도인지는 판단하지 않습니다(그건 extract_tables) — 렌더러가 아는 개체를 자를 뿐. 결과: output_dir/<유형>_<번호>_page_<쪽>.png + regions.json(id·유형·페이지·bbox pt).\",\n {\n file_path: z.string().min(1).describe(\"HWPX 또는 HWP(5.x) 파일 절대 경로\"),\n output_dir: z.string().min(1).describe(\"crop 파일 저장 디렉토리\"),\n target: z.array(z.enum([\"table\", \"image\", \"paragraph\", \"shape\"])).default([\"table\"]).describe(\"잘라낼 개체 유형\"),\n format: z.enum([\"png\", \"jpeg\"]).default(\"png\"),\n pages: z.string().min(1).optional().describe(\"대상 페이지(1-based 범위)\"),\n padding_pt: z.number().min(0).max(100).default(0).describe(\"bbox 둘레 여백 pt\"),\n },\n async ({ file_path, output_dir, target, format, pages, padding_pt }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const dir = safeOutputPath(join(output_dir, \"regions.json\"), new Set([\".json\"])).replace(/[\\\\/]regions\\.json$/, \"\")\n const { extractRenderedRegions } = await import(\"../render/index.js\")\n const regions = await extractRenderedRegions(buffer, { types: target, format, pages, paddingPt: padding_pt, reflow: true })\n await mkdir(dir, { recursive: true })\n const ext = format === \"jpeg\" ? \"jpg\" : \"png\"\n const manifest = []\n for (const r of regions) {\n const name = `${r.region.id.replace(\"-\", \"_\")}_page_${String(r.page).padStart(3, \"0\")}.${ext}`\n await writeOutputFile(join(dir, name), r.data)\n manifest.push({ file: name, id: r.region.id, type: r.region.type, sourceId: r.region.sourceId, parentId: r.region.parentId, page: r.page, bbox: r.bbox, widthPx: r.widthPx, heightPx: r.heightPx })\n }\n await writeOutputFile(join(dir, \"regions.json\"), JSON.stringify(manifest, null, 2))\n return { content: [{ type: \"text\", text: `crop ${regions.length}건 → ${dir}\\n` + manifest.map(m => `${m.file} p${m.page} (${m.bbox.x},${m.bbox.y} ${m.bbox.width}×${m.bbox.height}pt)${m.sourceId ? ` src=${m.sourceId}` : \"\"}`).join(\"\\n\") }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `crop 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n\n // ─── 도구: extract_tables ────────────────────────────\n\n server.tool(\n \"extract_tables\",\n \"HWPX·HWP 문서의 표를 추출·분류합니다(#76). 표마다 semantic-table(데이터표) / non-tabular-layout(조직도·연락망·결재란처럼 표를 캔버스로 쓴 것) / uncertain 분류와 근거 신호, 페이지·bbox(pt, 렌더 region 조인), 정책(visual)에 따른 crop 이미지를 돌려줍니다 — 조직도는 이미지로, 데이터표는 셀 구조로 넘기는 멀티모달 파이프라인용. 휴리스틱(네트워크·LLM 없음), 중첩표도 독립 분류. crop 은 output_dir 에 저장하고 8장까지 응답에 함께 담습니다.\",\n {\n file_path: z.string().min(1).describe(\"HWPX 또는 HWP(5.x) 파일 절대 경로\"),\n output_dir: z.string().min(1).optional().describe(\"crop 파일·tables.json 저장 디렉토리 (visual 이 none 이 아니면 필수)\"),\n visual: z.enum([\"none\", \"non-tabular\", \"non-tabular-and-uncertain\", \"all\"]).default(\"none\").describe(\"crop 대상: none=분류·bbox 만 / non-tabular=조직도류만 / non-tabular-and-uncertain(권장) / all\"),\n format: z.enum([\"png\", \"jpeg\"]).default(\"png\"),\n padding_pt: z.number().min(0).max(100).default(0).describe(\"crop 둘레 여백 pt\"),\n cells: z.boolean().default(false).describe(\"응답 JSON 에 셀 텍스트 격자 포함\"),\n },\n async ({ file_path, output_dir, visual, format, padding_pt, cells }) => {\n try {\n if (visual !== \"none\" && !output_dir) {\n return { content: [{ type: \"text\", text: \"visual 이 none 이 아니면 crop 파일을 저장할 output_dir 이 필요합니다.\" }], isError: true }\n }\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const dir = output_dir ? safeOutputPath(join(output_dir, \"tables.json\"), new Set([\".json\"])).replace(/[\\\\/]tables\\.json$/, \"\") : undefined\n const { extractTables } = await import(\"../table/visual.js\")\n const tables = await extractTables(buffer, { policy: visual, format, paddingPt: padding_pt })\n if (dir) await mkdir(dir, { recursive: true })\n const ext = format === \"jpeg\" ? \"jpg\" : \"png\"\n const images: Array<{ type: \"image\"; data: string; mimeType: string }> = []\n const report = []\n for (const t of tables) {\n const crops = []\n for (const c of t.crops) {\n const name = `${t.id.replace(/[^\\w.-]/g, \"_\")}_page_${String(c.page).padStart(3, \"0\")}.${ext}`\n if (dir) await writeOutputFile(join(dir, name), c.data)\n if (images.length < 8) images.push({ type: \"image\", data: c.data.toString(\"base64\"), mimeType: c.mimeType })\n crops.push({ file: dir ? name : undefined, page: c.page, bbox: c.bbox })\n }\n report.push({\n id: t.id, sourceId: t.sourceId, page: t.page, classification: t.classification,\n table: { rows: t.table.rows, cols: t.table.cols, hasHeader: t.table.hasHeader, caption: t.table.caption, ...(cells ? { cells: t.table.cells.map(r => r.map(c => c.text)) } : {}) },\n regions: t.regions, crops, warnings: t.warnings,\n })\n }\n const json = JSON.stringify(report, null, 2)\n if (dir) await writeOutputFile(join(dir, \"tables.json\"), json + \"\\n\")\n const kinds = report.reduce<Record<string, number>>((m, r) => { m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1; return m }, {})\n const head = `표 ${report.length}개 (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(\", \") || \"없음\"}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}건${dir ? ` → ${dir}` : \"\"}${images.length < report.reduce((n, r) => n + r.crops.length, 0) ? \" (응답에는 8장까지)\" : \"\"}`\n return { content: [...images, { type: \"text\", text: `${head}\\n${json}` }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `표 추출 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 도구 — 생성 — extract_profile·generate_document */\n\nimport { z } from \"zod\"\nimport { readFile, mkdir, realpath } from \"fs/promises\"\nimport { resolve, dirname, join } from \"path\"\nimport { markdownToHwpx, unknownFontWarnings, usesGaejosikMunche, PRESET_ALIAS, incompatibleGongmunWarnings, gongmunLintWarnings, muncheLintWarnings } from \"../index.js\"\nimport type { GongmunOptions } from \"../index.js\"\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS, FONT_ROLE_KEYS, SIZE_KEYS, DOC_HEAD_KEYS, DOC_FOOT_KEYS, DOC_INFO_KEYS, NOTICE_HEAD_KEYS, PRESS_CONTACT_KEYS, BODY_PT_RANGE, LINE_SPACING_RANGE, SIZE_PT_RANGE, APPROVAL_MAX, LEVEL_STYLE_KEYS } from \"../hwpx/gongmun-surface.js\"\nimport { assertWithinRoot } from \"../shared/offline.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { PROFILE_EXTENSIONS, safePath, safeOutputPath, writeOutputFile, describeError, readValidatedFile } from \"./shared.js\"\n\nexport function registerGenerateTools(server: McpServer): void {\n // ─── 도구: extract_profile ───────────────────────────\n\n server.tool(\n \"extract_profile\",\n \"참조 HWPX 문서에서 표 서식 프로필(테두리·음영·열 너비·셀 글꼴)을 JSON으로 추출합니다. 추출한 프로필을 generate_document의 profile_path로 넘기면 원본 문서 없이 같은 표 서식을 재현합니다 — \\\"이 문서 표 서식 그대로 만들어줘\\\" 워크플로의 1단계.\",\n {\n hwpx_path: z.string().min(1).describe(\"서식을 추출할 참조 HWPX 파일의 절대 경로\"),\n output_path: z.string().min(1).describe(\"프로필 JSON 출력 절대 경로 (.json 권장)\"),\n },\n async ({ hwpx_path, output_path }) => {\n try {\n const out = safeOutputPath(output_path, PROFILE_EXTENSIONS)\n const { buffer } = await readValidatedFile(hwpx_path)\n const { hwpxToProfile } = await import(\"../index.js\")\n const profile = await hwpxToProfile(buffer)\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, JSON.stringify(profile, null, 2))\n return {\n content: [{ type: \"text\", text: `서식 프로필 추출 완료: 표 ${profile.tables.length}개 → ${out}\\n(generate_document의 profile_path로 사용)` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n server.tool(\n \"generate_document\",\n \"마크다운을 HWPX 한글 문서로 생성합니다. \\\"보고서로/공문서로/개조식으로/계획서로 뽑아줘·만들어줘\\\" 요청이 이 도구입니다. 프리셋 매핑: 정부 표준 보고서(표지·목차·로마숫자 장헤더 자동)='개조식', 중앙부처 업무보고·국회 서면보고(재경부 실측: 장 띠·절 숫자칸·소제목 박스·① 항목 띠·연노랑 성과 요약박스·별첨 띠, □ 뒤 (키워드) 파랑)='업무보고', 지방자치단체 방침서·추진계획(서울시 시장방침 실측: 제목표·파랑 부제·요약박스·[Ⅰ] 장 상자·절 띠)='서울방침' — 보고서·계획서를 만들 때 정부(업무보고)형과 지방(서울방침)형 중 무엇으로 할지 불명확하면 사용자에게 물어보세요, 기안문·시행문·알림공문='기안문', 1페이지 요약보고서='보고서', 추진계획='계획서'. 표는 실측 정부 서식(헤더 음영+이중선·외곽 굵은선·내용 비례 열폭), 쪽번호·결재란·'끝.' 표시 지원. ⚠ 생성 전 확인 권장: 문서종류(보고서/기안문)·제목·기관명(org)·날짜·목차 여부가 불명확하면 사용자에게 물어보세요 — 엉뚱한 프리셋 선택이 가장 흔한 오생성 원인. 마크다운 규칙(v4.13 서울 실결재 실측 위계): #(h1)=문서 제목, ##(h2)=장(보고서 Ⅰ Ⅱ / 기안문·통지는 법정 1.), ###(h3)=□ 대항목(기안문 가.), 그 아래 리스트=ㅇ → - → ㆍ(기안문 가. → 1) → 가)), 본문에 □/ㅇ/-/1./가. 를 직접 써도 같은 위계로 정규화, ※시작·'출처:'·'자료:'=참고(13pt), 제목 직후 인용문(>)=보고서 요약박스 — ★보고서는 반드시 제목 직후 `> …하고자 함` 한 문장(쉼표 허용·부호 없음·3줄 이내 약 90~100자)로 보고 목적을 넣을 것(없거나 3줄 초과면 경고), <right>텍스트</right>=우측정렬. □·제목은 한 줄에 자동 축소, 본문은 어절 단위 줄바꿈(낱말·날짜가 줄 끝에서 안 쪼개짐)·부호 뒤 탭 정렬(둘째 줄이 첫 줄 내용과 같은 위치), 마지막 줄이 짧은 고아 줄과 공백이 크게 벌어지는 줄은 자간 축소로 정리, 곧은따옴표는 ‘’“”로. 법령 코드 (282791)·KOSIS 표 ID DT_…·(법정동코드 …)·○○ MCP 조회 같은 내부 식별자·도구 언급은 자동 제거 — 출처는 기관·자료명만 쓸 것. (원본 서식 보존 제자리 수정은 patch_document, 서식 빈칸 채우기는 fill_form)\",\n {\n markdown: z.string().min(1).describe(\"HWPX로 변환할 마크다운 전문. 표는 GFM 문법 사용 (예: '| 이름 | 부서 |\\\\n| --- | --- |\\\\n| 홍길동 | 기획팀 |')\"),\n output_path: z.string().min(1).describe(\"출력 HWPX 파일의 절대 경로 (.hwpx 권장)\"),\n profile_path: z.string().optional().describe(\"서식 프로필 JSON 경로 (extract_profile로 추출) — 참조 문서의 표 테두리·음영·열폭·셀 글꼴을 재현. 표 행·열 수와 첫 셀 텍스트가 일치하는 표에만 적용\"),\n // 값 집합·범위는 gongmun-surface SSOT에서 파생 (CLI와 드리프트 불가 — v4.0.4 영역1-1)\n preset: z.enum(Object.keys(PRESET_ALIAS) as [string, ...string[]]).optional()\n .describe(\"공문서 프리셋 — 지정 시 한국 행정 공문서 표준 서식 적용. '개조식'=정부 표준 개조식 보고서(표지·목차·로마숫자 장 헤더 자동 + □○-※ 부호별 폰트), '업무보고'=중앙부처 업무보고(##=Ⅰ 장 띠, ###=파란 숫자칸 절, ####=남색 소제목 박스, #####=① 하늘색 항목 띠, > ▪…=연노랑 성과 요약박스, ## 별첨 …=별첨 띠, ❶⇒ 부호 보존, 함초롬바탕 15·각주 맑은 고딕 12), '서울방침'=서울시 방침서(# 제목 뒤 '- 부제 -' 줄=파랑 부제·☎ 줄=담당자 행·> =요약박스, ##=[Ⅰ] 장 상자, ###=파란 번호 절 띠, ####=❶ 과제 소제목, □ HY견고딕 17·ㅇ 한컴돋움 15 굵게·- 휴먼명조 14·▸ 13, 줄간격 200%), '보도자료'=머리박스+제목 25pt+□→ㅇ→*(각주) 체계. 미지정 시 범용 마크다운 변환\"),\n font: z.enum(BODY_FONTS).optional().describe(\"본문 글꼴(공문서 모드): myeongjo=명조 계열(개조식·보고서·계획서는 실측 휴먼명조, 그 외 함초롬바탕), gothic=맑은 고딕\"),\n body_pt: z.number().int().min(BODY_PT_RANGE.min).max(BODY_PT_RANGE.max).optional().describe(\"본문 글자 크기(pt, 공문서 모드). 기본: 기안문 12, 보고서·계획서·통지 15\"),\n line_spacing: z.number().int().min(LINE_SPACING_RANGE.min).max(LINE_SPACING_RANGE.max).optional().describe(\"본문 줄간격(%, 공문서 모드). 기본: 프리셋별 실측값(기안문 160, 회의록 130 등)\"),\n org: z.string().optional().describe(\"표지 기관명 (표지를 켜는 모든 프리셋에서 사용 가능). 미지정 시 표지에 기관명 생략\"),\n date: z.string().optional().describe(\"표지 날짜 ('YYYY. M. D.' 표기 권장). 미지정 시 오늘 날짜\"),\n toc: z.boolean().optional().describe(\"목차 페이지 생성 여부 — h2 목록을 Ⅰ Ⅱ Ⅲ 장으로 자동 구성. 전 프리셋 사용 가능(보도자료 제외). 미지정 시 개조식 프리셋만 켜짐\"),\n cover: z.boolean().optional().describe(\"표지 페이지 생성 여부 — 첫 h1을 제목으로 파랑 장식 표지. 전 프리셋 사용 가능(보도자료 제외 — 머리박스 서식과 양립 불가). 미지정 시 개조식 프리셋만 켜짐 (org/date 지정 시 자동 켜짐)\"),\n approval: z.array(z.string()).max(APPROVAL_MAX).optional().describe(\"결재란 직위 라벨 (최대 6개, 예: ['담당','팀장','과장']) — 문서 최상단 우측에 서명 공란 결재 표 생성\"),\n page_numbers: z.boolean().optional().describe(\"쪽번호(하단 중앙 '- 1 -', 표지·목차 카운트 제외). 미지정 시 개조식·보고서·계획서 켜짐\"),\n end_mark: z.boolean().optional().describe(\"본문 끝 '끝.' 표시 (행정업무규정). 미지정 시 기안문만 켜짐, 본문이 이미 '끝.'으로 끝나면 중복 생성 안 함\"),\n body_title_box: z.boolean().optional().describe(\"본문 첫 페이지 제목 반복 박스 (개조식 실측 관행). 미지정 시 개조식+표지 조합에서 켜짐\"),\n chapter_fit: z.boolean().optional().describe(\"개조식 장 헤더 제목 칸을 글자 폭에 맞춤. 미지정 시 제목 칸이 본문 폭까지\"),\n h2_marker: z.enum(H2_MARKERS).optional().describe(\"h2 장 제목 표기: band=로마자 채움 칸+제목 띠 표(보고서·계획서 기본), roman='Ⅰ. 제목' 텍스트, number='1. 제목'(통지 기본), box=장 없이 □ 대항목으로, none=번호 없음. 기안문 본문의 h2는 항상 법정 '1.' 항목\"),\n band_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(\"띠 제목 번호칸 채움색 #RRGGBB (기본 #003366 실측 최다. 교육청형 밝은 띠는 #DFE6F7 + band_text_color #000000)\"),\n band_text_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(\"띠 제목 번호 글자색 #RRGGBB (기본 #FFFFFF)\"),\n summary: z.string().optional().describe(\"보고서 요약 박스 — 제목표 아래 #DFE6F7 음영 상자(서울 실결재 관행). 마크다운 제목 직후 인용문(> …)으로도 지정 가능\"),\n doc_info: z.object(Object.fromEntries(DOC_INFO_KEYS.map(k => [k, z.string().optional()]))).optional().describe(\"보고서 표지 문서정보표 — docNum=문서번호/date=결재일자/disclosure=공개여부/policyNo=방침번호 (cover=true와 함께)\"),\n checklist: z.union([z.boolean(), z.object({ na: z.array(z.number().int()).optional(), notes: z.record(z.string(), z.string()).optional() })]).optional()\n .describe(\"서울 사전 검토항목 점검표(표지 다음 쪽, 보고서·계획서·서울방침) — true=표시 없는 빈 서식, {na:[6,7,…]}=적은 문항(1~14)은 해당없음·나머지 검토완료, notes={\\\"7\\\":\\\"교육\\\"}=비고\"),\n dept: z.string().optional().describe(\"표지 부서명 — 기관명 아래 '(스마트도시과)' (cover와 함께)\"),\n cover_label: z.string().optional().describe(\"표지 우상단 취급 표시 — '대외주의'·'비공개' 빨간 테두리 박스 (업무보고 프리셋 실측, cover와 함께)\"),\n fonts: z.object(Object.fromEntries(FONT_ROLE_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"요소별 글꼴 오버라이드(공문서 모드) — body=본문(○·-)/heading=제목 계열(□·장헤더·표지·목차)/ref=※ 참고/table=표 셀. 개조식·보고서·계획서는 네 역할 전부, 그 외 프리셋은 body만 적용\"),\n sizes: z.object(Object.fromEntries(SIZE_KEYS.map(k => [k, z.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional()])))\n .optional().describe(\"개조식 요소별 글자 크기(pt) 오버라이드 — dae=□/cham=※/chapter=장헤더/coverTitle·coverSub=표지/tocLabel·tocRoman·tocItem=목차/table=표 셀/bodyTitle=본문 첫 페이지 제목 반복 박스. 미지정 요소는 body_pt 비례 기본값\"),\n levels: z.record(z.string().regex(/^[0-7]$/), z.object(Object.fromEntries(LEVEL_STYLE_KEYS.map(k => [k, k === \"pt\" ? z.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional() : k === \"bold\" ? z.boolean().optional() : z.string().optional()]))))\n .optional().describe(\"항목부호 단계별 위계 타이포(공문서 모드, v4.12.3) — {\\\"0\\\":{font:\\\"HY견고딕\\\",pt:17,bold:true},\\\"1\\\":{font:\\\"한컴돋움\\\",bold:true}} 꼴(depth 0~7). 실측: 전자결재 기안문 □/ㅇ/- 계열은 □=HY견고딕 +2~3pt 굵게·ㅇ=한컴돋움 굵게·-=휴먼명조 본문. 법정 8단계(1. 가.)는 본문 동일이 관행이라 기본 미적용\"),\n bullet2: z.enum(BULLET2_CHARS).optional().describe(\"2단계 항목부호 — 'ㅇ'(이응, 전자결재 기안문·공고문 실측 지배) / '○'(원, 보고서 양식). 미지정 시 통지·보도자료 ㅇ, 그 외 ○\"),\n suppress_single: z.boolean().optional().describe(\"단일 형제 항목 부호 생략(편람 규정, 법정 번호 standard 전용 — 불릿 체계인 보고서·계획서·개조식·보도자료엔 무효). 기본 false — 하나뿐인 항목에도 부호(1. 가.)를 부여 (부호 없는 계단 들여쓰기가 실무 눈에 어색)\"),\n doc_head: z.object(Object.fromEntries(DOC_HEAD_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"기안문 두문표(별지 제1호서식·서울 실결재 6행 표) — org=행정기관명(굴림 20pt bold 자간띄움)/slogan=원훈(상단 10pt)/to=수신('내부결재'면 발신명의 생략)/via=경유/title=제목(미지정 시 첫 h1). 기안문 프리셋 전용\"),\n doc_foot: z.object(Object.fromEntries(DOC_FOOT_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"기안문 결문표 — sender=발신명의(18pt bold 중앙)/drafter·reviewer·approver='직위 성명' 결재선/cooperator=협조자/recipients=수신자 목록/docNum=시행 '과-번호 (날짜)'/receive=접수/zip·address·site/phone·fax·email/disclosure=공개구분. 기안문 프리셋 전용\"),\n report_info: z.string().optional().describe(\"보고서: 제목표 아래 담당자 행 '(2026. 9. 6., 스마트도시과 홍길동, ☎450-1234)' / 기안문: 우상단 12pt 보고정보 행\"),\n notice_head: z.object(Object.fromEntries(NOTICE_HEAD_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"공고문 두문·결문 — no=공고번호(본문 위 bold)/date=날짜(본문 아래 우측)/sender=발신명의(우측 bold). 통지 프리셋 전용\"),\n press: z.object({\n release: z.string().optional(), distribute: z.string().optional(),\n sub: z.array(z.string()).optional(),\n contact: z.object(Object.fromEntries(PRESS_CONTACT_KEYS.map(k => [k, z.string().optional()]))).optional(),\n }).optional().describe(\"보도자료 옵션 — release=보도시점/distribute=배포일(머리박스)/sub=부제 배열('- … -')/contact=담당 부서·담당자·연락처 표\"),\n paper: z.enum([\"A4\", \"A3\", \"B4\", \"B5\", \"Letter\"]).optional().describe(\"용지 크기 (v4.5.0). 기본 A4\"),\n landscape: z.boolean().optional().describe(\"용지 가로 방향 (v4.5.0). 기본 세로\"),\n columns: z.number().int().min(1).max(8).optional().describe(\"다단 개수 (v4.5.0). 기본 1단\"),\n header: z.string().optional().describe(\"머리말 텍스트 — 모든 쪽 상단, 인라인 마크다운 허용 (v4.5.0)\"),\n footer: z.string().optional().describe(\"꼬리말 텍스트 — 모든 쪽 하단 (v4.5.0)\"),\n image_dir: z.string().optional().describe(\"마크다운 이미지 참조()를 이 디렉토리에서 읽어 실데이터 임베드 (v4.5.0, PNG/JPEG/GIF/BMP). 미지정 시 참조만 placeholder로 보존\"),\n },\n async ({ markdown, output_path, profile_path, preset, font, body_pt, line_spacing, org, date, toc, cover, approval, page_numbers, end_mark, body_title_box, chapter_fit, h2_marker, band_color, band_text_color, summary, doc_info, checklist, dept, cover_label, fonts, sizes, levels, bullet2, suppress_single, doc_head, doc_foot, report_info, notice_head, press, paper, landscape, columns, header, footer, image_dir }) => {\n try {\n // 조립은 gongmun-surface SSOT(buildGongmunOptions) — CLI와 의미론 공유 (v4.0.4)\n let gongmun: GongmunOptions | undefined\n if (preset) {\n gongmun = buildGongmunOptions({\n preset: PRESET_ALIAS[preset], font, bodyPt: body_pt, lineSpacing: line_spacing,\n org, date, cover, toc, approval,\n pageNumbers: page_numbers, endMark: end_mark, bodyTitleBox: body_title_box, chapterFit: chapter_fit,\n h2Marker: h2_marker, bandColor: band_color, bandTextColor: band_text_color, fonts, sizes, levels, bullet2, suppressSingle: suppress_single,\n docHead: doc_head, docFoot: doc_foot, reportInfo: report_info,\n noticeHead: notice_head, press, summary, docInfo: doc_info, dept, coverLabel: cover_label,\n checklist: checklist && typeof checklist === \"object\" ? { na: checklist.na, notes: checklist.notes && Object.fromEntries(Object.entries(checklist.notes).map(([k, v]) => [Number(k), v])) } : checklist,\n })\n }\n // 서식 프로필 (이슈 #41) — 경로 검증(realpath + .json) 후 경계 zod 검증 (CLI --profile과 공유 스키마)\n let profile: import(\"../hwpx/gen-profile.js\").FormatProfile | undefined\n if (profile_path) {\n const { parseFormatProfileJson } = await import(\"../hwpx/profile-io.js\")\n profile = parseFormatProfileJson(await readFile(safePath(profile_path, PROFILE_EXTENSIONS), \"utf-8\"))\n }\n const out = safeOutputPath(output_path, new Set([\".hwpx\"]))\n // 페이지 옵션 (v4.5.0)\n const page = paper || landscape || columns || header || footer\n ? {\n ...(paper ? { size: paper } : {}),\n ...(landscape ? { orientation: \"landscape\" as const } : {}),\n ...(columns ? { columns } : {}),\n ...(header ? { header } : {}),\n ...(footer ? { footer } : {}),\n }\n : undefined\n // 이미지 실데이터 (v4.5.0) — 안전한 파일명 참조만 디렉토리에서 읽는다\n let images: Record<string, Uint8Array> | undefined\n if (image_dir) {\n const dir = await realpath(resolve(image_dir))\n assertWithinRoot(dir)\n for (const m of markdown.matchAll(/!\\[[^\\]]*\\]\\(([^)\\s]+)\\)/g)) {\n const url = m[1]\n if (!/^[A-Za-z0-9._-]+\\.[A-Za-z0-9]+$/.test(url) || url.includes(\"..\")) continue\n try {\n images ??= {}\n images[url] = new Uint8Array(await readFile(join(dir, url)))\n } catch { /* 파일 없음 — placeholder 유지 */ }\n }\n }\n const genWarnings: string[] = []\n const buf = await markdownToHwpx(markdown, gongmun || profile || page || images\n ? {\n ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}),\n ...(page ? { page } : {}), ...(images ? { images } : {}),\n warnings: genWarnings,\n }\n : undefined)\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, Buffer.from(buf))\n\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\n const tableCount = (markdown.match(/^\\s*\\|.*\\|\\s*$/gm) || []).length > 0\n ? `, 표 포함` : \"\"\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행, 경고만 병기.\n // 프리셋 비호환 옵션(조용한 폐기)·편람 표기법 검수도 같은 채널로 병기\n const fontWarns = gongmun?.fonts ? unknownFontWarnings(gongmun.fonts) : []\n if (gongmun) fontWarns.push(...incompatibleGongmunWarnings(gongmun))\n if (gongmun) fontWarns.push(...gongmunLintWarnings(markdown, 5))\n // 개조식 문체 검수 — 보고서·계획서·개조식 프리셋만 (기안문 경어체 등에는 미적용)\n if (gongmun && usesGaejosikMunche(gongmun.preset)) fontWarns.push(...muncheLintWarnings(markdown, 5))\n fontWarns.push(...genWarnings)\n const warnText = fontWarns.length ? `\\n⚠ ${fontWarns.join(\"\\n⚠ \")}` : \"\"\n return {\n content: [{ type: \"text\", text: `✓ HWPX 생성 (${mode}${tableCount}) → ${out}\\n크기: ${(buf.byteLength / 1024).toFixed(1)}KB${warnText}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n}\n"],"mappings":"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","names":["realpathSync","server","z","readFile","stat","extname","dirname","stat","server","z","summary","dirname","readFile","extname","z","mkdir","dirname","join","server","z","summary","mkdir","dirname","join","z","readFile","mkdir","realpath","resolve","dirname","join","server","z","mkdir","dirname","readFile","realpath","resolve","join","realpathSync"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts","../src/mcp/tools-parse.ts","../src/mcp/shared.ts","../src/mcp/tools-form.ts","../src/mcp/tools-render.ts","../src/mcp/tools-generate.ts"],"sourcesContent":["/** kordoc MCP 서버 — Claude/Cursor에서 문서 파싱 도구로 사용. 도구 정의는 mcp/ 아래 도구군 모듈 */\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"\nimport { realpathSync } from \"fs\"\nimport { pathToFileURL } from \"url\"\nimport { VERSION, routeConsoleToStderr } from \"./utils.js\"\nimport { getAccessRoot, isOfflineMode } from \"./shared/offline.js\"\nimport { registerParseTools } from \"./mcp/tools-parse.js\"\nimport { registerFormTools } from \"./mcp/tools-form.js\"\nimport { registerRenderTools } from \"./mcp/tools-render.js\"\nimport { registerGenerateTools } from \"./mcp/tools-generate.js\"\n\nexport { ALLOWED_EXTENSIONS, PARSE_EXTENSIONS, IMAGE_EXTENSIONS, PROFILE_EXTENSIONS, safePath, safeOutputPath, describeError, capResponseText } from \"./mcp/shared.js\"\nexport { buildFillInputs } from \"./mcp/tools-form.js\"\n\nconst server = new McpServer({\n name: \"kordoc\",\n version: VERSION,\n})\n\nregisterParseTools(server)\nregisterFormTools(server)\nregisterRenderTools(server)\nregisterGenerateTools(server)\n\n// ─── 서버 시작 ───────────────────────────────────────\n\n/** MCP 서버 시작 (중복 호출 무해) — kordoc-mcp bin 직접 실행 시 자동, `kordoc mcp` 서브커맨드에선 CLI가 호출 */\nlet serverStarted = false\nexport async function startMcpServer(): Promise<void> {\n if (serverStarted) return\n serverStarted = true\n // stdout 은 JSON-RPC 전용 — pdfjs 등이 console 로 찍는 경고가 프레이밍을 깨지 않게 (parse-worker 와 같은 처리)\n routeConsoleToStderr()\n // 폐쇄망 배포 감사용 — 적용된 제한을 기동 시 1회 stderr 에 남긴다 (stdout 은 MCP 프로토콜 전용)\n const root = getAccessRoot()\n if (isOfflineMode() || root) {\n const flags = [isOfflineMode() ? \"offline\" : null, root ? `root=${root}` : null].filter(Boolean)\n process.stderr.write(`[kordoc-mcp] 제한 모드: ${flags.join(\", \")}\\n`)\n }\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\n// 직접 실행(kordoc-mcp bin / node dist·src mcp)이 아닌 import(테스트의 헬퍼 import)에서는\n// 자동 시작하지 않는다 — stdio 점유로 테스트 러너가 행. 판정 불가 시엔 기존 동작(자동 시작) 유지.\nlet autoStart = true\ntry {\n const entry = process.argv[1]\n if (entry && pathToFileURL(realpathSync(entry)).href !== import.meta.url) autoStart = false\n} catch { /* 판정 실패 → 자동 시작 유지 */ }\n\nif (autoStart) startMcpServer().catch((err) => { console.error(err); process.exit(1) })\n","/** kordoc MCP 도구 — 문서 읽기 — parse_document·detect_format·parse_metadata·parse_pages·parse_table·compare_documents·parse_chunks */\n\nimport { z } from \"zod\"\nimport { parse, detectFormat, detectZipFormat, detectOle2Format, blocksToMarkdown, compare } from \"../index.js\"\nimport { KordocError } from \"../utils.js\"\nimport { extractHwp5MetadataOnly } from \"../hwp5/parser.js\"\nimport { extractHwpxMetadataOnly } from \"../hwpx/parser.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { PARSE_EXTENSIONS, MAX_FILE_SIZE, safePath, describeError, capResponseText, MAX_METADATA_FILE_SIZE, readValidatedFile, detectFormatFromHeader } from \"./shared.js\"\n\nexport function registerParseTools(server: McpServer): void {\n // ─── 도구: parse_document ────────────────────────────\n\n server.tool(\n \"parse_document\",\n \"한국 문서 파일(HWP, HWPX, PDF, XLSX, DOCX)과 이미지(PNG/JPG/WebP)를 마크다운으로 변환합니다. 파일 경로를 입력하면 포맷을 자동 감지하여 텍스트를 추출합니다. 이미지는 OCR(내장 PP-OCRv5)이 자동 적용되고 표 괘선도 복원됩니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로 (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP)\"),\n ocr: z.union([z.boolean(), z.literal(\"force\")]).optional()\n .describe(\"스캔/이미지 PDF 텍스트 OCR (내장 PP-OCRv5 korean, 첫 사용 시 ~18MB 자동 다운로드). true=텍스트층이 없거나 깨진 페이지만 인식하고 정상 페이지는 그대로 둡니다. \\\"force\\\"=텍스트층이 있어도 무시하고 전 페이지 강제 재인식. parse 결과에 NEEDS_OCR 경고가 있으면 이 옵션으로 재시도하세요\"),\n remove_header_footer: z.boolean().optional()\n .describe(\"PDF 머리글/바닥글 자동 제거 (기본 true — false로 끄기, CLI --no-header-footer 대응)\"),\n formula_ocr: z.boolean().optional()\n .describe(\"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드, CLI --formula-ocr 대응)\"),\n dedupe_running_headers: z.boolean().optional()\n .describe(\"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의, CLI --dedupe-headers 대응)\"),\n keep_trailing_empty_cols: z.boolean().optional()\n .describe(\"표 오른쪽 끝 빈 열(서식 입력란) 보존 (#47, 기본 off: 후행 빈 열 트림, CLI --keep-empty-cols 대응)\"),\n keep_empty_paragraphs: z.boolean().optional()\n .describe(\"빈 문단 보존 — 본문은 빈 paragraph 블록, 표 셀은 빈 줄 (#57, 기본 off, CLI --keep-empty-paragraphs 대응)\"),\n include_field_placeholders: z.boolean().optional()\n .describe(\"미기입 누름틀 안내문도 출력 — 빈 서식 문서의 칸 용도 보존 (#92, 기본 off, CLI --include-field-placeholders 대응)\"),\n html_tables: z.boolean().optional()\n .describe(\"모든 표를 HTML 로 — 파이프 표도 HTML 표로, 태그마다 한 줄씩 들여써 냄 (기본 off, CLI --html-tables 대응)\"),\n script_tags: z.boolean().optional()\n .describe(\"위·아래첨자를 <sup>·<sub> 로 표기(\\\"10⁴ m²\\\" 가 \\\"104 m2\\\" 로 펴지지 않게) — 기본: HWPX·HWP·DOCX 켬, PDF 끔(논문·수식 PDF 는 true 권장), false 면 모두 평문. CLI --script-tags / --no-script-tags 대응\"),\n plain: z.boolean().optional()\n .describe(\"평문 Markdown — 그림 자리 표시·링크 URL·밑줄/굵게 표기를 빼고 글만 (제목·목록·표 구조는 유지, 기본 off, CLI --plain 대응)\"),\n password: z.string().optional()\n .describe(\"암호로 보호된 문서의 열기 암호 (#59, HWPX·HWP3·HWP5 지원. 파싱이 ENCRYPTED로 실패하면 이 옵션으로 재시도하세요. 한컴 DRM 보호 문서는 해당 없음)\"),\n tables: z.boolean().optional()\n .describe(\"PDF 표 감지 (기본 true — false로 끄기, CLI --no-tables 대응). 테두리 박스를 표로 오인해 읽기 순서가 뒤집히는 문서(2단 시험지 등)에서 자연 읽기순 텍스트만 뽑습니다 (#64)\"),\n },\n async ({ file_path, ocr, remove_header_footer, formula_ocr, dedupe_running_headers, keep_trailing_empty_cols, keep_empty_paragraphs, include_field_placeholders, html_tables, script_tags, plain, password, tables }) => {\n try {\n const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // 이미지는 파일 참조(image_NNN)로 둔다 — MCP 텍스트 응답에 base64 를 인라인해도\n // 모델은 data URI 를 이미지로 해석하지 못하고, 사진 한 장(≈100KB → base64 133KB)\n // 만으로 클라이언트 도구 응답 한도(Claude Code 기본 25k 토큰)를 넘겨 호출 자체가\n // 깨진다(v3.18.0 회귀). 자체 완결형 마크다운이 필요하면 CLI `--inline-images`.\n // filePath 전달 — 배포용 HWP의 COM fallback에 필요 (CLI와 동일)\n const result = await parse(buffer, {\n filePath: resolved,\n ...(ocr !== undefined ? { ocr } : {}),\n ...(remove_header_footer !== undefined ? { removeHeaderFooter: remove_header_footer } : {}),\n ...(formula_ocr ? { formulaOcr: true } : {}),\n ...(dedupe_running_headers ? { dedupeRunningHeaders: true } : {}),\n ...(keep_trailing_empty_cols ? { keepTrailingEmptyCols: true } : {}),\n ...(keep_empty_paragraphs ? { keepEmptyParagraphs: true } : {}),\n ...(include_field_placeholders ? { includeFieldPlaceholders: true } : {}),\n ...(plain ? { plain: true } : {}),\n ...(script_tags !== undefined ? { scriptTags: script_tags } : {}),\n ...(html_tables ? { htmlTables: true } : {}),\n ...(password ? { password } : {}),\n ...(tables === false ? { tables: false } : {}),\n })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const markdown = result.markdown\n\n const meta = [\n `포맷: ${result.fileType.toUpperCase()}`,\n result.pageCount ? `페이지: ${result.pageCount}` : null,\n result.metadata?.title ? `제목: ${result.metadata.title}` : null,\n result.metadata?.author ? `작성자: ${result.metadata.author}` : null,\n result.isImageBased\n ? (result.warnings?.some(w => w.code === \"OCR_APPLIED\") ? \"이미지 기반 PDF (OCR 적용)\" : \"이미지 기반 PDF (텍스트 추출 불가 — ocr: true 로 재시도 가능)\")\n : null,\n ].filter(Boolean).join(\" | \")\n\n // outline/warnings 부가 정보 추가\n const parts: string[] = [`[${meta}]`]\n\n if (result.outline && result.outline.length > 0) {\n const outlineText = result.outline.map(o => `${\" \".repeat(o.level - 1)}- ${o.text}`).join(\"\\n\")\n parts.push(`\\n📑 문서 구조:\\n${outlineText}`)\n }\n\n if (result.warnings && result.warnings.length > 0) {\n const warnText = result.warnings.map(w => `- [p${w.page || \"?\"}] ${w.message}`).join(\"\\n\")\n parts.push(`\\n⚠️ 경고:\\n${warnText}`)\n }\n\n parts.push(`\\n\\n${markdown}`)\n\n return {\n content: [{ type: \"text\", text: capResponseText(parts.join(\"\")) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: detect_format ─────────────────────────────\n\n server.tool(\n \"detect_format\",\n \"파일의 포맷을 매직 바이트와 컨테이너 내부 구조로 감지합니다 (hwpx, hwp, hwp3, hwpml, pdf, xls, xlsx, docx, pptx, image, unknown). PPTX는 감지만 지원합니다.\",\n {\n file_path: z.string().min(1).describe(\"감지할 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n let format: string = detectFormatFromHeader(resolved)\n // 16바이트 헤더로는 모든 ZIP이 'hwpx'로 나온다 — 파일을 읽어 내부 구조로\n // hwpx/xlsx/docx/pptx 세분화 (parse_metadata와 판정 일치)\n // 크기 상한은 parse_document와 동일(500MB) — 50MB 초과 ZIP 감지 실패 방지\n if (format === \"hwpx\") {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n format = await detectZipFormat(buffer)\n } else if (format === \"hwp\") {\n // OLE2 도 동일하게 세분화 — .xls(Excel 97-2003)를 'hwp'로 보고하던 누락 (parse()와 판정 일치)\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const ole2Format = detectOle2Format(buffer)\n if (ole2Format !== \"unknown\") format = ole2Format\n }\n return {\n content: [{ type: \"text\", text: `${file_path}: ${format}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_metadata ────────────────────────────\n\n server.tool(\n \"parse_metadata\",\n \"문서의 메타데이터(제목, 작성자, 날짜 등)만 빠르게 추출합니다. 전체 파싱 없이 헤더/매니페스트만 읽습니다.\",\n {\n file_path: z.string().min(1).describe(\"메타데이터를 추출할 문서 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n const format = detectFormatFromHeader(resolved)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // metadata 전용 크기 제한 (50MB)\n const { buffer } = await readValidatedFile(file_path, MAX_METADATA_FILE_SIZE, PARSE_EXTENSIONS)\n\n let metadata\n // ZIP(hwpx→xlsx/docx/pptx)·OLE2(hwp→xls) 모두 내부 구조로 세분화 — parse()와 판정 일치\n let effectiveFormat: ReturnType<typeof detectFormat> = format\n if (format === \"hwpx\") {\n const zipFormat = await detectZipFormat(buffer)\n if (zipFormat !== \"unknown\") effectiveFormat = zipFormat\n } else if (format === \"hwp\") {\n if (detectOle2Format(buffer) === \"xls\") effectiveFormat = \"xls\"\n }\n switch (effectiveFormat) {\n case \"pptx\":\n throw new KordocError(\"PPTX 파일은 지원하지 않는 파일 형식입니다.\")\n case \"hwp\":\n metadata = extractHwp5MetadataOnly(Buffer.from(buffer))\n break\n case \"hwpx\":\n metadata = await extractHwpxMetadataOnly(buffer)\n break\n case \"pdf\":\n try {\n const { extractPdfMetadataOnly } = await import(\"../pdf/parser.js\")\n metadata = await extractPdfMetadataOnly(buffer)\n } catch {\n metadata = undefined // pdfjs-dist 미설치 시 metadata 생략\n }\n break\n case \"hwp3\":\n case \"hwpml\":\n case \"xls\":\n case \"xlsx\":\n case \"docx\": {\n // 전용 metadata 추출기가 없는 포맷은 전체 파싱 후 metadata 반환\n const result = await parse(buffer)\n metadata = result.success ? result.metadata : undefined\n break\n }\n default:\n // image 등 — 헤더성 메타데이터 없음. 무음 undefined 대신 포맷만 정직하게 반환.\n metadata = undefined\n break\n }\n\n return {\n content: [{ type: \"text\", text: JSON.stringify({ format: effectiveFormat, ...metadata }, null, 2) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_pages ──────────────────────────────\n\n server.tool(\n \"parse_pages\",\n \"문서의 특정 페이지 범위만 파싱합니다. PDF와 한컴 저장본 HWP/HWPX는 실제 페이지 기준(metadata.pageMode=layout), 조판 캐시가 없는 생성 파일은 섹션 단위 근사(pageMode=section)입니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로\"),\n pages: z.string().min(1).describe(\"페이지 범위 (예: '1-3', '1,3,5-7')\"),\n },\n async ({ file_path, pages }) => {\n try {\n const resolved = safePath(file_path, PARSE_EXTENSIONS)\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n // filePath 전달 — 배포용 HWP의 COM fallback에 필요 (parse_document·parse_chunks와 동일)\n const result = await parse(buffer, { pages, filePath: resolved })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const meta = [\n `포맷: ${result.fileType.toUpperCase()}`,\n `범위: ${pages}`,\n result.pageCount ? `페이지: ${result.pageCount}` : null,\n result.metadata?.pageMode === \"section\" ? \"기준: 섹션 근사\" : null,\n ].filter(Boolean).join(\" | \")\n\n return {\n content: [{ type: \"text\", text: `[${meta}]\\n\\n${result.markdown}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_table ──────────────────────────────\n\n server.tool(\n \"parse_table\",\n \"문서에서 N번째 테이블만 추출합니다 (0-based index). 테이블이 없거나 인덱스 범위를 초과하면 오류를 반환합니다.\",\n {\n file_path: z.string().min(1).describe(\"파싱할 문서 파일의 절대 경로\"),\n table_index: z.number().int().min(0).describe(\"추출할 테이블 인덱스 (0부터 시작)\"),\n },\n async ({ file_path, table_index }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const format = detectFormat(buffer)\n\n if (format === \"unknown\") {\n return {\n content: [{ type: \"text\", text: `지원하지 않는 파일 형식입니다: ${file_path}` }],\n isError: true,\n }\n }\n\n const result = await parse(buffer)\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패 (${result.fileType}): ${result.error}` }],\n isError: true,\n }\n }\n\n const tableBlocks = result.blocks.filter(b => b.type === \"table\" && b.table)\n if (tableBlocks.length === 0) {\n return {\n content: [{ type: \"text\", text: `문서에 테이블이 없습니다.` }],\n isError: true,\n }\n }\n\n if (table_index >= tableBlocks.length) {\n return {\n content: [{ type: \"text\", text: `테이블 인덱스 초과: ${table_index} (총 ${tableBlocks.length}개 테이블)` }],\n isError: true,\n }\n }\n\n const tableBlock = tableBlocks[table_index]\n const tableMarkdown = blocksToMarkdown([tableBlock])\n\n return {\n content: [{ type: \"text\", text: `[테이블 #${table_index} / 총 ${tableBlocks.length}개]\\n\\n${tableMarkdown}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: compare_documents ─────────────────────────\n\n server.tool(\n \"compare_documents\",\n \"두 한국 문서 파일을 비교하여 추가/삭제/변경된 블록을 표시합니다. 신구대조표 생성에 활용됩니다. 크로스 포맷(HWP↔HWPX) 비교 가능.\",\n {\n file_path_a: z.string().min(1).describe(\"비교 원본 문서의 절대 경로\"),\n file_path_b: z.string().min(1).describe(\"비교 대상 문서의 절대 경로\"),\n },\n async ({ file_path_a, file_path_b }) => {\n try {\n const { buffer: bufA } = await readValidatedFile(file_path_a)\n const { buffer: bufB } = await readValidatedFile(file_path_b)\n\n const result = await compare(bufA, bufB)\n const { stats, diffs } = result\n\n const lines: string[] = [\n `## 문서 비교 결과`,\n `추가: ${stats.added} | 삭제: ${stats.removed} | 변경: ${stats.modified} | 동일: ${stats.unchanged}`,\n \"\",\n ]\n\n for (const d of diffs) {\n const prefix = d.type === \"added\" ? \"+\" : d.type === \"removed\" ? \"-\" : d.type === \"modified\" ? \"~\" : \" \"\n const text = d.after?.text || d.before?.text || (d.after?.table ? \"[테이블]\" : d.before?.table ? \"[테이블]\" : \"\")\n const sim = d.similarity !== undefined ? ` (${(d.similarity * 100).toFixed(0)}%)` : \"\"\n lines.push(`${prefix} ${text.substring(0, 200)}${sim}`)\n }\n\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: parse_chunks ──────────────────────────────\n\n server.tool(\n \"parse_chunks\",\n \"문서를 RAG용 구조 청크 JSON으로 파싱합니다. 헤딩·개조식 위계(□○- / 1.·가.·1))가 breadcrumb 경로로 보존되고 표는 독립 청크로 나옵니다 — 임베딩·인덱싱 전처리용. 자르기(토큰 상한·오버랩)는 소비자 몫입니다.\",\n {\n file_path: z.string().min(1).describe(\"대상 문서의 절대 경로 (HWP/HWPX/PDF/XLSX/DOCX)\"),\n granularity: z.enum([\"section\", \"block\"]).default(\"section\").describe(\"section=같은 breadcrumb 아래 연속 텍스트 병합(기본), block=IRBlock 1개=청크 1개\"),\n include_table_cells: z.boolean().default(false).describe(\"표 청크에 셀 텍스트 2차원 배열 포함 여부\"),\n },\n async ({ file_path, granularity, include_table_cells }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS)\n const parsed = await parse(buffer, { filePath: file_path })\n if (!parsed.success) {\n return { content: [{ type: \"text\", text: `파싱 실패: ${parsed.error}` }], isError: true }\n }\n const { blocksToChunks } = await import(\"../chunks.js\")\n const chunks = blocksToChunks(parsed.blocks, { granularity, includeTableCells: include_table_cells })\n return { content: [{ type: \"text\", text: capResponseText(JSON.stringify(chunks, null, 2)) }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `청크 파싱 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 공용 — 경로·확장자 검증, 파일 읽기, 오류 문구, 응답 상한 (도구 모듈 공유) */\n\nimport { realpathSync, openSync, readSync, closeSync, lstatSync, constants } from \"fs\"\nimport { readFile, stat, realpath, open } from \"fs/promises\"\nimport { resolve, isAbsolute, extname, dirname, basename, join } from \"path\"\nimport { detectFormat } from \"../index.js\"\nimport { toArrayBuffer, sanitizeError, classifyError, KordocError } from \"../utils.js\"\nimport { assertWithinRoot } from \"../shared/offline.js\"\n\n/** 허용 파일 확장자 */\nexport const ALLOWED_EXTENSIONS = new Set([\".hwp\", \".hwpx\", \".hml\", \".pdf\", \".xls\", \".xlsx\", \".docx\"])\n/** 파싱 계열 도구(parse_*·detect_format) 입력 확장자 — 문서 + 이미지(자동 OCR).\n * 이미지 3종은 detect.ts 매직바이트 지원 범위와 동일. 쓰기·패치 계열은 ALLOWED_EXTENSIONS 유지 */\nexport const PARSE_EXTENSIONS = new Set([...ALLOWED_EXTENSIONS, \".png\", \".jpg\", \".jpeg\", \".webp\"])\n/** 도장/서명 이미지 허용 확장자 (place_seal image_path) */\nexport const IMAGE_EXTENSIONS = new Set([\".png\", \".jpg\", \".jpeg\", \".gif\", \".bmp\"])\n/** 서식 프로필 허용 확장자 (generate_document profile_path) */\nexport const PROFILE_EXTENSIONS = new Set([\".json\"])\n/** 최대 파일 크기 (500MB) */\nexport const MAX_FILE_SIZE = 500 * 1024 * 1024\n\n/** 경로 정규화 및 보안 검증 */\nexport function safePath(filePath: string, allowedExts: ReadonlySet<string> = ALLOWED_EXTENSIONS): string {\n if (!filePath) throw new KordocError(\"파일 경로가 비어있습니다\")\n const resolved = resolve(filePath)\n let real: string\n try {\n real = realpathSync(resolved)\n } catch (err: any) {\n if (err?.code === \"ENOENT\") throw new KordocError(`파일을 찾을 수 없습니다: ${resolved}`)\n if (err?.code === \"EACCES\" || err?.code === \"EPERM\") throw new KordocError(`파일 접근 권한이 없습니다: ${resolved}`)\n throw new KordocError(`경로 처리 오류 [${err?.code ?? \"UNKNOWN\"}]`)\n }\n if (!isAbsolute(real)) throw new KordocError(\"절대 경로만 허용됩니다\")\n assertWithinRoot(real)\n const ext = extname(real).toLowerCase()\n if (!allowedExts.has(ext)) throw new KordocError(`지원하지 않는 확장자입니다: ${ext} (허용: ${[...allowedExts].join(\", \")})`)\n return real\n}\n\n/**\n * 출력 경로 정규화 및 검증 — 확장자 allowlist + 가장 가까운 실재 조상 realpath (safePath의 쓰기 대응).\n * 종전엔 부모만 realpath 해서 KORDOC_ROOT 안 심볼릭 링크로 쓰기가 샜다(v4.14.4 리뷰 재현): 최종 경로가 밖을 가리키는\n * 링크면 writeFile 이 따라가 덮어썼고, 부모가 없으면 문자열로만 판정해 mkdir(recursive) 가 조상의 디렉토리 링크를\n * 따라가 밖에 만들었다. 그래서 최종 경로가 링크면 거부하고, 실재하는(링크 포함) 가장 가까운 조상을 realpath 로 푼 뒤\n * 남은 세그먼트를 이어 판정한다\n */\nexport function safeOutputPath(outputPath: string, allowedExts: ReadonlySet<string>): string {\n if (!outputPath) throw new KordocError(\"출력 경로가 비어있습니다\")\n const resolved = resolve(outputPath)\n const ext = extname(resolved).toLowerCase()\n if (!allowedExts.has(ext)) {\n throw new KordocError(`지원하지 않는 출력 확장자입니다: ${ext || \"(없음)\"} (허용: ${[...allowedExts].join(\", \")})`)\n }\n const entry = (p: string) => { try { return lstatSync(p) } catch { return null } }\n if (entry(resolved)?.isSymbolicLink()) throw new KordocError(`출력 경로가 심볼릭 링크입니다: ${resolved}`)\n let base = dirname(resolved)\n const rest = [basename(resolved)]\n while (!entry(base) && dirname(base) !== base) {\n rest.unshift(basename(base))\n base = dirname(base)\n }\n let real: string\n try {\n real = resolve(realpathSync(base), ...rest) // 끊긴 링크 조상은 여기서 ENOENT — 거부\n } catch (err: any) {\n throw new KordocError(`출력 경로 처리 오류 [${err?.code ?? \"UNKNOWN\"}]: ${base}`)\n }\n assertWithinRoot(real)\n return real\n}\n\n/** Recheck the output directory after asynchronous processing, then open the leaf without following a late symlink. */\nexport async function writeOutputFile(filePath: string, data: string | Uint8Array, encoding?: BufferEncoding): Promise<void> {\n const parent = await realpath(dirname(filePath))\n assertWithinRoot(parent)\n const target = join(parent, basename(filePath))\n const handle = await open(target, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW, 0o666)\n try {\n await handle.writeFile(data, encoding ? { encoding } : undefined)\n } finally {\n await handle.close()\n }\n}\n\n/**\n * MCP 오류 응답 텍스트 — KordocError는 그대로, fs 계열(ENOENT 등)은 경로 노출 없이\n * 코드별 힌트, 그 외는 classifyError 분류를 병기해 일반화 (\"문서 처리 중 오류\" 뭉개기 방지)\n */\nexport function describeError(err: unknown): string {\n if (err instanceof KordocError) return err.message\n const code = (err as NodeJS.ErrnoException)?.code\n if (typeof code === \"string\" && /^E[A-Z]+$/.test(code)) {\n const hints: Record<string, string> = {\n ENOENT: \"파일 또는 디렉토리를 찾을 수 없습니다\",\n EACCES: \"접근 권한이 없습니다\",\n EPERM: \"작업 권한이 없습니다\",\n EISDIR: \"파일이 아니라 디렉토리입니다\",\n ENOTDIR: \"경로 중간이 디렉토리가 아닙니다\",\n ENOSPC: \"디스크 공간이 부족합니다\",\n }\n return `파일 시스템 오류 [${code}]: ${hints[code] ?? \"경로와 권한을 확인하세요\"}`\n }\n const cls = classifyError(err)\n return cls === \"PARSE_ERROR\" ? sanitizeError(err) : `문서 처리 중 오류가 발생했습니다 (${cls})`\n}\n\n/** MCP 응답 본문 상한 — 사진 몇 장·대형 문서로 클라이언트 도구 응답 한도를 넘기지 않게 */\nexport const MAX_RESPONSE_CHARS = 200_000\nexport function capResponseText(text: string, maxChars = MAX_RESPONSE_CHARS): string {\n if (text.length <= maxChars) return text\n return text.slice(0, maxChars) +\n `\\n\\n… [응답이 ${maxChars.toLocaleString()}자 상한을 넘어 절단됨 (전체 ${text.length.toLocaleString()}자) — parse_pages로 페이지 범위를 나눠 읽으세요]`\n}\n\n/** 최대 파일 크기 — metadata 전용 (50MB, 전체 파싱보다 보수적) */\nexport const MAX_METADATA_FILE_SIZE = 50 * 1024 * 1024\n\n/** 파일 읽기 + 크기 검증 공통 로직 — MCP는 장수 stdio 프로세스라 비동기 I/O (이벤트루프 블로킹 방지) */\nexport async function readValidatedFile(filePath: string, maxSize = MAX_FILE_SIZE, allowedExts: ReadonlySet<string> = ALLOWED_EXTENSIONS): Promise<{ buffer: ArrayBuffer; resolved: string }> {\n const resolved = safePath(filePath, allowedExts)\n let fileSize: number\n try {\n fileSize = (await stat(resolved)).size\n } catch (err: any) {\n throw new KordocError(`파일 상태 읽기 실패 [${err?.code ?? \"UNKNOWN\"}]: ${resolved}`)\n }\n if (fileSize > maxSize) {\n throw new KordocError(`파일이 너무 큽니다: ${(fileSize / 1024 / 1024).toFixed(1)}MB (최대 ${maxSize / 1024 / 1024}MB)`)\n }\n let raw: Buffer\n try {\n raw = await readFile(resolved)\n } catch (err: any) {\n throw new KordocError(`파일 읽기 실패 [${err?.code ?? \"UNKNOWN\"}]: ${resolved}`)\n }\n return { buffer: toArrayBuffer(raw), resolved }\n}\n\n/** 파일 헤더(512바이트)만 읽어 포맷 감지 — 전체 파일 로드 불필요.\n * 16바이트로는 HWP3 매직(30B)·HWPML(<?xml…<HWPML, 최대 512B 윈도)이 안 잡힌다 */\nexport function detectFormatFromHeader(resolved: string): ReturnType<typeof detectFormat> {\n const fd = openSync(resolved, \"r\")\n try {\n const headerBuf = Buffer.alloc(512)\n const bytesRead = readSync(fd, headerBuf, 0, 512, 0)\n return detectFormat(toArrayBuffer(headerBuf.subarray(0, bytesRead)))\n } finally {\n closeSync(fd)\n }\n}\n","/** kordoc MCP 도구 — 서식·편집 — parse_form·fill_form·place_seal·patch_document·redact_document */\n\nimport { z } from \"zod\"\nimport { readFile, mkdir, stat, realpath } from \"fs/promises\"\nimport { extname, dirname } from \"path\"\nimport { parse, detectFormat, detectZipFormat, detectOle2Format, blocksToMarkdown, extractFormFields, fillFormFields, markdownToHwpx, fillHwpx, patchHwpx, patchHwp, BUILTIN_TEMPLATES, resolveBuiltinTemplate, readBuiltinTemplate } from \"../index.js\"\nimport { fillWithUniqueGuard, type FillInput } from \"../form/match.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { IMAGE_EXTENSIONS, safePath, safeOutputPath, writeOutputFile, describeError, capResponseText, readValidatedFile } from \"./shared.js\"\n\n/** fields + formats 를 FillInput 맵으로 결합 (formats의 라벨은 fields와 동일 표기 기준) */\nexport function buildFillInputs(fields: Record<string, string>, formats?: Record<string, string>): Record<string, FillInput> {\n const out: Record<string, FillInput> = {}\n for (const [k, v] of Object.entries(fields)) {\n const format = formats?.[k]\n out[k] = format ? { value: v, format } : v\n }\n return out\n}\n\n/** 같은 파일인가 — 경로가 같거나(정규화 후) 대소문자 무시 파일시스템·하드링크로 같은 inode */\nasync function isSameFile(a: string, b: string): Promise<boolean> {\n if (a === b) return true\n try {\n const [sa, sb] = await Promise.all([stat(a), stat(b)])\n return sa.ino === sb.ino && sa.dev === sb.dev\n } catch { return false }\n}\n\nexport function registerFormTools(server: McpServer): void {\n // ─── 도구: parse_form ───────────────────────────────\n\n server.tool(\n \"parse_form\",\n \"한국 서식 문서에서 레이블-값 쌍을 구조화된 JSON으로 추출합니다. 양식/서식 문서에 최적화.\",\n {\n file_path: z.string().min(1).describe(\"서식 문서 파일의 절대 경로\"),\n },\n async ({ file_path }) => {\n try {\n const { buffer } = await readValidatedFile(file_path)\n // 서식 입력란(빈 후행 열)이 필드로 잡히도록 보존 (#47)\n const result = await parse(buffer, { keepTrailingEmptyCols: true })\n\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패: ${result.error}` }],\n isError: true,\n }\n }\n\n const form = extractFormFields(result.blocks)\n return {\n content: [{ type: \"text\", text: JSON.stringify(form, null, 2) }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: fill_form ───────────────────────────────\n\n server.tool(\n \"fill_form\",\n \"한국 서식 문서의 빈칸을 채워서 새 문서로 출력합니다. hwpx-preserve를 사용하면 원본 서식(테두리, 폰트, 병합 등)을 100% 유지합니다. HWPX 누름틀(CLICK_HERE) 필드는 이름으로 정확 매칭되어 우선 채워집니다. file_path 대신 template으로 내장 정부 표준 기안문 서식을 쓸 수 있습니다 — gian(일반기안문, 별지 제1호서식: 행정기관명·수신자·경유·제목·본문·붙임·발신명의·기안자·검토자·결재권자 등 23필드) / gian-simple(간이기안문, 별지 제2호서식: 내부결재용 13필드).\",\n {\n file_path: z.string().min(1).optional().describe(\"서식 템플릿 문서의 절대 경로 (HWP, HWPX, PDF, XLSX, DOCX). template 사용 시 생략\"),\n template: z.enum([\"gian\", \"gian-simple\", \"일반기안문\", \"간이기안문\"]).optional().describe(\"내장 정부 표준 서식 이름 — file_path 대신 사용. gian=일반기안문(별지 제1호서식), gian-simple=간이기안문(별지 제2호서식)\"),\n fields: z.record(z.string(), z.string()).describe(\"채울 필드 맵 (라벨 → 값). 예: {\\\"성명\\\": \\\"홍길동\\\", \\\"전화번호\\\": \\\"010-1234-5678\\\"}\"),\n formats: z.record(z.string(), z.string()).optional().describe(\"필드별 값 서식 (라벨 → 포맷). 정준값 하나로 서식마다 다른 모양을 채울 때: date:yy.mm.dd / phone:hyphen·dot·digits / rrn:hyphen·masked / mask:###-## / 자유 패턴(yyyy년 m월 d일, ###-####-####)\"),\n require_unique: z.boolean().optional().describe(\"한 키가 서식의 2곳 이상에 매칭되면 채우지 않고 거부 — 반복 라벨 양식에서 남의 블록 오염 방지 (배열 값은 예외)\"),\n mask_values: z.boolean().optional().describe(\"응답에 값 대신 글자수만 표시 — 개인정보 채움 시 값이 대화 로그에 남지 않게\"),\n output_format: z.enum([\"markdown\", \"hwpx\", \"hwpx-preserve\"]).default(\"hwpx-preserve\").describe(\"출력 포맷: hwpx-preserve (원본 스타일 보존, HWPX 전용), hwpx (새 HWPX 생성), markdown\"),\n output_path: z.string().optional().describe(\"출력 파일 저장 경로 (선택). 지정 시 파일로 저장, 미지정 시 텍스트로 반환\"),\n },\n async ({ file_path, template, fields, formats, require_unique, mask_values, output_format, output_path }) => {\n try {\n // 출력 경로 사전 검증 (포맷별 확장자 allowlist) — 채우기 전에 실패시킨다\n const outExts = output_format === \"markdown\" ? new Set([\".md\", \".markdown\", \".txt\"]) : new Set([\".hwpx\"])\n const outPath = output_path ? safeOutputPath(output_path, outExts) : undefined\n\n // 입력 소스 — 내장 템플릿(template) 또는 파일 경로(file_path) 중 하나\n let buffer: ArrayBuffer\n if (template) {\n const t = resolveBuiltinTemplate(template)\n if (!t) {\n return {\n content: [{ type: \"text\", text: `알 수 없는 내장 템플릿: ${template} (사용 가능: ${BUILTIN_TEMPLATES.map(x => `${x.id}(${x.aliases[0]})`).join(\", \")})` }],\n isError: true,\n }\n }\n buffer = readBuiltinTemplate(t)\n } else if (file_path) {\n buffer = (await readValidatedFile(file_path)).buffer\n } else {\n return {\n content: [{ type: \"text\", text: \"file_path 또는 template 중 하나를 지정해주세요\" }],\n isError: true,\n }\n }\n\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 (스타일 보존) ───\n if (output_format === \"hwpx-preserve\") {\n // ZIP 은 내부 구조로 세분화한 포맷을 보고한다 — PPTX 를 \"hwpx\" 로 안내하던 오해 방지 (#80).\n // 다른 포맷으로 확인될 때만 거부하고, 판별 불가(손상 ZIP 등)는 종전대로 HWPX 로 시도\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n const isHwpx = format === \"hwpx\"\n if (!isHwpx) {\n return {\n content: [{ type: \"text\", text: `hwpx-preserve는 HWPX 파일만 지원합니다 (감지된 포맷: ${format}). hwpx 또는 markdown을 사용하세요.` }],\n isError: true,\n }\n }\n\n const inputs = buildFillInputs(fields, formats)\n const hwpxResult = require_unique\n ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(buffer, vals, blocked))\n : { ...(await fillHwpx(buffer, inputs)), rejected: [] as string[] }\n // 마스킹 verify — 채운 결과를 재파싱해 값이 실제 문서에 있는지만 확인 (값 미노출)\n let verifyLine: string | null = null\n if (mask_values && hwpxResult.filled.length > 0) {\n const reparsed = await parse(Buffer.from(hwpxResult.buffer))\n // 마크다운 이스케이프(\\*,\\|,\\~ 등)·개행/연속공백 정규화 후 비교 — rrn:masked\n // ('900315-1******')의 * 이스케이프로 생기던 결정적 false negative 방지.\n // 빈 값은 includes('')===true 로 항상 통과하던 것을 FILLED 에서 제외한다.\n const norm = (s: string): string => s.replace(/\\\\([\\\\`*_{}[\\]()#+.!|~>-])/g, \"$1\").replace(/\\s+/g, \" \")\n const normMd = reparsed.success ? norm(reparsed.markdown) : \"\"\n const okCount = reparsed.success\n ? hwpxResult.filled.filter(f => f.value !== \"\" && normMd.includes(norm(f.value))).length\n : 0\n verifyLine = `검증(마스킹): ${okCount}/${hwpxResult.filled.length} FILLED — 재파싱 대조, 값 미노출`\n }\n const summary = [\n `채워진 필드: ${hwpxResult.filled.length}개 (원본 스타일 보존)`,\n hwpxResult.rejected.length > 0 ? `모호 라벨 거부(2곳+ 매칭): ${hwpxResult.rejected.join(\", \")}` : null,\n hwpxResult.unmatched.length > 0 ? `매칭 실패: ${hwpxResult.unmatched.join(\", \")}` : null,\n verifyLine,\n ].filter(Boolean).join(\" | \")\n\n const filledList = hwpxResult.filled\n .map(f => ` - ${f.label}: ${mask_values ? `[${[...f.value].length}자]` : f.value}`).join(\"\\n\")\n\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(hwpxResult.buffer))\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n채워진 필드:\\n${filledList}\\n\\nHWPX 파일 저장 (원본 서식 유지): ${outPath}` }],\n }\n }\n\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n채워진 필드:\\n${filledList}\\n\\n⚠️ output_path를 지정하면 원본 서식이 유지된 HWPX 파일로 저장됩니다.` }],\n }\n }\n\n // ─── 일반 경로: parse → fill → output ─── (양식 입력란 보존, #47)\n const result = await parse(buffer, { keepTrailingEmptyCols: true })\n if (!result.success) {\n return {\n content: [{ type: \"text\", text: `파싱 실패: ${result.error}` }],\n isError: true,\n }\n }\n\n const formInfo = extractFormFields(result.blocks)\n const irInputs = buildFillInputs(fields, formats)\n const fillResult = require_unique\n ? await fillWithUniqueGuard(irInputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked))\n : { ...fillFormFields(result.blocks, irInputs), rejected: [] as string[] }\n\n if (fillResult.filled.length === 0 && formInfo.fields.length === 0) {\n return {\n content: [{ type: \"text\", text: `서식 필드를 찾을 수 없습니다. 일반 문서이거나 서식 패턴이 감지되지 않았습니다.` }],\n isError: true,\n }\n }\n\n const markdown = blocksToMarkdown(fillResult.blocks)\n // mask_values 시 채운 값(주민번호·연락처 등)이 응답(대화 로그)에 노출되지 않게\n // 본문 미리보기를 안내 문구로 대체 (sfill-8). 값은 output_path 파일에만 기록된다.\n const previewMd = mask_values\n ? \"⚠️ mask_values 활성 — 개인정보 노출 방지를 위해 본문을 응답에 포함하지 않습니다. output_path 로 파일 저장 후 확인하세요.\"\n : markdown\n const summary = [\n `채워진 필드: ${fillResult.filled.length}개`,\n fillResult.rejected.length > 0 ? `모호 라벨 거부(2곳+ 매칭): ${fillResult.rejected.join(\", \")}` : null,\n fillResult.unmatched.length > 0 ? `매칭 실패: ${fillResult.unmatched.join(\", \")}` : null,\n formInfo.fields.length > 0 ? `서식 필드: ${formInfo.fields.length}개 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)` : null,\n ].filter(Boolean).join(\" | \")\n\n if (output_format === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(hwpxBuffer))\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\nHWPX 파일 저장: ${outPath}` }],\n }\n }\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n⚠️ output_path를 지정하면 HWPX 파일로 저장됩니다. 미리보기:\\n\\n${previewMd}` }],\n }\n }\n\n // markdown\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, markdown, \"utf-8\")\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n마크다운 파일 저장: ${outPath}\\n\\n${previewMd}` }],\n }\n }\n return {\n content: [{ type: \"text\", text: `[${summary}]\\n\\n${previewMd}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: place_seal ─────────────────────────────\n\n server.tool(\n \"place_seal\",\n \"도장/서명 이미지를 앵커 문구(\\\"(인)\\\"·\\\"서명 또는 인\\\" 등) 위에 부유(글 앞) 배치합니다. 표/페이지를 키우지 않습니다 (HWPX 전용).\",\n {\n file_path: z.string().min(1).describe(\"대상 HWPX 문서의 절대 경로\"),\n image_path: z.string().min(1).describe(\"도장/서명 이미지 절대 경로 (투명 배경 PNG 권장)\"),\n anchor: z.string().default(\"(인)\").describe(\"앵커 문구 — 이 문구 기준으로 배치\"),\n occurrence: z.number().int().min(0).default(0).describe(\"같은 앵커가 여럿일 때 0-based 선택\"),\n size_mm: z.number().positive().optional().describe(\"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\"),\n mode: z.enum([\"overlap\", \"right\", \"auto\"]).default(\"auto\").describe(\"overlap=문구 위 겹침, right=문구 오른쪽 옆, auto=공간 있으면 right\"),\n dx_mm: z.number().optional().describe(\"x 미세조정 mm\"),\n dy_mm: z.number().optional().describe(\"y 미세조정 mm\"),\n output_path: z.string().min(1).describe(\"출력 HWPX 저장 경로\"),\n },\n async ({ file_path, image_path, anchor, occurrence, size_mm, mode, dx_mm, dy_mm, output_path }) => {\n try {\n const outPath = safeOutputPath(output_path, new Set([\".hwpx\"]))\n const { buffer } = await readValidatedFile(file_path)\n const format = detectFormat(buffer)\n if (format !== \"hwpx\") {\n return {\n content: [{ type: \"text\", text: `place_seal 은 HWPX 파일만 지원합니다 (감지된 포맷: ${format}).` }],\n isError: true,\n }\n }\n // 이미지 경로도 문서와 동일하게 검증 (realpath + 확장자 allowlist)\n const imgResolved = safePath(image_path, IMAGE_EXTENSIONS)\n const imgSize = (await stat(imgResolved)).size\n if (imgSize > 500 * 1024 * 1024) {\n return { content: [{ type: \"text\", text: `도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB) — 500MB 이하여야 합니다.` }], isError: true }\n }\n const image = new Uint8Array(await readFile(imgResolved))\n const ext = extname(imgResolved).slice(1).toLowerCase() as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\"\n const { placeSealHwpx } = await import(\"../form/seal.js\")\n const result = await placeSealHwpx(buffer, [{\n anchor, occurrence, image, ext,\n sizeMm: size_mm, mode, dxMm: dx_mm, dyMm: dy_mm,\n }])\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, Buffer.from(result.buffer))\n const p0 = result.placed[0]\n const warnLines = (p0.warnings ?? []).map(w => `\\n⚠️ ${w}`).join(\"\")\n return {\n content: [{\n type: \"text\",\n text: `도장 배치 완료: \"${p0.anchor}\" #${p0.occurrence} → ${p0.mode} (x ${p0.posXMm}mm, y ${p0.posYMm}mm, ${p0.sizeMm}mm각, ${p0.entry})\\n저장: ${outPath}${warnLines}\\n표/페이지 불확장(글 앞 부유) — 한컴에서 위치 확인 후 dx_mm/dy_mm 로 미세조정 가능합니다.`,\n }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `도장 배치 실패: ${describeError(err)}` }],\n isError: true,\n }\n }\n },\n )\n\n // ─── 도구: patch_document ────────────────────────────\n\n server.tool(\n \"patch_document\",\n \"원본 HWPX/HWP의 서식(글꼴·표·도장칸·이미지)을 1바이트도 건드리지 않고, 편집된 마크다운의 바뀐 텍스트만 제자리 치환해 새 문서로 출력합니다. parse_document로 얻은 마크다운을 수정해 넘기세요 — 양식 빈칸 채우기·문구 수정에 적합하며 한컴 한글에서 변조 경고 없이 열립니다. (블록 추가/삭제·표 구조 변경은 미지원, 미적용 항목은 결과에 보고)\",\n {\n file_path: z.string().min(1).describe(\"원본 문서의 절대 경로 (HWPX 또는 HWP 5.x)\"),\n edited_markdown: z.string().min(1).describe(\"parse_document 출력 마크다운을 편집한 전체 마크다운. 바뀐 문단/셀 텍스트만 반영하고 블록 수·순서는 원본과 같게 유지하세요\"),\n output_path: z.string().min(1).describe(\"출력 파일 저장 절대 경로 (원본과 같은 확장자: .hwpx 또는 .hwp)\"),\n },\n async ({ file_path, edited_markdown, output_path }) => {\n try {\n const out = safeOutputPath(output_path, new Set([\".hwpx\", \".hwp\"]))\n const { buffer } = await readValidatedFile(file_path)\n // ZIP(hwpx/xlsx/docx/pptx)·OLE2(hwp/xls) 모두 내부 구조로 세분화한 포맷으로 판정·안내 (#80).\n // 다른 포맷으로 확인될 때만 거부 — 판별 불가(손상 컨테이너 등)는 종전대로 HWPX/HWP 패처가 판단한다\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n else if (format === \"hwp\") { const o = detectOle2Format(buffer); if (o !== \"unknown\") format = o }\n const isHwpx = format === \"hwpx\"\n if (!isHwpx && format !== \"hwp\") {\n return {\n content: [{ type: \"text\", text: `patch_document는 HWPX 또는 HWP 5.x만 지원합니다 (감지된 포맷: ${format}).` }],\n isError: true,\n }\n }\n\n const original = new Uint8Array(buffer)\n const result = isHwpx\n ? await patchHwpx(original, edited_markdown)\n : await patchHwp(original, edited_markdown)\n\n if (!result.success || !result.data) {\n return {\n content: [{ type: \"text\", text: `패치 실패: ${result.error ?? \"알 수 없는 오류\"}` }],\n isError: true,\n }\n }\n\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, Buffer.from(result.data))\n\n const v = result.verification?.stats\n const lossless = v ? (v.modified === 0 && v.added === 0 && v.removed === 0) : undefined\n const lines = [\n `✓ ${result.applied}개 변경 적용 (${isHwpx ? \"HWPX\" : \"HWP\"}, 원본 서식 보존) → ${out}`,\n lossless === true ? \"검증: 편집 내용과 재파싱 결과 완전 일치\" :\n lossless === false ? `검증 잔차: 수정 ${v!.modified} · 추가 ${v!.added} · 삭제 ${v!.removed} (반영 안 된 편집 있음)` : null,\n result.skipped.length > 0\n ? `미적용 ${result.skipped.length}건:\\n` + result.skipped.map(s => ` - ${s.reason}`).join(\"\\n\")\n : null,\n ].filter(Boolean)\n\n return {\n content: [{ type: \"text\", text: lines.join(\"\\n\") }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n // ─── 도구: redact_document ───────────────────────────\n\n server.tool(\n \"redact_document\",\n \"문서의 개인정보(주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허, rules 로 인명·주소 opt-in)를 탐지해 서식 보존 마스킹합니다. HWPX/HWP는 원본 서식 그대로 같은 길이로 가린 파일 — 본문·표·중첩표·머리말/꼬리말·각주·글상자·필드·미리보기(텍스트·이미지)·문서 정보(제목·작성자)까지 가리고, 저장 전 결과 파일을 다시 훑어 남은 PII를 보고합니다. 그 외 포맷(PDF·DOCX·XLSX 등)은 원본을 건드리지 않고 마스킹된 마크다운만 출력합니다. 자동 검출 보조 도구 — 결과 리포트를 사람이 최종 확인해야 하며 이미지 속 글자는 탐지하지 못합니다. 마스킹 후 render_document로 눈으로 확인하는 것을 권장합니다.\",\n {\n file_path: z.string().min(1).describe(\"대상 문서의 절대 경로\"),\n rules: z.array(z.enum([\"rrn\", \"phone\", \"email\", \"card\", \"account\", \"brn\", \"passport\", \"driver\", \"crn\", \"ip\", \"name\", \"address\"])).optional()\n .describe(\"적용 룰 (기본: rrn·phone·email·card·account·brn·passport·driver — crn(법인등록번호)·ip·name(인명, 문맥 게이트)·address(주소)는 opt-in)\"),\n mask_char: z.string().min(1).max(1).optional().describe(\"마스크 문자 1글자 (기본: ●)\"),\n output_path: z.string().min(1).optional().describe(\"출력 경로 (HWPX/HWP는 같은 확장자, 그 외는 .md) — dry_run이 아니면 필수\"),\n dry_run: z.boolean().default(false).describe(\"탐지 리포트만 반환, 파일 미생성\"),\n },\n async ({ file_path, rules, mask_char, output_path, dry_run }) => {\n try {\n const { buffer, resolved } = await readValidatedFile(file_path)\n // ZIP·OLE 내부 구조까지 세분화 — PPTX·XLS 를 hwpx·hwp 로 보고 확장자를 잘못 요구하지 않게 (#80)\n let format: string = detectFormat(buffer)\n if (format === \"hwpx\") { const z = await detectZipFormat(buffer); if (z !== \"unknown\") format = z }\n else if (format === \"hwp\") { const o = detectOle2Format(buffer); if (o !== \"unknown\") format = o }\n const patchable = format === \"hwpx\" || format === \"hwp\"\n if (!dry_run && !output_path) {\n return { content: [{ type: \"text\", text: \"output_path가 필요합니다 (탐지만 원하면 dry_run: true).\" }], isError: true }\n }\n const outPath = !dry_run\n ? safeOutputPath(output_path!, new Set(patchable ? [format === \"hwp\" ? \".hwp\" : \".hwpx\"] : [\".md\", \".markdown\", \".txt\"]))\n : undefined\n if (outPath && await isSameFile(outPath, resolved)) {\n return { content: [{ type: \"text\", text: \"output_path가 입력 파일과 같습니다 — 원본을 덮어쓰지 않습니다. 다른 경로를 지정하세요.\" }], isError: true }\n }\n const { redactDocument } = await import(\"../redact-doc.js\")\n const r = await redactDocument(buffer, { rules, maskChar: mask_char, filePath: file_path, dryRun: dry_run })\n // HWPX/HWP 는 파일 안 위치 기준, 그 외는 본문 마크다운 기준. 명단 수천 행이면 응답이 넘치므로 자른다\n const MAX_LINES = 50\n const listed = r.fileHits.length > 0\n ? r.fileHits.map(h => ` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})`)\n : r.markdownHits.map(h => ` - [${h.rule}] ${h.masked}`)\n const byRule = new Map<string, number>()\n for (const h of r.fileHits.length > 0 ? r.fileHits : r.markdownHits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1)\n const grouped = new Map<string, number>()\n for (const l of listed) grouped.set(l, (grouped.get(l) ?? 0) + 1)\n const groupedLines = [...grouped].map(([l, n]) => n > 1 ? `${l} ×${n}` : l)\n const lines = [\n `탐지: ${[...byRule.values()].reduce((a, b) => a + b, 0)}건 (${[...byRule.entries()].map(([k, v]) => `${k} ${v}`).join(\", \") || \"없음\"})`,\n ...groupedLines.slice(0, MAX_LINES),\n ...(groupedLines.length > MAX_LINES ? [` … 외 ${groupedLines.length - MAX_LINES}줄`] : []),\n ]\n // HWPX/HWP 는 결과 바이트가 원본과 다르면 저장 (탐지 0건이어도 미할당 영역을 비웠으면 저장),\n // 그 외 포맷은 본문에서 찾은 게 있을 때 마스킹된 마크다운을 저장\n const save = r.data ? r.changed : r.markdownHits.length > 0\n if (!dry_run && save) {\n await mkdir(dirname(outPath!), { recursive: true })\n if (r.data) {\n await writeOutputFile(outPath!, Buffer.from(r.data))\n lines.push(`저장: ${outPath} (원본 서식 보존)`)\n } else {\n await writeOutputFile(outPath!, r.markdown, \"utf-8\")\n lines.push(`저장: ${outPath} (${r.format} 원본은 수정하지 않음 — 마스킹된 마크다운)`)\n }\n } else if (!dry_run) {\n lines.push(listed.length > 0 ? \"❌ 파일에서 가린 곳이 없어 출력 파일을 만들지 않았습니다.\" : \"탐지 0건 — 출력 파일을 만들지 않았습니다.\")\n }\n const failed = r.residual.length > 0 || r.unscanned.length > 0\n if (r.residual.length > 0) {\n lines.push(`❌ 마스킹 후 재검사에서 PII ${r.residual.length}건이 남아 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요:`)\n for (const h of r.residual.slice(0, MAX_LINES)) lines.push(` - [${h.rule}] ${h.masked} (${h.where} @ ${h.part})`)\n if (r.residual.length > MAX_LINES) lines.push(` … 외 ${r.residual.length - MAX_LINES}건`)\n }\n if (r.unscanned.length > 0) lines.push(`❌ 글자를 검사하지 못한 곳이 있습니다 — 출력 파일을 공개하지 말고 수동 확인하세요: ${r.unscanned.join(\", \")}`)\n if (!failed && r.data && save) lines.push(\"재검사: 결과 파일 전체(본문·머리말·각주·미리보기·메타데이터·미할당 영역)와 다시 읽은 본문에서 남은 PII 0건\")\n for (const w of r.warnings) lines.push(`⚠️ ${w}`)\n if (r.data && save) lines.push(\"render_document로 마스킹 결과를 눈으로 확인하세요.\")\n lines.push(\"주의: 자동 검출은 보조 수단입니다. 이미지 속 텍스트·표기 변형·이름·주소는 놓칠 수 있으니 최종 공개 전 사람 검토가 필요합니다.\")\n return { content: [{ type: \"text\", text: capResponseText(lines.join(\"\\n\")) }], ...(failed ? { isError: true } : {}) }\n } catch (err) {\n return { content: [{ type: \"text\", text: `마스킹 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 도구 — 렌더 — render_document·crop_regions·extract_tables */\n\nimport { z } from \"zod\"\nimport { mkdir } from \"fs/promises\"\nimport { dirname, join } from \"path\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { MAX_FILE_SIZE, safeOutputPath, writeOutputFile, describeError, readValidatedFile } from \"./shared.js\"\n\nexport function registerRenderTools(server: McpServer): void {\n // ─── 도구: render_document ───────────────────────────\n\n server.tool(\n \"render_document\",\n \"HWPX·HWP 문서를 실제 조판 그대로 렌더해 PNG/JPEG 이미지로 응답하거나 SVG·HTML·PDF 파일로 저장합니다. generate_document·fill_form·patch_document·place_seal 결과물을 눈으로 확인하는 용도 — 생성/수정 후 이 도구로 렌더해 깨짐·잘림·배치를 검증하고 다시 고치는 루프를 권장합니다. 한컴 저장본(HWPX·HWP 모두)은 조판 캐시로 정확히, AI 생성본(캐시 없음)은 순수 조판 엔진(reflow)으로 렌더되며 후자는 한컴 실조판의 근사입니다 (참고용 미리보기).\",\n {\n file_path: z.string().min(1).describe(\"렌더할 HWPX 또는 HWP(5.x) 파일의 절대 경로\"),\n format: z.enum([\"png\", \"jpeg\", \"svg\", \"html\", \"pdf\"]).default(\"png\").describe(\"png/jpeg=이미지로 응답에 직접 반환(output_path 는 선택) / svg·html·pdf=output_path 에 파일 저장(필수). svg 는 pages 미지정 HWPX 면 전체 세로 스택 1파일, 그 외 페이지별 파일. html=자급자족 레이아웃 HTML 1파일, pdf=Chromium 필요\"),\n output_path: z.string().min(1).optional().describe(\"결과 저장 경로 (확장자는 format 과 일치 — .png/.jpg/.svg/.html/.pdf). 페이지별 산출은 _page_NNN 접미\"),\n highlights: z.array(z.string().min(1)).optional().describe(\"형광펜 표시할 검색어 목록 — 채운 값·수정 문구 위치 확인용\"),\n reflow_mode: z.enum([\"keep\", \"charAll\"]).default(\"keep\").describe(\"reflow 줄바꿈: keep=어절 단위, charAll=글자 단위\"),\n pages: z.string().min(1).optional().describe(\"페이지 선택(1-based: '3', '1-3', '1,3,7-9') — 지정하면 페이지별 산출(이미지 응답은 최대 8쪽). HWPX png/svg 에서 미지정이면 전체를 세로 스택 1장으로\"),\n max_width_px: z.number().int().min(200).max(4000).optional().describe(\"래스터(png/jpeg) 최대 폭 px — 큰 문서 응답 부피 조절\"),\n },\n async ({ file_path, format, output_path, highlights, reflow_mode, pages, max_width_px }) => {\n try {\n const EXT: Record<string, string[]> = { png: [\".png\"], jpeg: [\".jpg\", \".jpeg\"], svg: [\".svg\"], html: [\".html\", \".htm\"], pdf: [\".pdf\"] }\n const needsFile = format === \"svg\" || format === \"html\" || format === \"pdf\"\n if (needsFile && !output_path) {\n return { content: [{ type: \"text\", text: `format: \"${format}\" 은 output_path(${EXT[format][0]})가 필수입니다 — 원문은 커서 응답에 직접 담지 않습니다.` }], isError: true }\n }\n const outPath = output_path ? safeOutputPath(output_path, new Set(EXT[format])) : undefined\n const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const isHwp5 = resolved.toLowerCase().endsWith(\".hwp\")\n if (!isHwp5 && !pages && (format === \"png\" || format === \"svg\")) {\n // 종전 동작(HWPX·pages 미지정): 전 페이지 세로 스택 1장/1파일\n const { renderHwpxToSvg } = await import(\"../render/index.js\")\n // reflow는 조판 캐시가 있으면 무시되므로 항상 켠다 — 한컴본·생성본 모두 커버\n const result = await renderHwpxToSvg(buffer, { highlights, reflow: true, reflowMode: reflow_mode })\n const summary = [\n `렌더 완료: ${result.pageCount}페이지, ${Math.round(result.width)}x${Math.round(result.height)}pt (텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables})`,\n ...result.warnings.map(w => `⚠️ ${w}`),\n ]\n if (format === \"svg\") {\n await mkdir(dirname(outPath!), { recursive: true })\n await writeOutputFile(outPath!, result.svg, \"utf-8\")\n summary.push(`저장: ${outPath}`)\n return { content: [{ type: \"text\", text: summary.join(\"\\n\") }] }\n }\n const { rasterizeSvg } = await import(\"../render/rasterize.js\")\n const raster = await rasterizeSvg(result.svg, result.width, result.height, max_width_px ? { maxWidthPx: max_width_px } : undefined)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n await writeOutputFile(outPath, raster.png)\n summary.push(`저장: ${outPath}`)\n }\n summary.push(`이미지 ${raster.widthPx}x${raster.heightPx}px — 잘림·겹침·빈칸·페이지 넘침이 보이면 원인 텍스트를 수정해 다시 생성/패치하세요.`)\n return {\n content: [\n { type: \"image\", data: raster.png.toString(\"base64\"), mimeType: \"image/png\" },\n { type: \"text\", text: summary.join(\"\\n\") },\n ],\n }\n }\n // 통합 렌더러(renderDocument) — 페이지별 산출. HWP5 는 항상 이 경로\n const { renderDocument } = await import(\"../render/index.js\")\n const { scene, assets } = await renderDocument(buffer, { format, pages, highlights, reflow: true, reflowMode: reflow_mode, maxWidthPx: max_width_px })\n const summary = [\n `렌더 완료: 문서 ${scene.pages.length}페이지 중 ${assets.filter(a => a.page !== undefined).length || 1}건 (텍스트 ${scene.stats.texts}·이미지 ${scene.stats.images}·표 ${scene.stats.tables}·도형 ${scene.stats.shapes})`,\n ...scene.warnings.map(w => `⚠️ ${w}`),\n ]\n const suffixed = (p: string, page: number) => p.replace(/(\\.[^.]+)$/, `_page_${String(page).padStart(3, \"0\")}$1`)\n if (outPath) {\n await mkdir(dirname(outPath), { recursive: true })\n for (const a of assets) {\n const p = a.page === undefined || assets.length === 1 ? outPath : suffixed(outPath, a.page)\n await writeOutputFile(p, a.data as Buffer | string)\n summary.push(`저장: ${p}`)\n }\n }\n if (format === \"png\" || format === \"jpeg\") {\n const MAX_PAGES = 8\n const shown = assets.slice(0, MAX_PAGES)\n if (assets.length > MAX_PAGES) summary.push(`⚠️ ${MAX_PAGES}쪽까지만 응답에 담았습니다 — pages 를 좁히세요`)\n return {\n content: [\n ...shown.map(a => ({ type: \"image\" as const, data: (a.data as Buffer).toString(\"base64\"), mimeType: format === \"jpeg\" ? \"image/jpeg\" : \"image/png\" })),\n { type: \"text\", text: summary.join(\"\\n\") },\n ],\n }\n }\n return { content: [{ type: \"text\", text: summary.join(\"\\n\") }] }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `렌더 실패: ${describeError(err)}` }],\n isError: true,\n }\n }\n },\n )\n\n // ─── 도구: crop_regions ──────────────────────────────\n\n server.tool(\n \"crop_regions\",\n \"HWPX·HWP 문서를 렌더해 표·이미지·문단·도형 영역을 페이지 이미지에서 잘라 파일로 저장합니다(render_document 와 같은 조판 엔진, 페이지 로컬 pt bbox 를 실배율로 환산). 표가 진짜 데이터표인지 조직도인지는 판단하지 않습니다(그건 extract_tables) — 렌더러가 아는 개체를 자를 뿐. 결과: output_dir/<유형>_<번호>_page_<쪽>.png + regions.json(id·유형·페이지·bbox pt).\",\n {\n file_path: z.string().min(1).describe(\"HWPX 또는 HWP(5.x) 파일 절대 경로\"),\n output_dir: z.string().min(1).describe(\"crop 파일 저장 디렉토리\"),\n target: z.array(z.enum([\"table\", \"image\", \"paragraph\", \"shape\"])).default([\"table\"]).describe(\"잘라낼 개체 유형\"),\n format: z.enum([\"png\", \"jpeg\"]).default(\"png\"),\n pages: z.string().min(1).optional().describe(\"대상 페이지(1-based 범위)\"),\n padding_pt: z.number().min(0).max(100).default(0).describe(\"bbox 둘레 여백 pt\"),\n },\n async ({ file_path, output_dir, target, format, pages, padding_pt }) => {\n try {\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const dir = safeOutputPath(join(output_dir, \"regions.json\"), new Set([\".json\"])).replace(/[\\\\/]regions\\.json$/, \"\")\n const { extractRenderedRegions } = await import(\"../render/index.js\")\n const regions = await extractRenderedRegions(buffer, { types: target, format, pages, paddingPt: padding_pt, reflow: true })\n await mkdir(dir, { recursive: true })\n const ext = format === \"jpeg\" ? \"jpg\" : \"png\"\n const manifest = []\n for (const r of regions) {\n const name = `${r.region.id.replace(\"-\", \"_\")}_page_${String(r.page).padStart(3, \"0\")}.${ext}`\n await writeOutputFile(join(dir, name), r.data)\n manifest.push({ file: name, id: r.region.id, type: r.region.type, sourceId: r.region.sourceId, parentId: r.region.parentId, page: r.page, bbox: r.bbox, widthPx: r.widthPx, heightPx: r.heightPx })\n }\n await writeOutputFile(join(dir, \"regions.json\"), JSON.stringify(manifest, null, 2))\n return { content: [{ type: \"text\", text: `crop ${regions.length}건 → ${dir}\\n` + manifest.map(m => `${m.file} p${m.page} (${m.bbox.x},${m.bbox.y} ${m.bbox.width}×${m.bbox.height}pt)${m.sourceId ? ` src=${m.sourceId}` : \"\"}`).join(\"\\n\") }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `crop 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n\n // ─── 도구: extract_tables ────────────────────────────\n\n server.tool(\n \"extract_tables\",\n \"HWPX·HWP 문서의 표를 추출·분류합니다(#76). 표마다 semantic-table(데이터표) / non-tabular-layout(조직도·연락망·결재란처럼 표를 캔버스로 쓴 것) / uncertain 분류와 근거 신호, 페이지·bbox(pt, 렌더 region 조인), 정책(visual)에 따른 crop 이미지를 돌려줍니다 — 조직도는 이미지로, 데이터표는 셀 구조로 넘기는 멀티모달 파이프라인용. 휴리스틱(네트워크·LLM 없음), 중첩표도 독립 분류. crop 은 output_dir 에 저장하고 8장까지 응답에 함께 담습니다.\",\n {\n file_path: z.string().min(1).describe(\"HWPX 또는 HWP(5.x) 파일 절대 경로\"),\n output_dir: z.string().min(1).optional().describe(\"crop 파일·tables.json 저장 디렉토리 (visual 이 none 이 아니면 필수)\"),\n visual: z.enum([\"none\", \"non-tabular\", \"non-tabular-and-uncertain\", \"all\"]).default(\"none\").describe(\"crop 대상: none=분류·bbox 만 / non-tabular=조직도류만 / non-tabular-and-uncertain(권장) / all\"),\n format: z.enum([\"png\", \"jpeg\"]).default(\"png\"),\n padding_pt: z.number().min(0).max(100).default(0).describe(\"crop 둘레 여백 pt\"),\n cells: z.boolean().default(false).describe(\"응답 JSON 에 셀 텍스트 격자 포함\"),\n },\n async ({ file_path, output_dir, visual, format, padding_pt, cells }) => {\n try {\n if (visual !== \"none\" && !output_dir) {\n return { content: [{ type: \"text\", text: \"visual 이 none 이 아니면 crop 파일을 저장할 output_dir 이 필요합니다.\" }], isError: true }\n }\n const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, new Set([\".hwpx\", \".hwp\"]))\n const dir = output_dir ? safeOutputPath(join(output_dir, \"tables.json\"), new Set([\".json\"])).replace(/[\\\\/]tables\\.json$/, \"\") : undefined\n const { extractTables } = await import(\"../table/visual.js\")\n const tables = await extractTables(buffer, { policy: visual, format, paddingPt: padding_pt })\n if (dir) await mkdir(dir, { recursive: true })\n const ext = format === \"jpeg\" ? \"jpg\" : \"png\"\n const images: Array<{ type: \"image\"; data: string; mimeType: string }> = []\n const report = []\n for (const t of tables) {\n const crops = []\n for (const c of t.crops) {\n const name = `${t.id.replace(/[^\\w.-]/g, \"_\")}_page_${String(c.page).padStart(3, \"0\")}.${ext}`\n if (dir) await writeOutputFile(join(dir, name), c.data)\n if (images.length < 8) images.push({ type: \"image\", data: c.data.toString(\"base64\"), mimeType: c.mimeType })\n crops.push({ file: dir ? name : undefined, page: c.page, bbox: c.bbox })\n }\n report.push({\n id: t.id, sourceId: t.sourceId, page: t.page, classification: t.classification,\n table: { rows: t.table.rows, cols: t.table.cols, hasHeader: t.table.hasHeader, caption: t.table.caption, ...(cells ? { cells: t.table.cells.map(r => r.map(c => c.text)) } : {}) },\n regions: t.regions, crops, warnings: t.warnings,\n })\n }\n const json = JSON.stringify(report, null, 2)\n if (dir) await writeOutputFile(join(dir, \"tables.json\"), json + \"\\n\")\n const kinds = report.reduce<Record<string, number>>((m, r) => { m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1; return m }, {})\n const head = `표 ${report.length}개 (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(\", \") || \"없음\"}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}건${dir ? ` → ${dir}` : \"\"}${images.length < report.reduce((n, r) => n + r.crops.length, 0) ? \" (응답에는 8장까지)\" : \"\"}`\n return { content: [...images, { type: \"text\", text: `${head}\\n${json}` }] }\n } catch (err) {\n return { content: [{ type: \"text\", text: `표 추출 실패: ${describeError(err)}` }], isError: true }\n }\n },\n )\n}\n","/** kordoc MCP 도구 — 생성 — extract_profile·generate_document */\n\nimport { z } from \"zod\"\nimport { readFile, mkdir } from \"fs/promises\"\nimport { dirname } from \"path\"\nimport { markdownToHwpx, unknownFontWarnings, usesGaejosikMunche, PRESET_ALIAS, incompatibleGongmunWarnings, gongmunLintWarnings, muncheLintWarnings } from \"../index.js\"\nimport type { GongmunOptions } from \"../index.js\"\nimport { buildGongmunOptions, BODY_FONTS, H2_MARKERS, BULLET2_CHARS, FONT_ROLE_KEYS, SIZE_KEYS, DOC_HEAD_KEYS, DOC_FOOT_KEYS, DOC_INFO_KEYS, NOTICE_HEAD_KEYS, PRESS_CONTACT_KEYS, BODY_PT_RANGE, LINE_SPACING_RANGE, SIZE_PT_RANGE, APPROVAL_MAX, LEVEL_STYLE_KEYS } from \"../hwpx/gongmun-surface.js\"\nimport { assertWithinRoot } from \"../shared/offline.js\"\nimport { loadGenerationImages } from \"../shared/generate-images.js\"\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"\nimport { PROFILE_EXTENSIONS, safePath, safeOutputPath, writeOutputFile, describeError, readValidatedFile } from \"./shared.js\"\n\nexport function registerGenerateTools(server: McpServer): void {\n // ─── 도구: extract_profile ───────────────────────────\n\n server.tool(\n \"extract_profile\",\n \"참조 HWPX 문서에서 표 서식 프로필(테두리·음영·열 너비·셀 글꼴)을 JSON으로 추출합니다. 추출한 프로필을 generate_document의 profile_path로 넘기면 원본 문서 없이 같은 표 서식을 재현합니다 — \\\"이 문서 표 서식 그대로 만들어줘\\\" 워크플로의 1단계.\",\n {\n hwpx_path: z.string().min(1).describe(\"서식을 추출할 참조 HWPX 파일의 절대 경로\"),\n output_path: z.string().min(1).describe(\"프로필 JSON 출력 절대 경로 (.json 권장)\"),\n },\n async ({ hwpx_path, output_path }) => {\n try {\n const out = safeOutputPath(output_path, PROFILE_EXTENSIONS)\n const { buffer } = await readValidatedFile(hwpx_path)\n const { hwpxToProfile } = await import(\"../index.js\")\n const profile = await hwpxToProfile(buffer)\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, JSON.stringify(profile, null, 2))\n return {\n content: [{ type: \"text\", text: `서식 프로필 추출 완료: 표 ${profile.tables.length}개 → ${out}\\n(generate_document의 profile_path로 사용)` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n\n server.tool(\n \"generate_document\",\n \"마크다운을 HWPX 한글 문서로 생성합니다. \\\"보고서로/공문서로/개조식으로/계획서로 뽑아줘·만들어줘\\\" 요청이 이 도구입니다. 프리셋 매핑: 정부 표준 보고서(표지·목차·로마숫자 장헤더 자동)='개조식', 중앙부처 업무보고·국회 서면보고(재경부 실측: 장 띠·절 숫자칸·소제목 박스·① 항목 띠·연노랑 성과 요약박스·별첨 띠, □ 뒤 (키워드) 파랑)='업무보고', 지방자치단체 방침서·추진계획(서울시 시장방침 실측: 제목표·파랑 부제·요약박스·[Ⅰ] 장 상자·절 띠)='서울방침' — 보고서·계획서를 만들 때 정부(업무보고)형과 지방(서울방침)형 중 무엇으로 할지 불명확하면 사용자에게 물어보세요, 기안문·시행문·알림공문='기안문', 1페이지 요약보고서='보고서', 추진계획='계획서'. 표는 실측 정부 서식(헤더 음영+이중선·외곽 굵은선·내용 비례 열폭), 쪽번호·결재란·'끝.' 표시 지원. ⚠ 생성 전 확인 권장: 문서종류(보고서/기안문)·제목·기관명(org)·날짜·목차 여부가 불명확하면 사용자에게 물어보세요 — 엉뚱한 프리셋 선택이 가장 흔한 오생성 원인. 마크다운 규칙(v4.13 서울 실결재 실측 위계): #(h1)=문서 제목, ##(h2)=장(보고서 Ⅰ Ⅱ / 기안문·통지는 법정 1.), ###(h3)=□ 대항목(기안문 가.), 그 아래 리스트=ㅇ → - → ㆍ(기안문 가. → 1) → 가)), 본문에 □/ㅇ/-/1./가. 를 직접 써도 같은 위계로 정규화, ※시작·'출처:'·'자료:'=참고(13pt), 제목 직후 인용문(>)=보고서 요약박스 — ★보고서는 반드시 제목 직후 `> …하고자 함` 한 문장(쉼표 허용·부호 없음·3줄 이내 약 90~100자)로 보고 목적을 넣을 것(없거나 3줄 초과면 경고), <right>텍스트</right>=우측정렬. □·제목은 한 줄에 자동 축소, 본문은 어절 단위 줄바꿈(낱말·날짜가 줄 끝에서 안 쪼개짐)·부호 뒤 탭 정렬(둘째 줄이 첫 줄 내용과 같은 위치), 마지막 줄이 짧은 고아 줄과 공백이 크게 벌어지는 줄은 자간 축소로 정리, 곧은따옴표는 ‘’“”로. 법령 코드 (282791)·KOSIS 표 ID DT_…·(법정동코드 …)·○○ MCP 조회 같은 내부 식별자·도구 언급은 자동 제거 — 출처는 기관·자료명만 쓸 것. (원본 서식 보존 제자리 수정은 patch_document, 서식 빈칸 채우기는 fill_form)\",\n {\n markdown: z.string().min(1).describe(\"HWPX로 변환할 마크다운 전문. 표는 GFM 문법 사용 (예: '| 이름 | 부서 |\\\\n| --- | --- |\\\\n| 홍길동 | 기획팀 |')\"),\n output_path: z.string().min(1).describe(\"출력 HWPX 파일의 절대 경로 (.hwpx 권장)\"),\n profile_path: z.string().optional().describe(\"서식 프로필 JSON 경로 (extract_profile로 추출) — 참조 문서의 표 테두리·음영·열폭·셀 글꼴을 재현. 표 행·열 수와 첫 셀 텍스트가 일치하는 표에만 적용\"),\n // 값 집합·범위는 gongmun-surface SSOT에서 파생 (CLI와 드리프트 불가 — v4.0.4 영역1-1)\n preset: z.enum(Object.keys(PRESET_ALIAS) as [string, ...string[]]).optional()\n .describe(\"공문서 프리셋 — 지정 시 한국 행정 공문서 표준 서식 적용. '개조식'=정부 표준 개조식 보고서(표지·목차·로마숫자 장 헤더 자동 + □○-※ 부호별 폰트), '업무보고'=중앙부처 업무보고(##=Ⅰ 장 띠, ###=파란 숫자칸 절, ####=남색 소제목 박스, #####=① 하늘색 항목 띠, > ▪…=연노랑 성과 요약박스, ## 별첨 …=별첨 띠, ❶⇒ 부호 보존, 함초롬바탕 15·각주 맑은 고딕 12), '서울방침'=서울시 방침서(# 제목 뒤 '- 부제 -' 줄=파랑 부제·☎ 줄=담당자 행·> =요약박스, ##=[Ⅰ] 장 상자, ###=파란 번호 절 띠, ####=❶ 과제 소제목, □ HY견고딕 17·ㅇ 한컴돋움 15 굵게·- 휴먼명조 14·▸ 13, 줄간격 200%), '보도자료'=머리박스+제목 25pt+□→ㅇ→*(각주) 체계. 미지정 시 범용 마크다운 변환\"),\n font: z.enum(BODY_FONTS).optional().describe(\"본문 글꼴(공문서 모드): myeongjo=명조 계열(개조식·보고서·계획서는 실측 휴먼명조, 그 외 함초롬바탕), gothic=맑은 고딕\"),\n body_pt: z.number().int().min(BODY_PT_RANGE.min).max(BODY_PT_RANGE.max).optional().describe(\"본문 글자 크기(pt, 공문서 모드). 기본: 기안문 12, 보고서·계획서·통지 15\"),\n line_spacing: z.number().int().min(LINE_SPACING_RANGE.min).max(LINE_SPACING_RANGE.max).optional().describe(\"본문 줄간격(%, 공문서 모드). 기본: 프리셋별 실측값(기안문 160, 회의록 130 등)\"),\n org: z.string().optional().describe(\"표지 기관명 (표지를 켜는 모든 프리셋에서 사용 가능). 미지정 시 표지에 기관명 생략\"),\n date: z.string().optional().describe(\"표지 날짜 ('YYYY. M. D.' 표기 권장). 미지정 시 오늘 날짜\"),\n toc: z.boolean().optional().describe(\"목차 페이지 생성 여부 — h2 목록을 Ⅰ Ⅱ Ⅲ 장으로 자동 구성. 전 프리셋 사용 가능(보도자료 제외). 미지정 시 개조식 프리셋만 켜짐\"),\n cover: z.boolean().optional().describe(\"표지 페이지 생성 여부 — 첫 h1을 제목으로 파랑 장식 표지. 전 프리셋 사용 가능(보도자료 제외 — 머리박스 서식과 양립 불가). 미지정 시 개조식 프리셋만 켜짐 (org/date 지정 시 자동 켜짐)\"),\n approval: z.array(z.string()).max(APPROVAL_MAX).optional().describe(\"결재란 직위 라벨 (최대 6개, 예: ['담당','팀장','과장']) — 문서 최상단 우측에 서명 공란 결재 표 생성\"),\n page_numbers: z.boolean().optional().describe(\"쪽번호(하단 중앙 '- 1 -', 표지·목차 카운트 제외). 미지정 시 개조식·보고서·계획서 켜짐\"),\n end_mark: z.boolean().optional().describe(\"본문 끝 '끝.' 표시 (행정업무규정). 미지정 시 기안문만 켜짐, 본문이 이미 '끝.'으로 끝나면 중복 생성 안 함\"),\n body_title_box: z.boolean().optional().describe(\"본문 첫 페이지 제목 반복 박스 (개조식 실측 관행). 미지정 시 개조식+표지 조합에서 켜짐\"),\n chapter_fit: z.boolean().optional().describe(\"개조식 장 헤더 제목 칸을 글자 폭에 맞춤. 미지정 시 제목 칸이 본문 폭까지\"),\n h2_marker: z.enum(H2_MARKERS).optional().describe(\"h2 장 제목 표기: band=로마자 채움 칸+제목 띠 표(보고서·계획서 기본), roman='Ⅰ. 제목' 텍스트, number='1. 제목'(통지 기본), box=장 없이 □ 대항목으로, none=번호 없음. 기안문 본문의 h2는 항상 법정 '1.' 항목\"),\n band_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(\"띠 제목 번호칸 채움색 #RRGGBB (기본 #003366 실측 최다. 교육청형 밝은 띠는 #DFE6F7 + band_text_color #000000)\"),\n band_text_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe(\"띠 제목 번호 글자색 #RRGGBB (기본 #FFFFFF)\"),\n summary: z.string().optional().describe(\"보고서 요약 박스 — 제목표 아래 #DFE6F7 음영 상자(서울 실결재 관행). 마크다운 제목 직후 인용문(> …)으로도 지정 가능\"),\n doc_info: z.object(Object.fromEntries(DOC_INFO_KEYS.map(k => [k, z.string().optional()]))).optional().describe(\"보고서 표지 문서정보표 — docNum=문서번호/date=결재일자/disclosure=공개여부/policyNo=방침번호 (cover=true와 함께)\"),\n checklist: z.union([z.boolean(), z.object({ na: z.array(z.number().int()).optional(), notes: z.record(z.string(), z.string()).optional() })]).optional()\n .describe(\"서울 사전 검토항목 점검표(표지 다음 쪽, 보고서·계획서·서울방침) — true=표시 없는 빈 서식, {na:[6,7,…]}=적은 문항(1~14)은 해당없음·나머지 검토완료, notes={\\\"7\\\":\\\"교육\\\"}=비고\"),\n dept: z.string().optional().describe(\"표지 부서명 — 기관명 아래 '(스마트도시과)' (cover와 함께)\"),\n cover_label: z.string().optional().describe(\"표지 우상단 취급 표시 — '대외주의'·'비공개' 빨간 테두리 박스 (업무보고 프리셋 실측, cover와 함께)\"),\n fonts: z.object(Object.fromEntries(FONT_ROLE_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"요소별 글꼴 오버라이드(공문서 모드) — body=본문(○·-)/heading=제목 계열(□·장헤더·표지·목차)/ref=※ 참고/table=표 셀. 개조식·보고서·계획서는 네 역할 전부, 그 외 프리셋은 body만 적용\"),\n sizes: z.object(Object.fromEntries(SIZE_KEYS.map(k => [k, z.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional()])))\n .optional().describe(\"개조식 요소별 글자 크기(pt) 오버라이드 — dae=□/cham=※/chapter=장헤더/coverTitle·coverSub=표지/tocLabel·tocRoman·tocItem=목차/table=표 셀/bodyTitle=본문 첫 페이지 제목 반복 박스. 미지정 요소는 body_pt 비례 기본값\"),\n levels: z.record(z.string().regex(/^[0-7]$/), z.object(Object.fromEntries(LEVEL_STYLE_KEYS.map(k => [k, k === \"pt\" ? z.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional() : k === \"bold\" ? z.boolean().optional() : z.string().optional()]))))\n .optional().describe(\"항목부호 단계별 위계 타이포(공문서 모드, v4.12.3) — {\\\"0\\\":{font:\\\"HY견고딕\\\",pt:17,bold:true},\\\"1\\\":{font:\\\"한컴돋움\\\",bold:true}} 꼴(depth 0~7). 실측: 전자결재 기안문 □/ㅇ/- 계열은 □=HY견고딕 +2~3pt 굵게·ㅇ=한컴돋움 굵게·-=휴먼명조 본문. 법정 8단계(1. 가.)는 본문 동일이 관행이라 기본 미적용\"),\n bullet2: z.enum(BULLET2_CHARS).optional().describe(\"2단계 항목부호 — 'ㅇ'(이응, 전자결재 기안문·공고문 실측 지배) / '○'(원, 보고서 양식). 미지정 시 통지·보도자료 ㅇ, 그 외 ○\"),\n suppress_single: z.boolean().optional().describe(\"단일 형제 항목 부호 생략(편람 규정, 법정 번호 standard 전용 — 불릿 체계인 보고서·계획서·개조식·보도자료엔 무효). 기본 false — 하나뿐인 항목에도 부호(1. 가.)를 부여 (부호 없는 계단 들여쓰기가 실무 눈에 어색)\"),\n doc_head: z.object(Object.fromEntries(DOC_HEAD_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"기안문 두문표(별지 제1호서식·서울 실결재 6행 표) — org=행정기관명(굴림 20pt bold 자간띄움)/slogan=원훈(상단 10pt)/to=수신('내부결재'면 발신명의 생략)/via=경유/title=제목(미지정 시 첫 h1). 기안문 프리셋 전용\"),\n doc_foot: z.object(Object.fromEntries(DOC_FOOT_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"기안문 결문표 — sender=발신명의(18pt bold 중앙)/drafter·reviewer·approver='직위 성명' 결재선/cooperator=협조자/recipients=수신자 목록/docNum=시행 '과-번호 (날짜)'/receive=접수/zip·address·site/phone·fax·email/disclosure=공개구분. 기안문 프리셋 전용\"),\n report_info: z.string().optional().describe(\"보고서: 제목표 아래 담당자 행 '(2026. 9. 6., 스마트도시과 홍길동, ☎450-1234)' / 기안문: 우상단 12pt 보고정보 행\"),\n notice_head: z.object(Object.fromEntries(NOTICE_HEAD_KEYS.map(k => [k, z.string().optional()])))\n .optional().describe(\"공고문 두문·결문 — no=공고번호(본문 위 bold)/date=날짜(본문 아래 우측)/sender=발신명의(우측 bold). 통지 프리셋 전용\"),\n press: z.object({\n release: z.string().optional(), distribute: z.string().optional(),\n sub: z.array(z.string()).optional(),\n contact: z.object(Object.fromEntries(PRESS_CONTACT_KEYS.map(k => [k, z.string().optional()]))).optional(),\n }).optional().describe(\"보도자료 옵션 — release=보도시점/distribute=배포일(머리박스)/sub=부제 배열('- … -')/contact=담당 부서·담당자·연락처 표\"),\n paper: z.enum([\"A4\", \"A3\", \"B4\", \"B5\", \"Letter\"]).optional().describe(\"용지 크기 (v4.5.0). 기본 A4\"),\n landscape: z.boolean().optional().describe(\"용지 가로 방향 (v4.5.0). 기본 세로\"),\n columns: z.number().int().min(1).max(8).optional().describe(\"다단 개수 (v4.5.0). 기본 1단\"),\n header: z.string().optional().describe(\"머리말 텍스트 — 모든 쪽 상단, 인라인 마크다운 허용 (v4.5.0)\"),\n footer: z.string().optional().describe(\"꼬리말 텍스트 — 모든 쪽 하단 (v4.5.0)\"),\n image_dir: z.string().optional().describe(\"마크다운 이미지 참조()를 이 디렉토리에서 읽어 실데이터 임베드 (v4.5.0, PNG/JPEG/GIF/BMP). 미지정 시 참조만 placeholder로 보존\"),\n },\n async ({ markdown, output_path, profile_path, preset, font, body_pt, line_spacing, org, date, toc, cover, approval, page_numbers, end_mark, body_title_box, chapter_fit, h2_marker, band_color, band_text_color, summary, doc_info, checklist, dept, cover_label, fonts, sizes, levels, bullet2, suppress_single, doc_head, doc_foot, report_info, notice_head, press, paper, landscape, columns, header, footer, image_dir }) => {\n try {\n // 조립은 gongmun-surface SSOT(buildGongmunOptions) — CLI와 의미론 공유 (v4.0.4)\n let gongmun: GongmunOptions | undefined\n if (preset) {\n gongmun = buildGongmunOptions({\n preset: PRESET_ALIAS[preset], font, bodyPt: body_pt, lineSpacing: line_spacing,\n org, date, cover, toc, approval,\n pageNumbers: page_numbers, endMark: end_mark, bodyTitleBox: body_title_box, chapterFit: chapter_fit,\n h2Marker: h2_marker, bandColor: band_color, bandTextColor: band_text_color, fonts, sizes, levels, bullet2, suppressSingle: suppress_single,\n docHead: doc_head, docFoot: doc_foot, reportInfo: report_info,\n noticeHead: notice_head, press, summary, docInfo: doc_info, dept, coverLabel: cover_label,\n checklist: checklist && typeof checklist === \"object\" ? { na: checklist.na, notes: checklist.notes && Object.fromEntries(Object.entries(checklist.notes).map(([k, v]) => [Number(k), v])) } : checklist,\n })\n }\n // 서식 프로필 (이슈 #41) — 경로 검증(realpath + .json) 후 경계 zod 검증 (CLI --profile과 공유 스키마)\n let profile: import(\"../hwpx/gen-profile.js\").FormatProfile | undefined\n if (profile_path) {\n const { parseFormatProfileJson } = await import(\"../hwpx/profile-io.js\")\n profile = parseFormatProfileJson(await readFile(safePath(profile_path, PROFILE_EXTENSIONS), \"utf-8\"))\n }\n const out = safeOutputPath(output_path, new Set([\".hwpx\"]))\n // 페이지 옵션 (v4.5.0)\n const page = paper || landscape || columns || header || footer\n ? {\n ...(paper ? { size: paper } : {}),\n ...(landscape ? { orientation: \"landscape\" as const } : {}),\n ...(columns ? { columns } : {}),\n ...(header ? { header } : {}),\n ...(footer ? { footer } : {}),\n }\n : undefined\n const genWarnings: string[] = []\n let images: Record<string, Uint8Array> | undefined\n if (image_dir) {\n const loaded = await loadGenerationImages(markdown, image_dir, assertWithinRoot)\n images = loaded.images\n genWarnings.push(...loaded.warnings)\n }\n const buf = await markdownToHwpx(markdown, gongmun || profile || page || images\n ? {\n ...(gongmun ? { gongmun } : {}), ...(profile ? { profile } : {}),\n ...(page ? { page } : {}), ...(images ? { images } : {}),\n warnings: genWarnings,\n }\n : undefined)\n await mkdir(dirname(out), { recursive: true })\n await writeOutputFile(out, Buffer.from(buf))\n\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\n const tableCount = (markdown.match(/^\\s*\\|.*\\|\\s*$/gm) || []).length > 0\n ? `, 표 포함` : \"\"\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행, 경고만 병기.\n // 프리셋 비호환 옵션(조용한 폐기)·편람 표기법 검수도 같은 채널로 병기\n const fontWarns = gongmun?.fonts ? unknownFontWarnings(gongmun.fonts) : []\n if (gongmun) fontWarns.push(...incompatibleGongmunWarnings(gongmun))\n if (gongmun) fontWarns.push(...gongmunLintWarnings(markdown, 5))\n // 개조식 문체 검수 — 보고서·계획서·개조식 프리셋만 (기안문 경어체 등에는 미적용)\n if (gongmun && usesGaejosikMunche(gongmun.preset)) fontWarns.push(...muncheLintWarnings(markdown, 5))\n fontWarns.push(...genWarnings)\n const warnText = fontWarns.length ? `\\n⚠ ${fontWarns.join(\"\\n⚠ \")}` : \"\"\n return {\n content: [{ type: \"text\", text: `✓ HWPX 생성 (${mode}${tableCount}) → ${out}\\n크기: ${(buf.byteLength / 1024).toFixed(1)}KB${warnText}` }],\n }\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `오류: ${describeError(err)}` }],\n isError: true,\n }\n }\n }\n )\n}\n"],"mappings":"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","names":["realpathSync","server","z","readFile","stat","extname","dirname","stat","server","z","summary","dirname","readFile","extname","z","mkdir","dirname","join","server","z","summary","mkdir","dirname","join","z","readFile","mkdir","dirname","server","z","mkdir","dirname","readFile","realpathSync"]}
|