# kordoc **모두 파싱해버리겠다.** [![npm version](https://img.shields.io/npm/v/kordoc.svg)](https://www.npmjs.com/package/kordoc) [![license](https://img.shields.io/npm/l/kordoc.svg)](https://github.com/chrisryugj/kordoc/blob/main/LICENSE) > *대한민국에서 둘째가라면 서러울 문서지옥. 거기서 7년 버틴 공무원이 만들었습니다.* HWP 3.x/5.x, HWPX, HWPML, PDF, XLS, XLSX, DOCX, 이미지(PNG/JPG/WebP) — 관공서에서 쏟아지는 모든 문서를 파싱하고, 비교하고, 분석하고, 생성합니다. [English](./README-EN.md) [![Kordoc 활용하기 — 영상 보기](./docs/video-demo.jpg)](https://youtu.be/Q13GmgDcIw0) ▶ 클릭하면 유튜브에서 재생됩니다. --- ## ⚡ 30초 설치 (AI 에이전트 연동) **macOS / Linux / Windows 공용**. Node.js 20+ 만 있으면 됩니다. ```bash npx -y kordoc setup ``` 대화형 마법사가: 1. 사용 중인 AI 클라이언트 번호 선택 (Claude Desktop / Cursor / Claude Code / Windsurf / VS Code / Gemini CLI / Zed / Antigravity / Codex — 설치된 건 `[감지됨]` 표시) 2. 설정 파일 자동 패치 → 클라이언트 재시작 Windows 도 자동으로 `cmd /c npx` 래핑. 수동 JSON 편집 불필요. 재시작하면 17개 문서 도구 (`parse_document`, `parse_table`, `fill_form`, `patch_document`, `generate_document` 등) 활성화. > **CLI 로만 쓸 거면** 설치 없이 `npx kordoc <파일>` 바로 사용. 아래 [CLI](#cli) 섹션 참고. > **`MODULE_NOT_FOUND` / `Cannot find module ...\dist\cli.js` 가 뜨면**: 과거에 깨진 글로벌 설치가 남아있는 상태입니다. 아래로 해결: > ```powershell > npm uninstall -g kordoc > npx -y kordoc@latest setup > ``` > **Windows PowerShell 에서 `npx.ps1 파일을 로드할 수 없습니다 · PSSecurityException` 이 뜨면**: PowerShell 기본 보안 정책이 서명 없는 `.ps1` 을 차단하는 표준 동작입니다 (kordoc 무관). 아래 중 하나 쓰시면 됩니다. > > **방법 1 — 명령 프롬프트(cmd) 창에서 실행** (가장 안전) > 윈도우 키 → `cmd` 검색 → Enter → 검은 창에서 그대로: > ``` > npx -y kordoc setup > ``` > > **방법 2 — PowerShell 실행 정책 한 번만 완화** > 관리자 권한 PowerShell: > ```powershell > Set-ExecutionPolicy -Scope CurrentUser RemoteSigned > ``` > 이후 PowerShell 재시작 → `npx -y kordoc setup` 그대로 됨. ### Claude Code 플러그인으로 설치 MCP 등록 대신 스킬(SKILL.md) 형태로 쓰려면: ``` /plugin marketplace add chrisryugj/kordoc /plugin install kordoc@kordoc ``` `.hwp`/`.hwpx` 언급이나 공문서 생성·서식 채우기 요청 시 kordoc 스킬이 자동 활성화됩니다 (내부에서 `npx -y kordoc@^4` CLI 호출 — 별도 설치 불필요). --- ## 💡 kordoc으로 무엇을 할 수 있나요? 단순한 텍스트 추출을 넘어, **공문서 처리를 위한 모든 과정**을 자동화합니다. * **📄 어떤 문서든 마크다운으로**: `HWP3` (구버전), `HWP`(5.x), `HWPX`, `HWPML`, `PDF`, `XLS`, `XLSX`, `DOCX` 파일은 물론 `PNG`/`JPG`/`WebP` 이미지(자동 OCR)까지 즉시 `Markdown`으로 변환합니다. AI(LLM)가 문서를 읽고 분석하기 가장 좋은 상태로 만들어줍니다. * **📊 복잡한 표(Table) 복원 — 숫자로 잠금**: 병합·중첩 표를 구조 그대로 살립니다. HWPX 코퍼스 291문서 **표 1,673/1,673·셀 27,714/27,714 무손실**(독립 추출기 대조 게이트 1.0), 동일문서 hwpx↔pdf 대조(6쌍 69표)는 **매칭 98.6%·완전일치 65.2%**. 선 없는 PDF 표도 감지해 복원하고, 법령 개정안 PDF의 신구조문대비표도 통째로 살립니다 (v3.16.2). * **🔍 신구대조표 자동 생성**: 두 문서의 차이점을 분석하여 무엇이 바뀌었는지 한눈에 보여줍니다. (HWP와 HWPX 간의 비교도 가능!) * **📝 마크다운을 다시 HWPX로**: AI가 작성한 내용을 다시 보고서 양식(`HWPX`)으로 되돌려줍니다. 이제 복사-붙여넣기 노가다에서 해방되세요. * **🏛️ 정부 표준 공문서 생성 (v4.0)**: 실제 정부 양식 16종 + 실결재 기안문 60건을 전수 디코드·대조해 만든 공문서 엔진. 개조식 보고서(표지·목차 배너·로마숫자 장헤더·쪽번호·결재란), 기안문(별지 제1호서식 두문·결문, "끝." 자동), 공고문·보도자료 프리셋, 항목부호 8단계(1. 가. 1) 가)…) 자동, 공문서 표기법 검수 19룰(`kordoc lint`)까지 — 한글 COM 실렌더로 조판까지 실측 검증했습니다. * **🔄 서식 보존 무손실 라운드트립 (v3.0)**: 변환된 마크다운을 편집해서 `patchHwpx`(HWPX) / `patchHwp`(HWP 5.x 바이너리)에 넘기면, **원본 서식을 1바이트도 건드리지 않고** 바뀐 문단/표 셀의 텍스트만 원본 안에서 교체합니다. v3.7부터는 **표에 행을 추가/삭제하는 편집**도 원본 서식을 승계하며 반영되고, v3.8부터는 HWP 5.x의 **빈 셀에 값 넣기**도 지원합니다. * **🖼️ 레이아웃 보존 렌더 (v3.10~3.15)**: 한컴이 저장한 조판 캐시 좌표로 원본 레이아웃을 SVG로 재현하고, 캐시가 없는 파일(AI가 만든 HWPX·편집본)은 **순수 TS reflow 엔진**이 직접 조판합니다. 다페이지·표·그리기 도형·검색어 형광펜까지. 서버에 한컴 없이 HWPX 미리보기를 만들 수 있습니다. * **📊 차트 생성 (v3.16)**: 마크다운의 ```chart 펜스(type/cat/계열 라인)가 한컴 네이티브 차트(OOXML chartSpace)로 생성됩니다 — 막대·선·원·도넛·영역·분산·방사형 등 20종, 계열/조각 색 지정 가능. * **🔴 도장/서명 자동 날인 (v3.16)**: "(인)"·"서명 또는 인" 같은 앵커 문구를 찾아 도장 PNG를 글 앞 부유로 배치합니다. 표/페이지를 키우지 않아 날인 후 서식이 밀리지 않습니다 (`kordoc seal`). * **✏️ 양식 자동 채우기**: 공문서 양식 템플릿(신청서, 보고서)에 값을 넣으면 자동으로 빈칸을 채웁니다. 원본 서식(글꼴, 크기, 정렬)을 100% 보존합니다. * **👓 내장 OCR — API 키 없이 (v4.2)**: 스캔본·이미지 PDF와 PNG/JPG/WebP 이미지를 **로컬 CPU 추론**(PP-OCRv5 korean)으로 읽습니다. 외부 서비스도 API 키도 없이, 텍스트층이 깨진 페이지만 골라 OCR 하고, 래스터 괘선까지 찾아 스캔본에서도 표를 복원합니다. * **📑 RAG·인용 대응 (v4.1~4.8)**: 헤딩·개조식 위계를 breadcrumb으로 보존한 구조 청크(`--format chunks`)와, 조판 캐시로 복원한 **실제 쪽 번호** 기준 페이지별 마크다운(`pages`)을 냅니다 — 답변에 "몇 쪽" 각주를 붙일 수 있습니다. * **🕶️ 개인정보 마스킹 (v4.1)**: 주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허(v4.14.4 부터 opt-in 으로 이름·주소)를 탐지해 **원본 서식 그대로** 가린 HWPX/HWP를 냅니다 (`kordoc redact`). 본문·표·머리말/꼬리말·각주·글상자·필드·미리보기(텍스트·이미지)·문서 정보(제목·작성자)까지 가리고, 결과 파일을 다시 훑어 남은 개인정보가 있으면 실패(exit 2)로 알립니다. **PDF·DOCX·XLSX 등은 원본 파일을 고치지 않고 마스킹된 마크다운만** 냅니다 — PDF 자체의 가림(redaction)은 지원하지 않습니다. 이미지 속 글자와 문맥 없는 맨이름은 탐지하지 못하는 자동 검출 보조 도구이므로 공개 전 사람 확인은 필수입니다. * **🤖 AI 에이전트 연동 (MCP)**: `Claude Desktop`, `Cursor`, `Codex`와 같은 도구에서 직접 `kordoc`을 호출해 문서를 읽고 코딩할 수 있습니다. --- ## v4.15.4 변경사항 한국 PDF의 밀집 표 행과 클립 경계를 복원해 표 exact가 2,512/2,692에서 2,526/2,692로 늘었습니다. ODL 공개 PDF 200문서에서는 제목과 정렬된 수치표를 개선해 종합 점수가 0.724617에서 0.775354로 올랐습니다. 외부 하이브리드의 기존 예측을 재채점한 0.906572에는 아직 못 미칩니다. 남은 구조 오류와 세부 지표는 [CHANGELOG](CHANGELOG.md)를 참고하세요. ## v4.15.3 변경사항 쪽을 넘는 중첩표의 머리 행과 다음 쪽 본문이 감싸개 때문에 갈라지던 사례를 복원했습니다. PDF 중첩표 정답 176개 중 정확 일치는 157개에서 158개로 늘었고, 최상위 표 구조 정확 일치는 유지됐습니다. 셀 클립이 많은 PDF 쪽에서는 가까운 변끼리만 비교하도록 바꿔 클립 묶음 단계의 시간을 줄였습니다. 전체 문서 속도와 남은 정확도 한계는 [CHANGELOG](CHANGELOG.md)를 참고하세요. ## v4.15.2 변경사항 PDF 표의 좁은 시각적 간격을 빈 행·열로 잘못 늘리던 경우를 줄였습니다. 여러 행에 반복되는 실제 빈 열은 유지해, 기존 PDF 표 정답 2,692개의 정확도는 v4.15.1과 같습니다. 밀집 괘선의 교차점 처리에 쓰는 메모리도 줄였습니다. 일부 한 행짜리 머리표와 법령 양식의 빈 칸 구조는 아직 정확히 복원하지 못합니다. 자세한 수치와 남은 문제는 [CHANGELOG](CHANGELOG.md)를 참고하세요. ## v4.15.1 변경사항 PDF 표 복원과 대형 입력의 안정성을 보완했습니다. - **PDF 안정성과 속도**: 매우 긴 괘선 때문에 메모리가 폭증하던 문제를 고치고, 쪽 처리 후 자원 해제와 반복 그림 처리를 개선했습니다. 입력 ArrayBuffer를 재사용할 수 있으며, 쪽 수 상한으로 잘린 범위는 경고합니다. - **PDF 글·표**: 원점이 이동하거나 회전된 쪽과 Form XObject 안의 좌표 처리를 바로잡았습니다. 좁은 빈 열, 쪽을 넘는 중첩표·비고를 복원하고 표 아래 주석·출처가 꼬리말로 삭제되지 않게 했습니다. 쪽별 마크다운도 제공합니다. - **OCR**: JPEG의 EXIF 방향을 반영합니다. 큰 이미지는 최대 24 MP로 축소하고, 검출 상자는 3,000개까지 인식하며 축소·상한 초과는 경고합니다. 괘선 검출의 반복 계산도 줄였습니다. - **인명 마스킹**: 명시적인 속기록·회의록 문맥의 이름 4건을 추가 탐지했습니다(opt-in). 같은 외부 정답에서 361/411, 오탐 0건이며 미탐 50건은 남아 있습니다. 자세한 변경 내용은 [CHANGELOG](CHANGELOG.md)를 참고하세요. ## v4.15.0 변경사항 실문서 코퍼스를 보강하고 프로덕션 리뷰에서 확인한 파싱·보안·성능 문제를 고쳤습니다. - **긴 스프레드시트**: XLSX·XLS의 1만 행 무경고 절단을 수정하고, 칸 예산을 초과하면 경고합니다. XLSX는 XML을 행 묶음으로 읽어 대형 시트 메모리를 줄이고, XLS는 희소 격자를 사용합니다. 동아시아 날짜와 DOCX 머리글·바닥글도 보완했습니다. - **PDF 글**: 실제 낱말을 붙이던 균등배분 정리, 표 칸의 글자 조각, 날짜 빈칸, 넓은 줄간격의 문단 이음을 고쳤습니다. - **보안**: HTML 표 칸의 원문을 이스케이프하고, 인쇄·렌더 PDF는 JavaScript를 끄고 `data:`·`about:` 외 요청을 차단합니다. webhook의 IPv6 SSRF 방어와 MCP 쓰기 경로 제한도 보강했습니다. - **안정성과 속도**: CLI·MCP·parse-worker의 진단 메시지를 stderr로 보내 JSON 출력을 보호합니다. 확장자가 실제 형식과 다른 문서의 무손실 패치를 고치고, 문서 비교·여러 구간 치환의 반복 계산을 줄였습니다. - **인명·주소 마스킹**: 회의록 발언자·기관 직함 앞 이름·결재란과 도로명 변형을 보강하고 오탐을 줄였습니다(opt-in). - **디렉토리 감시**: `watch -d`가 하위 폴더 구조를 보존해 같은 파일명끼리 덮어쓰지 않습니다. [PR #82](https://github.com/chrisryugj/kordoc/pull/82), 기여: @ROTl24. - **검증 코퍼스**: 정책브리핑 HWPX↔PDF 300쌍, DOCX↔LibreOffice PDF 36쌍과 XLS 정답지 트랙을 추가했습니다. 자세한 실측은 [CHANGELOG](CHANGELOG.md)를 참고하세요. ## v4.14.4 변경사항 읽기 품질을 한 번 더 점검했습니다. 원본 HWPX 를 정답으로 PDF 글을 재는 벤치를 새로 세워 띄어쓰기·읽기 순서까지 보고, PDF 표·OCR·개인정보 마스킹을 고쳤습니다. - **📊 PDF 표**: 쪽을 넘는 표의 쪼개진 행과 반복 머리 행, 쪽을 넘는 한 칸, 표 위에 걸친 그림·글상자, 셀 간격 표를 바로잡았습니다. hwpx↔pdf 430쌍 1,784표 정확 일치 90.1% → 92.9%, 표 안의 표 63.7% → 72.0%. 텍스트층이 있는 417쌍만 보면 94.5%, 칸 글이 제자리에 있는 비율 0.768 → 0.903. - **✍️ PDF 띄어쓰기·줄 이음**: 본문을 시각 줄이 아니라 문단으로 복원합니다. 한글이 글자 단위로 줄바꿈된 문서에서 "재 일학도의용군인"·"또 는" 처럼 낱말 중간에 공백이 들어가던 것을 조사·어미·문서 안 어휘로 판정해 붙입니다. 어절 F1 0.925 → 0.971. - **🧮 한컴 밖에서 만든 PDF**: 예산서처럼 글자마다 떨어져 찍힌 숫자("2 0 , 7 7 5" → "20,775"), 행마다 끊어 그은 괘선, 빈칸 위에 따로 얹은 숫자를 바로잡았습니다. PDF 글자 커버리지 0.99569 → 0.99760. - **🔎 글자를 곡선으로 그린 PDF**: 한글을 글꼴 대신 곡선으로 그린 쪽은 텍스트층에 한글이 없어 종전엔 경고 없이 한글이 빠졌습니다. 이런 쪽을 찾아(`ocrReason: "vector_text"`) OCR 을 켜면 읽고, 끄면 경고합니다. 표는 그 쪽의 실제 괘선으로 복원합니다. - **👓 OCR**: 점선 괘선·색 칸 경계·목차 리더 점·숫자 앞 △ 를 바로잡았습니다. 글자 오류율 0.171 → 0.096(정답지인 텍스트층 수정분 포함), OCR 표 셀 F1 0.440 → 0.618. - **🕶️ 개인정보 마스킹 인명·주소** (opt-in, `--rules …,name,address`): 역할어·호칭·라벨·표 머리글 문맥으로 이름을, 도로명·지번 문법으로 주소를 찾아 가립니다(주소는 시·군·구까지 남김). 외부 정답(473문장) 인명 354/411·주소 141/141, 실문서 표본 오탐 0. 공무원 결재란 이름은 정보공개 관행상 공개 대상이라 기본값에는 넣지 않았습니다. ## v4.14.3 변경사항 읽기 품질을 전면 점검했습니다. 코퍼스를 넓히고(rhwp 표본 1,351파일·정책브리핑 hwpx+pdf 짝 200쌍) 포맷마다 정답지 벤치를 다시 세운 뒤 표·PDF·OCR·개인정보 마스킹을 고쳤고, 검색 색인처럼 글자만 필요한 호출자를 위한 두 가지를 더했습니다. - **📊 PDF 표 복원**: 쪽을 넘는 표를 잇고, 표 안의 표를 틀 칸 안에 넣습니다. hwpx↔pdf 430쌍 1,784표 정확 일치 64.1% → 90.1%, 셀 F1 0.790 → 0.945. - **🧾 HWP·HWP3·HWPX 표와 주석**: HWP 표를 HWPX 와 같은 규칙으로 배치해 hwp↔hwpx 쌍 3,593표가 모두 정확히 일치합니다(0.824 → 1). HWP3 표 격자를 복원하고, HWPX 각주·미주 번호와 문서 정보(제목·지은이 등)를 읽습니다. - **👓 OCR**: 기울기를 보정하고 세로로 이어진 글 상자를 나눠 읽으며 공문서 기호(○·△·따옴표)를 되살립니다. 글자 오류율 0.201 → 0.171, 3° 기울어진 스캔 57.6% → 22.0%. - **🕶️ 개인정보 마스킹**: 파일 안 모든 글자 저장소(머리말·각주·글상자·필드·미리보기·문서 정보 등)를 같은 길이로 가리고 결과를 다시 훑습니다. 5,081문서 오탐 387 → 0. - **💲 본문의 `$` 가 수식이 되지 않습니다**: 한글 문서(HWPX·HWP·HWP3)의 리터럴 `$` 는 `\$` 로 내고 `$…$` 는 수식에만 씁니다. "echo $HOME $PATH" 같은 글이 마크다운 렌더러에서 수식으로 바뀌던 것. 역슬래시 뒤 구두점("C:\.Pls")에서 역슬래시가 사라지던 것도 고쳤습니다. - **📝 미기입 누름틀 안내문을 빼고 읽습니다**: 한컴이 화면에만 흐리게 보이고 인쇄하지 않는 HWPX 안내문을 마크다운에서 뺍니다(블록 글에는 남김). 누름틀을 채우면 수정 표시를 켭니다. - **🖼️ 이미지 끄기** (`images: false` / `--no-images`): 결과에 이미지 바이트를 싣지 않습니다. 그림 자리 표시(`![image](…)`)와 본문 글자는 그대로라 그림 위치는 알 수 있습니다. PDF 는 PNG 인코딩을 건너뜁니다. 그림 많은 PDF 실측: JSON 출력 200MB → 9.5MB, CPU 시간 30% 감소. - **🚀 상주 파싱 워커** (`kordoc parse-worker`): 프로세스를 띄워 둔 채 stdin 요청 한 줄마다 한 줄 JSON 을 돌려줍니다. 파일마다 node 를 새로 띄우지 않아 대량 색인에 알맞습니다. 응답에 메모리 사용량(`rss`)을 실어 호스트가 워커 교체 시점을 정할 수 있습니다. ## v4.14.2 변경사항 공문서 출력을 한글 2024 실렌더 PDF로 다시 대조해 "진짜 공문처럼" 다듬었습니다. - **📐 항목 둘째 줄이 첫 줄 내용과 정확히 맞습니다**: 부호(□ ○ - ※ 1. 가.) 뒤를 공백이 아니라 탭으로 두고, 한글의 "내어쓰기용 자동 탭"을 씁니다. 양쪽 정렬이 부호 뒤 공백을 늘려 첫 줄 내용이 밀리던 것, 자간을 줄인 줄에서 내용이 당겨지던 것이 구조적으로 없어졌습니다. 기안문·보고서·계획서·통지·회의록·업무보고·개조식·보도자료 전부. - **✂️ 낱말이 줄 끝에서 쪼개지지 않습니다**: 본문을 어절 단위 줄바꿈으로 바꾸고("동대/문" → "동대문") 외톨이줄 보호를 켰습니다. 날짜·금액은 묶음 빈칸으로 묶어 "2026. 1. / 22." 처럼 갈라지지 않습니다. 곧은따옴표는 ‘ ’ “ ”로 바꿉니다. - **📏 한글 글꼴 실폭으로 조판을 재현합니다**: 한컴돋움·HY견고딕·휴먼명조 등 8종의 실제 글자 폭으로 줄바꿈을 계산합니다(한글 2024 PDF 154줄 전부 일치). 마지막 줄이 짧으면(줄 폭 절반 이하) 자간·장평을 최대 15%까지 줄여 한 줄 올리고, 한 줄에 맞춘다는 판단엔 2% 여유를 둬 한글에서 넘치지 않게 했습니다. 공백 없는 긴 목록("구(강남·강서·…·종로)가")처럼 한 줄보다 긴 어절이 있는 문단은 그 문단만 글자 단위로 조판하되 가운뎃점·쉼표 뒤에서만 끊어, 앞 줄이 크게 벌어지지 않습니다. - **🧩 PPTX 감지** (#80, PR #81 @LimePencil): PPTX 를 넣으면 "HWPX 섹션 없음" 대신 지원하지 않는 형식이라고 알려 줍니다. - **🧹 기술부채**: 1,200줄 넘던 `mcp.ts`·`cli.ts`·`hwp5/parser.ts`·`svg-render.ts` 를 기능별 모듈로 나눴고, 파서가 묶음 빈칸을 버리던 것과 `kordoc render` 미리보기의 탭 폭·줄 끝 공백 정렬을 고쳤습니다. ## v4.14.0 변경사항 - **🏛️ 중앙부처 업무보고 프리셋 `업무보고`**: 재정경제부 「2차 업무보고 서면보고자료」(2026. 7. 15., 17쪽)를 글꼴·크기·색·도형 좌표까지 전수 실측해 국회 서면보고형 골격을 그대로 냅니다 — 표지(대외주의 박스 `--cover-label`, 파란 바 두 줄), 목차 박스, `##` Ⅰ. 장 띠(그라데이션+파랑 이중선, 장마다 새 쪽), `###` 파란 숫자칸 절, `####` 남색 소제목 박스, `#####` ① 하늘색 항목 띠, `> ▪ …` 연노랑 성과 요약박스, `## 별첨 …` 별첨 띠. 본문 함초롬바탕 15·각주 맑은 고딕 12·표 맑은 고딕 12, **□ 뒤 `(키워드)`·`[키워드]` 는 파랑 굵게**(ㅇ 뒤는 검정 굵게), ❶⇒↳ 부호 보존. `kordoc generate 보고.md --preset 업무보고 --date "2026. 7. 15." --cover-label 대외주의`. 한글 COM 실렌더로 원본과 대조했습니다. - **🎨 표 셀 테두리에 색·굵기 직접 지정**(파랑 이중선·하늘색 0.4mm 등)과 LINEAR 그라데이션 — 3색 그라데이션은 한글에서 검게 칠해져 2색으로 고정. ## v4.13.1 변경사항 - **🖼️ HWP(5.x)도 조판 그대로 렌더**: `kordoc render 문서.hwp --format png -d ./pages`, `renderDocument("문서.hwp", …)`, MCP `render_document`·`crop_regions` 가 `.hwp` 를 받습니다. 한컴이 저장한 HWP5 의 조판 캐시(줄 좌표·셀 격자·개체 앵커)를 HWPX 와 같은 렌더러로 그리므로, 같은 문서를 hwp/hwpx 로 각각 저장한 10쌍에서 페이지 수·표 위치·괘선 굵기가 HWPX 렌더와 일치합니다. 표 영역 id 는 문서 순번(`t1`, `t2`…)이고 파서 결과의 `sourceId` 와 같아 `kordoc tables 문서.hwp --visual all -d ./tables` 도 HWP 에서 조직도 crop 까지 됩니다. 머리말·꼬리말·수식은 HWPX 와 같이 미렌더. - **🧭 MCP `extract_tables`**: 표 분류(데이터표/조직도류/불확실) + 페이지·bbox + crop 을 MCP 에서도. 응답에 crop 8장까지, `output_dir` 에 tables.json. - **🖨️ MCP `render_document` 포맷 확장**: `format: jpeg|html|pdf` 추가(html/pdf/svg 는 `output_path` 로 저장), `max_width_px`. - **🎨 띠 제목 색**: `--band-color #DFE6F7 --band-text-color #000000`(교육청형 밝은 띠). 기본은 실측 최다 남색 #003366·흰 글자. - **📏 개조식 문단 간격 재검증**: 실결재 428건을 `hp:case`(한컴 실렌더 값) 기준으로 다시 재어 □·ㅇ·- 문단 위 간격 0 이 84~96% 임을 확인, 엔진 값 유지. `docs/gongmunseo-reference.md` 2.8 에 □ 앞 간격 10pt 근거 추가. - **🔧 crop 이 표의 좌상단 1/4 만 잘리던 결함 수정**: sharp 최신판이 pt 단위 SVG 의 배율을 제곱으로 적용해 래스터가 보고값의 2배로 나오던 것 — 이제 실제 픽셀 크기로 환산하고 `render_document` 의 PNG 도 `max_width_px` 를 지킵니다 (v4.13.0 HWPX `crop_regions`·`kordoc crop` 도 같은 결함이었음). ## v4.13.0 변경사항 공문서 생성 엔진을 다시 설계했습니다(v5). 서울 정보소통광장 결재문서 **629건을 전수 실측**해 위계·글꼴·들여쓰기·골격을 스킴 하나에 박고, 기안문·보고서·계획서·통지·회의록 생성을 새 엔진으로 갈아탔습니다. 어떤 형태의 마크다운(`#/##/###`, 리스트, □ ㅇ - 1. 가. 명시 부호)을 던져도 같은 위계로 나옵니다. - **📐 위계 = 실결재 그대로**: 개조식형 □ HY견고딕 17pt 굵게(0타) → ㅇ 한컴돋움 15pt 굵게(1타) → - 휴먼명조 14pt(3타) → ㆍ, ※ 한컴돋움 14. 법정형 굴림체 12pt 160%, `1.` 0타 → `가.` 2타 → `1)` 4타(2타 계단), 내어쓰기는 부호폭+1타. 표는 한컴돋움 12(헤더 굵게·#DFE6F7). 근거는 `docs/gongmunseo-reference.md` 2.8. - **📏 □·제목은 절대 두 줄로 안 꺾입니다**: 장평 → 자간 → 글자 크기 순으로 줄여 한 줄에 담고(실측 관행), 그래도 안 되면 경고합니다. 표 셀도 12→11→10pt 자동 축소. - **📋 기안문 두문표·결문표**: 실결재 표 그대로 — 슬로건·기관명(굴림 20 굵게 자간띄움)·수신/(경유)/제목, 발신명의·회색 띠·결재선(직위/성명/일자)·협조자·시행/접수·주소·전화/전송/이메일/공개구분. 수신이 '내부결재'면 발신명의 생략. `--doc-head "org=광진구,slogan=…,to=…,title=…"` `--doc-foot "sender=…,drafter=주무관 홍길동,…,zip=…"`. - **📑 보고서(서울 실무 보고서형)**: 제목표(HY헤드라인M 25 굵게, 상 0.4mm/하 0.15mm) + 담당자 행(`--report-info`) + 요약박스(`--summary` 또는 제목 직후 `>`) + `Ⅰ. Ⅱ.` 장(h2) + □/ㅇ/- 본문. `--cover --dept 스마트도시과 --doc-info "docNum=…"` 로 표지(문서정보표·결재선·파랑 띠 제목·기관명). - **✍️ 실무 디테일**: `출처:`/`자료:`/`근거:` 줄은 자동으로 ※ 참고(13pt 작은 글씨), 둘째 줄이 한 줄의 20% 이내로 삐져나온 항목은 자간을 줄여(Shift+Alt+N 관행) 한 줄에 담고, 줄바꿈은 실결재 76%가 쓰는 글자 단위+양쪽정렬(어절 유지는 긴 어절 앞 줄이 벌어져 기각, 영문·숫자는 단어 유지), 법령 코드 `(282791)`·KOSIS 표 ID `DT_…`·"○○ MCP 조회" 같은 내부 식별자는 자동 제거. 보고서는 제목 직후 인용문(`>`) 한 문장("…하고자 함", 부호 없이 3줄 이내)이 요약박스가 됩니다(없거나 넘치면 경고). - **⚙️ 기본값 변경**: 기안문 본문 굴림체 12(함초롬바탕은 `--font myeongjo`), 보고서·계획서 여백 13/13/18/18·줄간격 180%·2단계 부호 ㅇ(중앙부처 개조식만 ○), h2는 장(`--h2-marker roman|number|box|none`). 개조식(`개조식` 프리셋)·보도자료는 종전 그대로. - **🏷️ 장 제목 띠 표**: 보고서·계획서의 `## 장 제목`이 로마자 채움 칸 + 제목 칸(밑줄) 표로 나옵니다(계획서 실결재 37~39% 관행). 종전 `Ⅰ. 제목` 텍스트는 `--h2-marker roman`. 맥 한컴에서 글꼴 칸이 비고 스타일이 영문명으로 뜨던 산출물 결함도 수정(7개 언어 글꼴 슬롯 통일·`langID`). - **📊 표 열폭은 중요도 순**: `비고`·`근거`·`참고`·`담당`·`연락처` 열과 내용 열이 있는 표의 마지막 열은 25% 이내로 좁게(실결재 462표에서 비고 열 중앙값 21%), `내용`·`사항`·`실적`·`계획`류 열은 넓게(중앙값 51%) 왼쪽 정렬. 긴 근거 텍스트가 최광열을 차지하고 내용이 두 줄로 꺾이던 결함. 요약박스는 문단 좌우 여백 1000(실측 55%)으로 글자가 테두리에 붙지 않습니다. - **📊 코퍼스**: `bench/corpus-gen/opengov-2609/` 7종 필터 280건 추가(계획·결과보고·방침·안내·회의·2024·2022). - **💰 금액 한글 병기 자동 계산**: `금113,560원` 처럼 한글 병기가 빠진 금액은 경고와 함께 `금113,560원(금일십일만삼천오백육십원)` 실제 값을 제안합니다(규정 시행규칙 제2조). 하이픈 날짜 `2026-07-18` 도 잡아서 `2026. 7. 18.` 로 바꿔 줍니다(URL·파일명·표 셀은 제외). - **🔣 항목 부호 확장**: `❑ ❏ ㅁ`(대항목)·`◎`(중항목)·`ㅡ ‣ ▪ ▫`(세부) 도 □/ㅇ/- 와 같은 위계로 읽습니다. - **🖼️ 렌더 통합 계층 (#75)**: `renderDocument(파일, { format: "svg"|"html"|"png"|"jpeg"|"pdf", pages: "2-4" })` 하나로 페이지별 SVG·자급자족 레이아웃 HTML·페이지별 PNG/JPEG·PDF(Chromium 필요)를 냅니다. 렌더 결과에는 문단·표·이미지·도형의 **페이지 로컬 pt bbox 와 결정적 id**(`RenderScene.regions`, SVG `data-kordoc-id`)가 붙고, `extractRenderedRegions()` / `kordoc crop 문서.hwpx --target table -d ./regions` 로 그 영역을 실배율로 잘라냅니다. `kordoc render --format png --pages 2-4 -d ./pages`, MCP `render_document` 의 `pages`, `crop_regions`. HWP5 렌더는 후속. - **🧭 표 분류·시각 추출 (#76)**: `parse(파일, { classifyTables: true })` 로 표마다 `semantic-table`(데이터표) / `non-tabular-layout`(표를 캔버스로 쓴 조직도·연락망) / `uncertain` 분류가 붙습니다(휴리스틱, 네트워크·LLM 없음, 중첩표 독립 분류). `extractTables(파일)` / `kordoc tables 문서.hwpx --visual non-tabular-and-uncertain -d ./tables` 는 분류 + 렌더 영역 + crop 을 한 번에 — 조직도는 이미지로, 데이터표는 구조로 넘기는 멀티모달 파이프라인용. 병합 없는 단순 표의 셀 이미지가 마크다운에서 사라지던 결함도 함께 수정. ## v4.12.3 변경사항 공문서 작성 쪽 라운드. 실결재 기안문 206건·보고서 337건의 항목부호 단계별 글꼴을 실측해 **위계 폰트 옵션**을 넣고, 표기법 검수의 쌍점·날짜 룰 오탐을 법정 서식 근거로 좁혔습니다. 별표 코퍼스 3차(183쌍)를 더해 게이트 모수는 hwpx ~1,390·pdf ~950·hwp쌍 ~860 입니다. - **🔤 위계 폰트 `levels`**: 항목부호 단계(0~7)마다 글꼴·크기·굵기를 지정합니다 — `--levels "0=HY견고딕/17/bold,1=한컴돋움/15/bold,2=휴먼명조/14"`, MCP `levels`. 실측: 법정 8단계(1. 가. 1))는 본문과 동일이 90% 라 기본값은 그대로이고, 전자결재 기안문의 □/ㅇ/- 계열은 □ HY견고딕 +2~3pt 굵게 · ㅇ 한컴돋움 굵게 · - 휴먼명조가 지배 관행입니다(`docs/gongmunseo-reference.md` 2.7). 내어쓰기 폭도 그 단계 글자 크기로 맞춥니다. 미지정이면 산출물 불변. - **📝 표기법 룰 좁힘**: `COLON_SPACE` 는 표 셀을 건너뜁니다 — 법정 별지서식 자체가 "성 명 :" 라벨 셀을 쓰므로(서식 595건의 표 셀 801건 전부 라벨) 규칙 대상이 아닙니다. 본문의 "일 시 : 값"(기안문 206건 중 100건, 414건)은 편람상 위반이라 그대로 경고합니다. HTML 태그·마크다운 강조 닫힘 뒤 쌍점("성명:", "과정:** 붙임") 오탐도 제거. `DATE_NO_SPACE` 는 법제처 연혁 표기(`<개정 2012.2.14>`·`삭제 <2016.2.29.>`·`[시행일:2017.9.8.]`)를 제외합니다(서식 156건 → 10건). 기안문의 문서번호 인용 "○○과-123(2026.7.1.)호"(103건)는 편람 날짜 표기 위반이라 유지. - **📄 PDF 가운뎃점**: 한컴 PDF 가 가운뎃점(ㆍ)을 조합형 아래아(U+119E)로 내던 것을 되돌립니다(별지서식 573쌍 실측 340자·41문서). - **📄 PDF 1×1 표 줄 보존**: 선서문 안쪽 상자처럼 중첩표 없는 1×1 표는 줄마다 문단으로 내어 "선 서 나는 헌법을 …" 처럼 제목 줄이 본문에 붙지 않습니다(표 셀 줄바꿈 보존 정책과 정합). - **📄 PDF 제목 아래 틀**: 테두리 없는 1칸 틀(별표 1×1 프레임·선서문 바깥 틀)을 "페이지 반복 클립" 으로 가르려던 가설은 반증됐고(본문 영역 클립은 쪽마다 좌표가 다르고 별표는 1쪽), 대신 **제목 아래(윗변 ≥ 20%)·본문 폭(≥ 60%)·위에 글이 있는** 컨테이너를 틀로 봅니다. 채용공고 2단 상자는 폭 조건으로 제외(pdf-table-gt 게이트 유지). - **🖋️ HWP 결재 기호 하나 더**: 한컴 PDF 실렌더로 확인한 네모 안 "인"(U+F00E1, HWP5 A0E1)을 "(인)" 으로 냅니다. HWP5 하이픈 제어문자(0x18)는 한컴이 그리지 않으므로("60g/㎡") 더 이상 "-" 를 내지 않습니다. - **📊 별표 코퍼스 3차**: `licbyl-byl2/` 183쌍(seed 20260907). 하위 30건 분해 — 1×1 틀 PDF 미감지 8 · HWP 레이아웃 해체 vs PDF 1열 유지 15 · 구조 차 7(수식 셀·쪽 경계 셀 분할·줄바꿈, 파서 결함 없음). HWP↔PDF 셀 일치 별표 0.728 → 0.746, 3차 0.772 → 0.787, 서식 0.965 유지. ## v4.12.2 변경사항 별지서식 라운드 2. 코퍼스를 서식 279쌍·별표 90쌍 더 모아(총 1,995파일) HWP·HWPX·PDF 세 파서가 **같은 IR 모양**을 내도록 맞췄습니다. HWP↔PDF 셀 텍스트 일치 0.927 → 0.965, PDF 표 GT cellExact 0.945 → 0.980 을 실측했고 게이트 플로어를 그 수치로 올렸습니다. - **🪆 PDF 틀 안 중첩표**: 지정서·영치증·선서문처럼 1칸 틀 안에 "발신명의 | 직인" 표가 든 서식에서, PDF 가 그 표를 틀 뒤 별도 블록으로 흘리던 것을 틀 셀 안에 문단·표 원문 순서로 넣습니다(HWPX 파서와 같은 모양). 네 변에 테두리가 그려진 1칸 틀은 표로, 그 안에 홀로 든 상자는 중첩표로 살립니다. 테두리 없는 바깥 틀은 한컴 본문 영역 클립과 구분할 수 없어 표로 삼지 않습니다. - **🖋️ HWP 결재란 "(인)" 복원**: HWP 5.x 는 2바이트 문자라 한컴 전용 기호(U+F012B)를 U+A000대에 접어 저장합니다. `ꄫ` 로 새던 결재란 기호가 "(인)" 으로 나옵니다. - **📋 HWP 서식 틀 보존**: 중첩표를 품은 별지서식 3×1 틀(제목행·틀·꼬리행)을 레이아웃 표로 보고 문단으로 해체하던 것을 표로 남깁니다. 페이지 사슬 레이아웃 표(글이 많은)는 종전대로 해체합니다. - **📝 표기법 검수 정밀화**: 실결재 기안문 206건·별지서식 595건으로 오탐을 실측해 `TILDE_SPACE` 는 숫자·날짜·시각 범위에만, `DUEUM_ERROR` 는 서식 기입란(" 년도", "( 년간)")과 표 머리글을 건너뜁니다. - **🧾 양식 인식이 틀 안 중첩표까지**: `extractFormFields` 가 셀 안 중첩표의 라벨-값을 훑습니다(`fillHwpx` 와 같은 경계). - **📊 `bench/cmp-hwp-pdf.mjs`**: HWP↔PDF 셀 텍스트 Jaccard 보고 지표 정식 편입. `--linebreaks` 로 PDF 셀 줄바꿈 자리의 어절 경계 비율(85%·글자 단위 13%)을 실측해 줄 결합은 하지 않기로 했습니다. ## v4.12.1 변경사항 법령 **별지서식**(법제처 별표·서식) 파싱을 HWP·HWPX·PDF 세 포맷에서 맞췄습니다. 법제처 OpenAPI로 서식 300건의 HWP 원본과 PDF를 쌍으로 모으고 rhwp 변환 HWPX를 붙인 900파일 코퍼스를 게이트에 편입해, HWP↔PDF 셀 텍스트 일치 0.79 → 0.92, PDF 표 GT cellExact 0.73 → 0.96 을 실측했습니다. - **📐 PDF 셀 클립 그리드**: 한컴 PDF는 표 셀마다 클립 사각형을 깔고 글을 찍습니다. 별지서식 외곽 표는 테두리 "없음" 셀이라 괘선만 보는 종전 경로가 표를 놓치고 제목·기입란이 헤딩과 문단으로 흩어졌는데, 이제 클립 사각형 묶음을 **셀 기하가 확정된 표**로 바로 씁니다. 도선사면허 신청서가 HWP 파서와 같은 23열·같은 병합 구조로 나옵니다. 클립의 포함 관계로 층을 나눠, 지정서·증서의 1칸 테두리 틀은 제목행·꼬리행과 한 표의 셀이 되고 안쪽 "발신명의 | 직인" 표는 별도 표로 살립니다. - **➔ 심볼 폰트 글리프 복원**: 처리절차 화살표·체크박스를 Wingdings로 찍은 PDF에서 `è` 같은 깨진 라틴 문자가 남던 것을 유니코드(➔ □ ✔ ☑)로 되돌립니다. - **📝 표기법 검수 6룰 보강**: 금액 괄호 한글 병기(`MONEY_NO_HANGUL`), 물결표 앞뒤 붙여쓰기(`TILDE_SPACE`), 두음법칙 '년도→연도'(`DUEUM_ERROR`), 외래어 오기 40종(`LOANWORD_ERROR`, 표준 표기 제안), 차별·비하 표현 25종(`DISCRIMINATORY_TERM`, 순화어 제안), 붙임 있는데 "끝." 없음(`END_MARK_MISSING`, `kordoc lint` 전용). 시중 HWPX 공문 도구(pyhwpxlib·hwpx-skill)의 검사 항목과 대조해 비어 있던 축을 채웠습니다. - **🏛️ 내부결재 문서의 발신명의 생략**: 수신이 "내부결재"인 기안문은 결문에 발신명의를 적지 않습니다(행정업무규정 시행규칙). - **🩹 기입 빈칸 보존**: "년 월 일"·"시 분"이 "년월일"로 붙던 것, 청구서류 1열 틀 표의 기입 항목이 한 줄로 뭉개지던 것을 고쳤습니다. ## v4.12.0 변경사항 v4.11.0 이 걷어낸 HWP3 유실의 **잔여 전량**을 처리했습니다. rhwp `samples/` 의 HWP3 원본 9종을 한컴 변환본과 문자 멀티셋으로 대조하면, 이제 변환본에만 있는 문자는 그림 대체텍스트를 빼면 **0** 입니다. - **🖼️ 그리기 개체 안 글상자 텍스트 회수 (#73)**: HWP3 의 ch=11(그림) 확장 블록은 `pic_type` 이 3 이면 그림이 아니라 **그리기 개체 트리**입니다. 표지 제목·순서도 라벨처럼 눈에 잘 띄는 본문이 그 안 글상자에 들어가는데, 종전에는 블록을 통째로 건너뛰어 사라졌습니다(sample16 618자, sample19 86자). 프레임 헤더 → 도형 트리(형제·자식 비트)를 훑어 글상자 문단 리스트를 본문과 같은 파서로 읽습니다. 비-글상자 도형이 '글상자로 만들기' 로 같은 블록을 실은 경우도, **잉여 길이가 스펙 표 78 과 정확히 맞을 때만** 회수합니다. 트리 해석은 확장 블록 슬라이스 안에서만 하므로 실패해도 본문 스트림 동기가 깨지지 않고 종전 동작으로 되돌아갑니다(재귀 256단계·도형 4,096개 상한). - **🔣 비가시 마커가 대체 문자로 새던 것**: 새 번호·쪽 번호 위치·쪽 감추기 제어 문자 자리에 ``(U+FFFC)를 심어 마크다운에 그대로 남았습니다. 한글도 그 자리에 아무 글자를 내지 않습니다 — 차례 표식과 같은 계약으로 맞췄습니다. ## v4.11.0 변경사항 rhwp 최신 devel(v0.8.3~0.8.4)을 훑어 kordoc 의 HWP3 디코더에 반영했습니다. 네 결함 모두 **글자가 경고 없이 사라지는** 형태라, 변환은 성공했는데 본문 일부가 비어 있는 식으로만 드러납니다. - **🈳 HWP3 기호·한자 유실 (완성형 좌표 규칙 누락)**: HWP3 은 KS X 1001 기호행(0xA1~0xAC)을 행 간격 96, 한자행(0xCA~0xFD)을 행 간격 94 로 편 코드에 문자를 담습니다. rhwp 에서 johab 디코더를 포팅할 때 하드코딩 표만 옮기고 **이 규칙 두 개를 빠뜨려**, 표에 없는 코드는 전부 삭제됐습니다 — `채권(債權)조서` 가 `채권()조서` 가 되고 `※ ○ 【】 ∴ ☞ ₩ ━` 같은 기호가 통째로 사라집니다. 규칙을 이식하고, 표준 매핑과 한컴 표기가 갈리는 두 자리(`∼→~`, `⊙→◉`)를 보정했습니다. - **🔤 사적 코드 실측 표 확장**: 라틴 확장(`ü·ö·ä·ß` 가 지워져 "für"→"fr" 이 되던 것)과 rhwp #5860 의 실측 28코드를 이식하고, rhwp 표에도 없던 코드를 직접 실측해 더했습니다 — 괘선 조각 6종, 겹줄, 원문자·괄호문자 계열(`⓪①②`·`ⓐ~ⓕ`·`㉠~㉢`), 글머리표 `•` 등. 근거는 HWP3 원본과 같은 문서의 한컴 변환본을 문맥 정렬한 것으로, **코드 출현 횟수가 변환본의 해당 문자 개수와 정확히 맞는 것만** 실었습니다. - **✒️ 초성 없는 아래아 음절 유실**: 초성이 '채움'인 아래아 음절(`ㆍ` 단독)을 무효 초성으로 보고 버렸습니다. 한컴 변환본과 같이 자모 하나로 남깁니다. - **🧱 서식 run 이 PUA 정리를 건너뛰던 결함 (전 포맷)**: 굵게·밑줄이 걸린 문단은 span 경로를 타는데 여기서만 PUA 치환·제거를 하지 않아, 한컴 전용 글머리표·괘선 조각이 **원시 PUA(두부 문자) 그대로** 마크다운에 실렸습니다. HWP5·HWPX·HWP3 공통 경로입니다. 함께 rhwp 의 한컴 PUA 검증표(한컴 PDF 대조 확정)에서 빠져 있던 22종(`┌┬┐└┘│`·`┈═━`·`⓪①②④~⑨`·`✺◇▸□`·`⊞⊟`)을 동기화했습니다. 검증은 rhwp `samples/` 의 HWP3 원본 9종을 같은 문서의 한컴 변환본과 문자 멀티셋으로 대조했습니다. 변환본에만 있는 문자(=HWP3 경로에서 잃은 문자)가 `hwp3-sample11` 189→0, `hwp3-sample16` 1,139→618, `hwp3-sample10` 172→11 로 줄었습니다. 남은 618자는 **그리기 개체 안 글상자**(표지 제목·순서도 라벨)로, kordoc 은 아직 그리기 개체를 건너뜁니다. ## v4.10.0 변경사항 - **📡 실패 계약 전 포맷 확장 (#69)**: 실패 JSON(`success:false` + `code`)이 `--format json` 전용에서 **markdown·chunks 포함 전 포맷**으로 확장됐습니다. 헤드리스 파이프라인이 stderr 한국어 문구 파싱 없이 원인 코드로 분기할 수 있습니다. `code` 값 집합·종료 코드 규칙·안정성 보증을 README [실패 계약](#실패-계약--기계-판독-가능한-실패-json-v4100-69) 표로 문서화했습니다. (@sorbetsharkroundhand 제보) - **🖼️ `images/manifest.json` (#70)**: 이미지 저장 시 `[ { name, mimeType, bytes, source } ]` manifest 를 함께 방출합니다. `mimeType` 은 매직바이트 실측 우선이라 확장자 추측이 필요 없습니다. DOCX 이미지의 미지 확장자를 `image/png` 로 단정하던 오폴백도 실측 판별로 교체. (@sorbetsharkroundhand 제보) - **🩹 patchHwp soft-wrap 축소 치환 무결성 (#71)**: 자동 줄바꿈으로 LINE_SEG 가 2세그먼트 이상인 문단을 더 짧은 한 줄로 치환하면 잔존 세그먼트의 textpos 가 새 nChars 밖을 가리켜 **한컴이 "문서 손상/변조" 경고로 열기를 거부**하던 버그 수정 — 범위를 벗어난 꼬리 세그먼트만 잘라내고 lineSegCount 를 정합화합니다(유효 세그먼트는 보존해 soft-wrap 렌더 유지). 재작성 압축 스트림에 한컴 실저장본의 8바이트 꼬리(CRC32+비압축 크기, 코퍼스 실측 7/7)도 복원합니다. (@heesun-woodi 제보) ## v4.9.2 변경사항 `` 출처행이 두 줄을 넘어가는 실제 보고서를 한글로 열어 확인하고 고쳤습니다. - **📌 다줄 출처행 왼쪽정렬 폴백**: `` 문단(출처행·발신일자)이 본문폭을 넘겨 줄바꿈되면 오른쪽정렬 특성상 **왼쪽 끝이 줄마다 들쭉날쭉**해져 들여쓰기가 깨진 듯 보였습니다(한글 실렌더 QA — 3줄 출처행). 이제 조판 폭을 미리 계산해 한 줄에 들어가면 종전대로 우측 배치(실측 GT6/GT7/GT11 관행), 넘치면 왼쪽정렬로 방출합니다. - **🔤 출처행 캡션체**: `출처:`·`자료:`로 시작하는 `` 행은 본문과 같은 크기라 캡션으로 읽히지 않았습니다. 전용 charPr을 신설해 **본문보다 3pt 작게**(하한 10pt), 실측 프리셋(개조식·보고서·계획서)은 한양중고딕, 그 외 프리셋은 본문 폰트로 방출합니다. 표 아래 출처를 본문과 구분하는 실무 관행을 따른 것으로, 발신일자 등 다른 `` 행은 본문 크기를 유지합니다. ## v4.9.1 변경사항 실제 자치구 검토보고서를 뽑아 한컴으로 열어보고, 눈에 걸리는 것을 코퍼스 555건 실측과 대조해 고쳤습니다. 세 결함 모두 **양식 파일 하나의 저장값을 실무 관행보다 앞세운 것**이 원인이었습니다. - **📐 `○` 항목 사이 간격 정상화**: 문단 위 간격 기본값이 `□15pt/○10pt/-6pt`(「2_보고서 양식」 한 파일의 저장값)였는데, 코퍼스 실측은 정반대입니다 — `□` 582문단 중 **88%**, `○` 799문단 중 **88%**가 간격 **0**이고 종전 값은 상위 6위에도 없습니다(2위가 1.5pt). 줄간격 160%에 10pt가 더해져 항목 사이가 1.4줄로 벌어지던 것을 실측 최빈값으로 되돌렸습니다(`□`만 절 구분용으로 실측 2위인 1.5pt 유지). - **📑 `□` 아래 `가./나.` 소제목 들여쓰기**: h3·h4 문단에 왼쪽 여백이 없어, `□`가 내어쓰기로 부호를 왼쪽에 내미는 동안 소제목이 대항목보다 **왼쪽**에 놓이며 계층이 사라졌습니다(실렌더 확인). `□` 부호폭만큼 들여써 대항목 제목 글자와 맞춥니다. - **📎 붙임 항목 번호 유실 수정**: `붙임 1. …` 다음 줄의 들여쓴 `2. …`가 마크다운 리스트로 잡혀 항목부호(`ㆍ`)로 치환되며 **번호가 사라지던** 결함을 고쳤습니다. 붙임 전용 블록으로 처리해 실측 관행을 따릅니다 — 앞에 빈 줄 한 줄(실측 343건 중 95%), 번호 `1. 2. 3.` 유지(부호 치환 실측 0건), 둘째 항목 선행 공백 보존으로 첫 번호와 세로 정렬(실측 123건 중 122건). - **✍️ 개조식 문체 검수 (`kordoc lint --munche`)**: 표기법과 축이 다른 **문체** 12룰을 추가했습니다 — 서술형 `~다` 종결(실측 0%), `~해야 한다` 당위, `A가 아니라 B(추상어)` 수사(실측 0건), 물음표·느낌표(본문 0건), 대구 슬로건, 항목 70자·결론 60자 초과, 리드문 `~하고자 함.`. 보고서·계획서·개조식 프리셋의 `generate` 경고 채널에 자동으로 붙고(생성은 막지 않음), `kordoc lint` 에서는 `--munche` 로 옵트인입니다. 기안문(경어 종결)·통지·회의록·보도자료는 문체 관행이 달라 적용하지 않습니다. 실측 근거와 규칙표는 [`docs/gaejosik-munche.md`](docs/gaejosik-munche.md). 통계 출처는 [jkf87/hwpx-skill](https://github.com/jkf87/hwpx-skill) v1.17.0 의 실무부서 보고서 15건(2,288줄) 실측입니다. ## v4.9.0 변경사항 - **🧹 공문서 AI 슬롭 검수 (lint `AI_*` 룰)**: 생성형 AI 초안이 공문서로 흘러들 때 남는 문체 흔적을 표기법 검수에 추가했습니다 — 줄표 사용(`AI_EM_DASH`: — – ―), 한 줄 강조(볼드) 3회 이상(`AI_BOLD_OVERUSE`). `kordoc lint` 와 `generate` 경고 채널에 공통 적용되는 조언용 warning 이며, 편람 13룰 원전과 구분되는 kordoc 자체 룰입니다. 실제 자치구 검토보고서를 공문서 HWPX 로 뽑는 작업에서 역도출했습니다. 작성 지침은 `.claude/skills/gongmunseo/`(줄표→쉼표·괄호, 강조는 핵심 한 곳, 외래어→행정용어)에 함께 반영. - **📄 렌더러가 명시적 쪽 나눔(`pageBreak="1"`)을 존중**: 한컴 '쪽 나누기'로 저장되는 `` 속성을 reflow 렌더가 무시하고 이어 그리던 것을 수정 — 이제 해당 문단부터 새 페이지로 조판합니다. 개조식 프리셋의 장 배너, 후처리로 쪽을 나눈 생성본이 한컴과 같은 페이지 경계로 렌더됩니다. ## v4.8.0 변경사항 - **📑 `--format json` 에 페이지별 마크다운 (#68)**: JSON 결과에 `pages: [{ pageNumber, markdown }]` 이 기본으로 들어갑니다. v4.7.3 의 실제 페이지 경계(`pageMode: "layout"`)를 그대로 써서, RAG 인용 각주나 뷰어 페이지 동기화에 쪽 단위 본문을 바로 쓸 수 있습니다. 문서를 다시 파싱하지 않고 이미 만든 블록의 `pageNumber` 로 가르기 때문에 비용은 파싱 시간의 1% 미만입니다(24쪽 PDF 기준 parse 399ms / pages 2.5ms). `--pages 3-5` 를 쓰면 `pages` 에도 3~5쪽만 담기고, 페이지 번호를 매기지 않는 포맷(DOCX 등)에서는 `pages` 자체가 없습니다. 라이브러리에서는 `blocksToPages(blocks)` 로도 같은 값을 얻습니다. (@sorbetsharkroundhand 제안) ```jsonc { "markdown": "# 전체 문서…", "pages": [ { "pageNumber": 1, "markdown": "# 1페이지…" }, { "pageNumber": 2, "markdown": "2페이지…" } ], "blocks": [/* … */], "metadata": { "pageCount": 2, "pageMode": "layout" } } ``` 여러 페이지에 걸친 표는 현 IR 구조상 시작 페이지의 한 블록이라, 표가 이어지는 중간 페이지의 `markdown` 은 빈 문자열입니다(항목 자체는 남깁니다 — 배열 길이 = 쪽수). ## v4.7.3 변경사항 - **📄 HWP/HWPX 실제 페이지 경계 복원 (#66)**: 한컴 저장본의 조판 캐시(HWPX `linesegarray` / HWP5 `PARA_LINE_SEG`)로 실제 페이지를 복원합니다 — `pageCount`·블록별 `pageNumber` 가 섹션 근사가 아닌 **실제 쪽 번호**가 되고, `parse(buffer, { pages: "3-5" })` 가 실제 3~5쪽을 반환합니다. 신호 4종(vertpos 역행·명시 쪽나눔·분할 표의 셀 흐름 리셋·분할 직후 이중 카운트 억제)을 결합해 실코퍼스 hwp↔hwpx↔pdf 쌍 대조에서 페이지 수 전수 일치. 조판 캐시가 없는 생성 파일은 종전대로 섹션 근사로 동작하며, 새 메타데이터 **`pageMode: "layout" | "section"`** 으로 구분됩니다(근사 상태에서 `pages` 필터 사용 시 `PAGE_BOUNDARY_APPROXIMATE` 경고). RAG 페이지 인용·뷰어 동기화용. (@sorbetsharkroundhand 제안) ## v4.7.2 변경사항 - **🔒 폐쇄망(내부망) 배포 대응**: `KORDOC_OFFLINE=1` 로 모든 아웃바운드 통신(OCR 모델 다운로드·watch webhook)을 요청 발신 전에 차단하고, `KORDOC_ROOT=<디렉토리>` 로 MCP 서버의 파일 읽기·쓰기를 해당 디렉토리 하위로 제한합니다(둘 다 opt-in — 미설정 시 기존 동작 그대로). 인터넷 없는 망에 반입하는 오프라인 설치 번들은 `node scripts/pack-offline.mjs [--with-ocr] [--with-models]` 로 만들고, OCR 모델은 `kordoc models --export/--import` 로 SHA-256 검증과 함께 옮깁니다. 절차와 보안성 검토용 근거는 [docs/offline-deployment.md](docs/offline-deployment.md) 참조. - **🧹 의존성 취약점 정리**: `npm audit --omit=dev` 0건 (sharp ^0.35.0, adm-zip ^0.6.0 override, MCP SDK 체인 권고 해소). ## v4.7.1 변경사항 - **✏️ 밑줄 보존 전 포맷 확장**: v4.7.0 이 PDF 에서 복원한 밑줄을 HWPX·HWP5 에서도 `…` 로 방출합니다. 한컴이 밑줄 없는 글자에도 `type="NONE"` 을 넣는 특성 때문에 존재 여부가 아니라 밑줄 **종류**로 판별합니다. - **🔗 PDF 링크 어노테이션 추출**: `/Annots` 의 Link(`/URI`)를 텍스트와 상관해 `[text](url)` 로 방출합니다 (스킴 화이트리스트 살균). ## v4.7.0 변경사항 - **✏️ PDF 밑줄 감지**: baseline 바로 아래 밀착한 얇은 수평선을 텍스트와 상관해 `…` 로 보존합니다. PDF 에는 밑줄 폰트 플래그가 없어 종전 파서는 이를 전부 버렸습니다. 표 괘선·배지 오탐 방어 5겹. 코퍼스 48문서 중 32문서에서 강조 밑줄 복원. ## v4.6.1 변경사항 - **📰 2단 지면 읽기 순서 수리 (#64)**: 시험지·잡지처럼 좌우 2단으로 조판된 PDF에서 좌·우 단이 행 단위로 섞여 나오던 문제. 프로즈 특성(정렬·긴 줄)에 기대지 않는 기하 전용 2단 검출을 신설해, 전폭 요소(머리글·쪽번호)를 경계로 좌단 전체 → 우단 전체 순서로 복원합니다 — 기본 모드·`--no-tables`·OCR 경로 모두. 2026학년도 수능 문제지 실측: `--no-tables` 기준 물리학Ⅰ·생활과윤리 20/20 문항 순서 역전 0회(종전 13문항/역전 3회), 국어 44/45 역전 0회. 일반 문서 오발화는 행 구조 가드 3종으로 차단(코퍼스 커버리지 게이트 베이스라인 동등). (@choa712 블록 덤프 제보) ## v4.6.0 변경사항 - **🚫 PDF 표 감지 opt-out (#64)**: `--no-tables`(CLI) / `tables: false`(API·MCP) — 시각적 테두리 박스(2단 시험지의 안내문·보기 상자)가 선 기반 표로 잡혀 주변 본문이 셀로 끌려가고 읽기 순서가 뒤집히던 문서에서, 표 감지를 통째로 끄고 자연 읽기순 텍스트만 뽑습니다. 기본값은 종전 그대로 표 감지 켬. (@choa712 제보) - **🖼️ 이미지 다량 문서의 JSON 출력 수리 (#65)**: 이미지가 수백 장인 HWP는 base64 총량이 문자열 한계를 넘어 `--format json`이 **비-JSON**으로 끝나고 실패 계약도 안 나왔습니다. 이제 `--image-refs`로 이미지 바이트 대신 저장 경로만 남길 수 있고, 한계를 넘으면 자동으로 참조 모드로 강등하며, 출력 단계 예외도 원인 코드(`OUTPUT_TOO_LARGE` 등)가 담긴 실패 JSON으로 나옵니다. (@choa712 제보) - **🔤 중첩 인라인 강조 수리 (#61)**: `**굵게 *기울임* 다시**` 같은 중첩 강조가 별 리터럴 노출·굵게 소실·서식 역전으로 깨지던 문제 — LLM이 쓴 마크다운에 흔한 패턴이라 `generate_document` 경로 노출이 컸습니다. (@LeeYudok 제보 + PR #62) - **📄 선두 BOM XML 파트 수리 (#63)**: 일부 OpenXML 라이터가 `[Content_Types].xml`·`.rels` 앞에 붙이는 UTF-8 BOM 때문에 xlsx·docx가 통째로 `PARSE_ERROR`로 거부되던 문제(엑셀·리브레오피스는 정상 열림). (@soyesenna 제보) ## v4.5.0 변경사항 - **📄 페이지 옵션 신설**: 용지 크기(A4·A3·B4·B5·Letter·커스텀 mm)·**가로 방향**·**다단**(1~8단)·**머리말/꼬리말**을 생성 옵션으로 지원합니다 — API `page`, CLI `--paper/--landscape/--columns/--header/--footer`, MCP `generate_document` 동명 파라미터. 머리말/꼬리말은 실물 저장본과 동일한 ``/`` 구조라 한글에서 그대로 조판됩니다. - **🔗 하이퍼링크 생성**: `[text](url)`이 텍스트로 뭉개지지 않고 실측 6-param `HYPERLINK` 필드로 방출됩니다 — 한글에서 실제 클릭 가능, 재파싱하면 `[text](url)` 복원(왕복 보존). 표 셀 안 링크 포함. - **📎 각주 개체 생성**: `[^1]` 마커 + `[^1]: 본문` 정의가 진짜 `` 개체로 방출돼 한글이 페이지 하단에 각주를 조판합니다. - **🖼️ 이미지 실데이터 임베드**: `images` 옵션(url→바이트)·`data:` URI·CLI/MCP `--image-dir`로 PNG/JPEG/GIF/BMP를 BinData에 실제로 넣습니다 — 픽셀 치수 자동 환산(96dpi)·본문폭 초과 시 비례 축소. 바이트가 없으면 종전처럼 참조를 placeholder로 보존합니다. - **🔍 OCR 저신뢰 폐기 관측**: 내장 OCR이 신뢰도<0.5로 조용히 버리던 라인 수를 `OCR_LOW_CONF` 경고로 노출합니다. - **📏 스캔 표 실측 채점 교정**: 표 구조가 아닌 정답(클립아트 장식 그리드·1×1 텍스트박스, 비어있지 않은 셀 <3)을 모수에서 제외하고 제외 수를 투명하게 노출 — 교정 후 스캔 표 매칭 **71.4%**·cellF1 **0.595** (문자 recall·CER은 v4.4.1 실측과 동일). ## v4.4.1 변경사항 - **🖼️ MCP 이미지 입력 수리**: `parse_document` 등 파싱 도구가 PNG/JPG/WebP를 확장자 단계에서 거부하던 것(CLI는 정상, MCP만 차단)을 해제 — 스크린샷·스캔 이미지를 MCP로도 바로 변환합니다. - **📏 내장 OCR 정확도 첫 실측** (`bench/ocr-accuracy.mjs` 신설): 코퍼스 PDF 41문서 82페이지, 클린 텍스트층 대조 — 문자 recall 90.0%(글꼴 미렌더 1건 제외 94.0%)·precision 95.1%, 한글 음절 recall median 99.9%, 0.96s/페이지. 스캔 표 구조는 매칭 63%·cellF1 0.50로 아직 약한 지점입니다. 정답이 클린 렌더라 실스캔 노이즈는 미반영(상한치). ## v4.4.0 변경사항 - **🔑 비밀번호 문서 열기 (#59)**: 열기 암호가 걸린 **HWPX·HWP3·HWP5** 문서를 `--password`(CLI) / `password`(API·MCP)로 엽니다. 세 포맷의 암호화 방식이 각각 다릅니다 — HWPX는 ODF 표준(AES-256-CBC + PBKDF2), HWP3는 단일 DES-ECB, HWP5는 EncryptVersion 4의 비트 단위 CFB. 틀린 비밀번호는 성공으로 위장하지 않고 `ENCRYPTED`로 실패합니다. (한컴 DRM 문서보안은 별개라 해당 없음, @jangster77 제보) - **🩹 HWP3 본문 대량 유실 수리**: 그림 뒤에 오는 캡션 문단 리스트를 읽지 않아 그림 하나당 43바이트씩 스트림이 어긋났고, 어긋난 자리가 "문단 끝" 표식으로 읽히면 **경고 없이** 나머지를 통째로 버렸습니다. 945KB 문서가 0자로 나오던 수준입니다(rhwp 대조 실측 6종 복구, 최대 100만 자). 표 셀 상한 256도 실존 문서(367셀)를 죽여 잔여 스트림 기준으로 교체했습니다. - **🔤 CDATA 텍스트 소실 수리**: `` 로 저장된 텍스트를 경고 없이 버리던 결함 — 공용 XML 헬퍼에 있어 HWPX·HWPML·DOCX 세 포맷에 걸쳐 있었습니다. - **🔣 사라지던 글자 복원**: 한컴 검증 PUA 11종(결재란 `(인)`, 편람 글머리표, 사각 안 숫자 ①~⑳ 등)과 HWP3 johab 매핑 2종(표 셀 글머리표 ▸, 머리말 회사명) — 매핑에 없는 코드는 삭제되는 구조라 누락이 곧 글자 증발이었습니다. - **ᄒᆞᆫ HWP3 아래아(옛한글) 복원**: 완성형에 대응 음절이 없어 통째로 빠지던 아래아 음절('ᄒᆞᆫ글 97' 등)을 한컴 HWP5/HWPX 변환본과 같은 자모열(초성+ᆞ+종성)로 보존합니다. - **🐛 그 외**: 동명 누름틀이 여러 곳에 있는 서식에서 `require_unique`가 한 곳도 채우지 않던 것, 수식 토큰이 `constructor`·`toString`이면 출력이 오염되던 프로토타입 체인 결함, 빈 셀 채우기가 엔티티(` `) 원문을 지우던 것(fail-closed 통일), fill 계열 ZIP 폭탄 가드, CLI `--format json`의 실패 JSON 출력(원인 코드 포함). npm 배포본에 NOTICE·THIRD_PARTY 라이선스 고지도 포함됩니다. ## v4.3.0 변경사항 - **🏛️ 정부 표준 기안문 서식 내장 + 누름틀 채우기**: 별지 제1호(일반기안문, 누름틀 23곳)·제2호(간이기안문, 13곳) 서식을 번들 — `kordoc fill --template gian` / `--list-templates` / MCP `fill_form`의 `template` 파라미터로 파일 없이 표준 기안문을 채워 만듭니다. 누름틀(CLICK_HERE) 필드 채우기 신설 (서식·안내문 보존, 안내문 충돌 침묵 유실 구조적 차단). - **📄 빈 문단 보존 옵션 (#57)**: `--keep-empty-paragraphs` — 행 줄맞춤 서식 문서(원규 번호표 등)에서 빈 문단이 사라져 값이 다른 항목에 붙던 문제의 opt-in 해법. 본문은 빈 블록, 표 셀은 빈 줄로 "원문 문단 수 = 줄 수" 대응 유지. (@jumaniac 제보) - **🐛 에러 계약·MCP 정합 7건**: 암호화 XLS가 성공으로 위장하던 것, HWPX DRM 오분류, HWP3/HWPML/sharp 진단 메시지 소실, MCP `parse_pages` 배포용 HWP 폴백 불발, `.xls`를 `hwp`로 오판, `pageCount` 미전파 등 — 전면 리뷰에서 발굴·일괄 수리. - **📐 TAC 인라인 표 outMargin 정합 (rhwp 포팅)**: 결재란 등 글자취급 표의 가로 여백이 무시돼 문단이 밀리던 렌더 결함 수리 — 실코퍼스 60건 스윕 검증. - **⚡ 성능**: HWP 바이너리 패치의 섹터 할당 O(n²) 제거(+4MB 삽입 **637배** 가속), PDF 괘선 표 감지 버킷화. MCP 핸들러 전면 비동기화로 대용량 문서 I/O 중 서버 멈춤 제거. - **🧰 내부 정비**: 수식 변환기 hwp5→hwpx 정본 통합(포맷별 LaTeX 갈림 해소), 번호서식·XML 헬퍼 공용화, CI 타입체크 신설, 발행 게이트 복원(`--ignore-scripts` 관행 제거). ## v4.2.6 변경사항 - **📐 개조식·보고서 본문 왼쪽정렬**: 개조식·보고서 공문서의 본문 항목(□/○/-)을 양쪽정렬에서 왼쪽정렬로 바꿨습니다. 어절 유지 + 양쪽정렬이 겹치면 다음 어절이 길어 짧게 끊긴 줄(예: 25자 줄을 34자 폭으로)의 어절 간격이 과하게 벌어져 문단이 깨진 것처럼 보이던 문제입니다. 「행정업무운영편람」 개조식 예시의 왼쪽정렬 관례와도 일치합니다. 기안문(official) 등 서술형 본문의 양쪽정렬은 그대로 유지합니다. ## v4.2.3 변경사항 - **인라인 표·텍스트 순서 보존 (#49·#50)**: 한 문단이나 한 셀 안에서 글자취급(treatAsChar) 표와 텍스트가 번갈아 놓일 때(`[날짜] 부터 [날짜] 까지` 같은 서식 기간 입력란) 텍스트가 표 앞으로 끌려나오던 순서 역전을 수정했습니다. 최상위 `blocks`와 `IRCell.blocks` 모두 원문 배치 순서를 따르고, 생성기도 같은 순서로 방출해 라운드트립이 대칭입니다. float·페이지 앵커 표는 종전대로 텍스트 흐름에 불참합니다. (@jumaniac 제보) ## v4.2.2 변경사항 - **~~취소선~~ 추출 (HWP5·HWPX)**: 법령 개정문 등의 삭제 표시가 마크다운 `~~취소선~~`으로 살아납니다. 판정은 취소선 **모양** whitelist — 한컴은 취소선 없는 문자에도 취소선 비트를 기본값으로 저장하므로(원저장소 rhwp 실측) 모양이 실제 선 종류일 때만 인정, 미지 값은 안전하게 무시. HWPX는 부분 취소선까지, HWP5는 문단 단위. - **ZIP 해제 한도 100→256MB**: 단일 섹션 XML이 75MB에 달하는 대형 실문서(rhwp 1만 건 서베이 실측)가 ZIP bomb으로 오인 거부되던 것을 상향. ## v4.2.1 변경사항 - **🖼️ 이미지(PNG/JPG/WebP) 직접 입력**: 스크린샷·스캔 이미지를 PDF 래핑 없이 바로 변환합니다 — `kordoc 서식.png` / `parse(buffer)` / MCP `parse_document`. 텍스트층이 없으므로 내장 OCR 이 자동 적용됩니다 (플래그 불필요, 디코딩은 optional dependency `sharp`). - **📐 스캔본 표 괘선 감지**: OCR 경로에 래스터 괘선 감지기 신설 — 페이지 픽셀에서 수평/수직 괘선을 직접 찾아(이진화+런렝스, ML 없음) 선 기반 표 파이프라인에 태웁니다. 세로 병합 라벨 셀 + 다중줄 서술형 서식(정부 제출 서식류)도 rowspan/colspan 이 살아있는 표로 복원됩니다. 종전 클러스터 감지는 괘선이 안 잡히는 무테두리 표의 fallback 으로 유지. ## v4.2.0 변경사항 - **👓 내장 텍스트 OCR (PP-OCRv5 korean)**: 스캔/이미지 PDF를 **API 키 없이 로컬 추론**으로 읽습니다 — `parse(buffer, { ocr: true })` / CLI `--ocr` / MCP `parse_document`의 `ocr` 옵션. 모델 ~18MB는 첫 사용 시 자동 다운로드+SHA 검증. 품질 신호가 가리키는 페이지(스캔·글꼴 매핑 깨짐)만 정밀 OCR 하고 정상 페이지는 그대로 두며, OCR 라인 좌표를 표 감지 파이프라인에 태워 **스캔본에서도 표가 복원**됩니다. 한국어 사전 11,945자(완성형 한글 11,172자 전량 + 자모·라틴·기호), 1페이지 ≈1초. - **🩹 HWP3 구버전 파서 정합 3종**: 탭/필드코드/책갈피의 스트림 소비 결함으로 이후 텍스트가 통째로 오염되던 것과, 로마숫자(Ⅰ~Ⅹ)·원문자(①~⑩)·따옴표·글머리가 증발하던 것을 원저장소(rhwp) 후속 패치 반영으로 수리. - **🐛 수식 OCR 페이지 off-by-one 수리**: `--pages` 필터가 한 페이지 밀리고 수식이 이전 페이지에 붙던 잠복 결함. XLSX/XLS `--keep-empty-cols` 배선 누락도 수리. ## v4.1.0 변경사항 - **👁️ `render_document` MCP 도구 신설**: 생성·패치·양식 채움 결과 HWPX를 조판 그대로 **PNG 이미지로 응답에 직접 반환** — AI가 자기가 만든 문서를 눈으로 확인하고 다시 고치는 루프가 MCP 안에서 닫힙니다 (한컴 저장본은 조판 캐시, 생성본은 reflow 조판, 검색어 형광펜 지원). - **🕶️ `kordoc redact` + `redact_document` MCP 신설**: 개인정보(주민번호·전화·이메일·카드·계좌, 여권·운전면허 opt-in)를 탐지해 **원본 서식 그대로 마스킹**(`850315-●●●●●●●`)한 HWPX/HWP를 출력합니다. 생년월일·Luhn 검증으로 오탐 축소, 리포트에 원본 개인정보 미포함. 자동 검출 보조 도구 — 최종 공개 전 사람 확인 필수. - **📦 `--format chunks` + `parse_chunks` MCP 신설**: RAG용 구조 청크 JSON — 헤딩·개조식 위계(□○- / 1.·가.·1))를 breadcrumb 경로로 보존하고 표는 독립 청크로 분리합니다. - **📋 표 오른쪽 끝 빈 열 보존 (#47)**: 서식 문서의 빈 입력란 열이 파싱에서 통째로 삭제되던 문제 — `keepTrailingEmptyCols` 파싱 옵션(CLI `--keep-empty-cols`)으로 보존할 수 있고, **양식 경로(parse_form·fill)는 항상 보존**해 fill이 채울 수 있는 필드가 목록에서 빠지지 않습니다. 제보 [@jumaniac](https://github.com/jumaniac). - **📅 XLSX/XLS 날짜 변환**: 날짜 셀이 시리얼 숫자("45306")로 나오던 것을 ISO("2024-01-15")로 변환합니다 (내장·커스텀 numFmt 감지, date1904 반영). - **🛡️ 프로덕션 전면 리뷰 ~80건 수정**: 악성 파일 대응(수식 정규식 ReDoS·HTML 표 span 폭주·HWP3 압축 폭탄·XLSX 그리드 폭주), 표-전용 PDF의 OCR 오판, HWP5 제어문자(하이픈/고정폭 공백) 매핑, DOCX 변경추적 삽입 유실, 양식 채움 라벨 오탐 4종, HWP5 패치 삭제 텍스트 잔존 제로화, MCP 쓰기 경로 검증, PDF 괘선 표 성능(62,500 교차점 3.1s→0.2s) 등 — 자세한 내역은 [CHANGELOG](CHANGELOG.md). ## v4.0.8 변경사항 - **🖼️ PDF 이미지 추출 신설**: 종전에는 이미지 영역 좌표만 계산하고 바이너리는 전량 유실되던 것을, 이미지 XObject를 디코딩 픽셀로 받아 순수 JS PNG 인코딩으로 추출합니다 (pdfjs 비동기 디코딩 대기 포함 — 코퍼스 52 PDF 중 45파일 731장 실측). 페이지 말미 위치에 `![image](...)` 참조, 로고·워터마크 페이지 간 중복 억제, 페이지 경계 표 병합 비간섭. - **🖼️ HWPX/HWP5 미참조 BinData 스윕**: 꼬리말·머리말 안 그림(보도자료 사진 스트립), 결재문서 셀 배경 이미지(borderFill imgBrush) 등 본문 워크가 닿지 않아 유실되던 이미지를 문서 끝에 보강 추출합니다 — 코퍼스 이미지 복구율 HWPX 686/686·HWP5 92/92 (100%). - **🖼️ DOCX `w:object` 이미지**: OLE 개체 미리보기(`v:imagedata`)가 추출에서 빠지던 것 수정 (mc:Fallback 사본은 종전대로 중복 제외). ## v4.0.7 변경사항 - **🔗 DOCX 하이퍼링크 대량 손실 수정**: 한 문단에 링크가 여러 개면 마지막 1개만 남던 구조를 제거하고 문서 순서대로 링크별 인라인 `[text](url)` 생성. 워드·구글독스가 흔히 쓰는 **필드코드 HYPERLINK**(`fldSimple`/`fldChar`)와 내부 anchor 링크도 처리 (실측 176→21 손실이던 문서 전량 복원). - **🖼️ DOCX 이미지 본문 링크**: 이미지가 파일로는 추출되나 마크다운에 `![image](...)` 참조가 안 들어가던 것을 문단 위치 인라인 방출로 수정. - **🔍 PDF 오매핑 mojibake 감지**: ToUnicode 오매핑으로 정상 한글 영역의 엉뚱한 글자가 무경고 통과하던 것을 종성(받침) 분포 신호로 감지 — `garbled_hangul` 사유의 페이지별 NEEDS_OCR 경고. ## v4.0.6 변경사항 - **📊 PDF 무괘선 밴드 표 파편화 수정**: 세출예산 사업명세서류의 요약행 밴드에서 수직선이 끊겨 부서명이 유실되던 것을 4중 가드 수직선 브리지로 복원 (광진구 2026 세출예산 637곳 실측). - **📝 HWPX 캡션 안 중첩표 보존 (#46)**: 캡션 속 표 내용이 통째로 사라지던 것(304자 중 297자)을 문서 순서 평탄화로 보존. 제보 [@jumaniac](https://github.com/jumaniac), 조언 @hiSandog. ## v4.0.5 변경사항 - **🖍️ 인라인 강조 복원 일반화**: kordoc이 만들지 않은 **일반 한컴 문서**도 볼드·이탤릭이 마크다운 `**`·`*` 마커로 복원됩니다 (charPr 실속성 기반, 한컴 편집 이력으로 쪼개진 run 자동 병합). 표 헤더행처럼 셀 전체가 볼드인 구조 서식은 마커를 만들지 않습니다. - **🏛️ 공문서 모드 인라인 강조 왕복**: 공문서 HWPX를 재파싱해도 항목 안 `**강조**`가 보존됩니다 — 보고서 1단계 □ 전체 굵게 같은 구조 볼드와 자동 구분. - **↔️ 리스트 depth 왕복**: 공문서 재파싱 산출물의 `1)`·`-` 항목이 재생성 시 1단계로 붕괴('1)'→'2.', '-'→□)하던 것을 들여쓰기 역산 선행 공백으로 해소 — 기안문·보고서·개조식 2차 왕복이 동일 결과로 수렴. ## v4.0.4 변경사항 - **🖋️ reflow 개체 흐름 모델**: float 표(두문 결재표)는 텍스트를 개체 아래로, 페이지 앵커·글 뒤 개체는 흐름 불참, inline 표는 실효높이+행간 전진 — 실결재 코퍼스 자기일관성 **59/59 (100%)**. 한컴 저장본을 프로그램 편집해 일부 문단만 캐시가 없는 **혼합 캐시 문서**도 reflow로 정확한 위치에 렌더됩니다. - **🎨 서식 프로필 0.3.0**: 셀 **글꼴 이름 왕복**(`fontName_hangul` — 원본 없이 글꼴 재현), 첫 행 지문 `anchor_row`(첫 셀이 빈 크로스탭 매칭), 행0 전체 병합 표의 열폭 보존, 손편집 JSON의 괘선 값(type·mm·색상) 사전 검증. - **🧰 CLI/MCP 옵션 표면 통일**: 공문서 옵션 조립·값 집합을 단일 SSOT로 — 두 인터페이스의 옵션 드리프트 원천 차단(MCP 프리셋 별칭 6종 회복 포함). 리팩터 전후 산출물 바이트 동일 검증. - **↔️ 왕복 보강**: 표 셀 안 볼드·이탤릭·코드 마커 왕복, 파서 문단 들여쓰기 관찰 슬롯(`IRBlock.indent`), 원문자 15+/51+ 폴백 파서 정합, 중첩표 높이 정밀화, 결문 구분선 컬럼폭 적응. - 게이트: 테스트 1,012 · 실렌더 시각 오라클 14종 해밍0 (default 모드 h1~h4 개요번호 미강제 실렌더 확증 포함). ## v4.0.3 변경사항 - **🛡️ 프로덕션 하드닝**: v4 전체 2중 리뷰에서 확정된 결함 수정 — 잘못된 수치 옵션(NaN·비정상 범위)의 명시적 거부, 폰트명 XML 이스케이프, 표지·목차를 전 프리셋으로 확대(보도자료 제외), 표지·목차 사용 시 본문 폰트 지정이 무시되던 결함과 13pt 이하 헤딩 위계 역전, 셀 안 개체 캡션 오귀속·거짓 손실 경고 수정. - **📏 기안문 기본 12pt·계획서 □→ㅇ→\* 체계**: 실결재·실측 계획안 지배값을 기본값으로 (종전 값은 `--pt 15`·`numbering: 'standard'`로 복원 가능). ## v4.0.2 변경사항 - **📏 실측 벤치마킹**: 서울 정보소통광장 **실결재 기안문 60건** + 부처별 양식을 전수 디코드해 생성 결과와의 괴리 17건을 목록화, 9건 반영. - **조판영역 근본수정**: 단 컬럼 정의(`colPr`) 미방출로 본문이 좌우 10mm씩 좁게 잡히고 표가 우측 여백을 침범하던 결함 해소 — 전 프리셋 실렌더 조판영역 초과 0건. - **기안문 두문·결문** (`--doc-head`/`--doc-foot`, 별지 제1호서식) · **보도자료 프리셋 `press`** (머리박스·담당 표) · **공고문 두문** (`--notice-head`) · **보고정보 행** (`--report-info`). - 표 열폭 배분 재작성(열 하한 = 최장 어절 폭 — 짧은 열이 글자 단위로 세로 쪼개지지 않음), 표 셀 12pt, 기안문 여백 실결재 지배값 20/15/20/15, 2단계 부호 ㅇ/○ 프리셋 분화(`--bullet2`). - 실무자(현직 공무원) 눈 QA 게이트 통과 후 릴리스. ## v4.0.1 변경사항 - **✍️ 실무자 QA 3건 수정**: bold 시 폰트가 HY견고딕/Arial Black으로 바뀌던 "정체모를 폰트" 제거, h2 섹션 제목 말머리 `--h2-marker`(box □ / number / none), 개조식 소분류 부호 ― → 실무 관행 하이픈 `-`. - **📝 공문서 표기법 검수 19룰**: 날짜·시간·금액·붙임·외래어·차별 표현 등을 검수하는 `kordoc lint ` + 공문서 생성 시 경고 병기. ## v4.0.0 변경사항 - **🏛️ 정부 표준 개조식 보고서 완성**: 실제 정부 공문서 16종 전수 디코드·대조 기반 — 표지(gradient 제목박스·장식 바)·목차 배너·로마숫자 장헤더·쪽번호("- 1 -", 표지·목차 제외)·결재란·"끝." 자동·본문 제목박스. 표는 실측 문법(헤더 음영+이중선, 외곽 0.4mm 위계, 내용 비례 열폭, 우측 배치) 자동 적용. `--preset 개조식`. ## v3.18.0 변경사항 - **🎨 서식 프로필**: 표의 위상뿐 아니라 **테두리·음영·열 실측폭·셀 글꼴까지** 원본 문서 없이 재현합니다. `hwpxToProfile(hwpx)`로 레퍼런스 서식만 JSON으로 추출하고, `markdownToHwpx(md, { profile })`로 다른 문서에 그 서식을 입힙니다 — 원본 유출 없이 기관 서식만 공유·재현(이슈 #41, 스키마 [`docs/format-profile-spec.md`](docs/format-profile-spec.md)). 스키마·예시 기여: [@ai-localgov-officer](https://github.com/ai-localgov-officer) (PR #42). ## v3.17.0 변경사항 - **🖼️ 레이아웃 렌더 충실도**: 글꼴이 문서 지정대로 나오는 per-run 폰트(고딕 제목이 바탕체로 나오던 것 해소), 표지+본문 다구역 문서 전체 렌더, 가로(landscape) 문서 프레임 회전(우측 잘림 해소), 연속 표 문단의 페이지 포개짐 분리. - **✍️ 결재란 겹침 해소 (reflow)**: 조판 캐시 없는 문서에서 결재란 라벨표·스탬프표가 같은 자리에 포개 찍히던 것을 한컴과 동일하게 나란히 배치. 중첩표 셀 높이 과소측정도 함께 수정. ## v3.16 변경사항 - **📊 차트 생성**: 마크다운 ```chart 펜스(type/cat/계열 라인)가 한컴 네이티브 차트(OOXML chartSpace)로 생성됩니다 — 막대·선·원·도넛·영역·분산·방사형 등 20종, 계열/조각 색 지정, 잘못된 펜스는 코드블록 폴백. - **🔴 도장/서명 자동 날인**: `kordoc seal` — "(인)"·"서명 또는 인" 앵커를 찾아 도장 PNG를 글 앞 부유로 배치. 표/페이지를 키우지 않아 날인 후 서식이 밀리지 않습니다 (MCP `place_seal` 포함). 중첩표·글상자·탭/줄바꿈 문단은 위치가 근사이며 결과 `warnings` 로 고지됩니다 — 한컴에서 확인 후 `--dx`/`--dy`(dx_mm/dy_mm)로 미세조정하세요. - **🔌 Claude Code 플러그인**: `/plugin marketplace add chrisryugj/kordoc` → `.hwp`/`.hwpx`/공문서 요청에 kordoc 스킬 자동 활성화. - **🩹 3.16.1 패치**: 통합 검증 리뷰 결함 55건 일괄 수정 — 도장 배치(rowspan·colspan·중첩표 원점), 차트 값 파서(천단위 콤마·CRLF 마크다운), 양식 채우기 가드(require_unique), CLI `fill -o` 출력 등 "성공 메시지 뒤에 조용히 틀린 산출물" 계열 소탕. - **🩹 3.16.2 패치**: 신구조문대비표의 `<신 설>` 표기를 텍스트 상자로 오인해 표 전체를 문단으로 해체하던 PDF 파서 결함 수정 — 30p 개정안 대비표가 통째 1표로 복원. ## v3.15.0 변경사항 - **🖋️ reflow 렌더 (캐시 없는 파일도 조판)**: `markdownToHwpx` 산출물·AI 생성본·편집본처럼 조판 캐시(linesegarray)가 없어 렌더가 거부되던 HWPX를 `renderHwpxToSvg(buf, { reflow: true })` / `kordoc render`(CLI는 기본 켬, `--no-reflow`로 끔)로 순수 TS 조판합니다. 검증된 줄나눔 엔진(실측 98% 일치) + 실측 세로 모델로 lineseg를 합성해 기존 렌더 파이프(정렬·표·이미지·형광펜·다페이지)를 재사용합니다. 단문단·표 셀·표 밀어내기·자동 페이지 분할. 한컴 저장본은 캐시 재생 그대로(무회귀). - **🔺 그리기 도형 렌더**: 사각형·타원·선·다각형·호를 SVG로 그립니다(선 색·굵기·점선, 채움, 크기 스케일). 조직도·화살표 등 "원본과 다르게 보이던" 큰 원인을 해결했습니다. - **🚀 persistent 렌더 워커**: `kordoc render-worker`가 프로세스를 유지하며 연속 렌더 요청(stdin NDJSON)을 처리해 node 콜드스타트를 없앱니다(미리보기 앱 연동용). ## v3.14.0 변경사항 - **📄 렌더 다페이지 지원**: `kordoc render`가 전 페이지를 세로 스택 SVG로 그립니다(페이지별 흰 배경·경계선·클립, `data-page` 속성, `RenderSvgResult.pageCount`). 기존엔 전 페이지가 첫 장 한 장에 겹쳐 그려졌습니다. - **🖍️ 렌더 검색어 형광펜**: `--highlight <쉼표구분어>` / `RenderSvgOptions.highlights` — 텍스트를 매치 경계로 분할해 매치 세그먼트에만 배경을 깝니다(대소문자 무시, `textLength` 동일 계산으로 정렬 오차 없음). - **📐 줄 경계 정합**: lineseg `textpos`를 HWP5 문자 스트림 슬롯(컨트롤 8·문자형 컨트롤 1·서로게이트 2슬롯) 기준으로 재구성해, 컨트롤·탭이 섞인 문단에서 첫 줄에 글자가 몰리고 다음 줄이 비던 어긋남을 해결했습니다(데모 1,132개 멀티라인 문단 검증). - **🖼️ 이미지 크롭 오판 수정**: `imgClip`을 `imgDim`(내용 상자) 기준으로 해석 — 삽입 후 리사이즈된 이미지(로고 대부분)가 좌상단 코너로 잘못 잘려 깨지던 문제를 해결했습니다(데모 pic 267개 검증). ## v3.13.0 변경사항 - **📄 프로즈 박스 감지**: 상단 라벨탭(제목 칩)이 박스 테두리에 걸쳐 만든 가짜 열 위로 본문이 전폭으로 흐르는 표(검정고시 응시자격 박스 등)를 감지해, 셀 경계에서 조각나던 본문을 자연 읽기 순서의 문단으로 복원합니다. 기하(전폭 행 지배)와 텍스트(긴 프로즈 셀)의 교집합에서만 발동해 정규 표는 건드리지 않습니다. - **📝 HML 표 캡션 보존**: 표에 딸린 도형 캡션(`※ …참조` 등)이 hwpml 파싱에서 통째로 소실되던 문제를 수정했습니다. 캡션을 표 앞/뒤 문단으로 보존합니다. --- ## v3.12.0 변경사항 - **🏷️ 라벨 헤더 표 강등 면제**: 첫 행이 라벨(채용분야|담당업무|우대조건, 성명|응시분야|비고)인 표가 본문 셀의 ○/ㅇ 항목부호나 빈 기입란 때문에 텍스트 박스로 오인돼 문단으로 강등되던 문제를 수정했습니다. 예산표·업무분장표·양식 표가 표로 살아납니다. - **🔗 개방 변 합성 체인 뷰**: 중간 괘선을 셀 경계마다 쪼개 그은 표(문의처 연락처 표 등)도 세그먼트를 논리적으로 이어 좌우 개방 변을 닫습니다. 물리 선은 건드리지 않아 기존 표의 셀 배치에 부작용이 없습니다. - **📊 PDF 표 구조 벤치**: 표 매칭 90.3→98.6%, 완전 일치 58.3→65.2%, cellF1 0.652→0.724. 채점기에 잡매칭 차단(bag 교집합 0)·세밀 분할 프로즈 박스 구제(접두 유사도 폴백)를 더하고, 흐름띠·빈 스캐폴딩 표는 모수에서 제외했습니다. ## v3.11.0 변경사항 - **📐 PDF 개방형 표 복원**: 한국 행정문서에 흔한 좌/우 바깥 테두리 생략 표(수평 괘선만 전폭, 수직선은 내부 구분선만)에서 가장자리 열이 통째로 사라지던 것을 가상 테두리 합성으로 복원합니다. 채용공고류에서 6열 표가 4열로 찢기고 남은 열·본문이 13x2 유령 표로 흡수되던 병리가 완치됐습니다. - **🎨 글상자 음영의 괘선 오염 차단**: 한컴 PDF가 제목 글상자의 그라디언트 배경을 촘촘한 수평선 수십 개로 내보내, 선 병합 단계에서 실제 상하 테두리까지 삼키던 것을 음영 스택 필터로 걸러냅니다. - **📊 PDF 표 구조 벤치**: hwpx↔pdf 쌍 GT 대조에서 표 매칭 84.7→90.3%, 완전 일치 54.2→58.3%, cellF1 0.632→0.652. ## v3.10.0 변경사항 - **🖼️ 레이아웃 보존 렌더**: `kordoc render 문서.hwpx -o 문서.svg` / `renderHwpxToSvg(buffer)` (v4.13.0: `renderDocument` 로 HTML·PNG·JPEG·PDF·페이지 선택·영역 crop) — 한컴이 저장한 조판 캐시(줄 좌표·셀 그리드·개체 앵커)를 SVG 절대배치로 그려 원본 레이아웃을 재현합니다. run별 글자 크기/굵기/색/장평/자간, 문단 정렬, 셀 배경·테두리, 병합 셀, 인라인 개체, 이미지 크롭까지. 한컴 저장본 전용(1페이지). - **🔧 uint32 음수 좌표**: `vertOffset="4294967103"`(= −193) 같은 uint32 저장 음수를 올바르게 해석합니다. - **🔧 셀 내부 COLUMN 기준계**: 셀 안 개체의 `horzRelTo="COLUMN"`을 셀 영역 기준으로 해석합니다 (사진이 페이지 왼쪽으로 튀던 문제). ## v3.9.0 변경사항 - **🧮 Markdown 수식 → HWPX native 수식 생성**: `$$ \frac{a}{b} $$` 같은 display math 블록이 한컴 수식 개체(``)로 생성됩니다. `\frac`·`\sqrt`·첨자·그리스 문자·적분/극한·행렬(matrix/pmatrix/bmatrix)·`\left(` 구분자·`\text` 리터럴 지원. 생성한 수식은 kordoc으로 다시 파싱해도 같은 LaTeX로 돌아옵니다 (#38, @leehuiso 기여). - **🛡️ 수식 입력 가드**: 닫히지 않은 `$$`가 문서 전체를 삼키던 문제(일반 문단 폴백), 중괄호 폭탄 크래시(깊이/길이 상한), 닫는 `$$` 뒤 텍스트 소실을 수정했습니다. - **📋 공문 모드 번호 연속**: 항목 사이에 수식이 끼어도 항목 번호가 이어집니다 (표와 동일). - **⚖️ 법령 문서 왕복 무결성 게이트**: 조문 번호 뒤 분리·문장 중간 끊김이 없음을 실측(민원처리법 전문 228문단)하고 벤치 게이트로 고정했습니다. ## v3.8.4 변경사항 - **📑 DOCX 병합표·텍스트박스 복구**: 병합표에서 셀이 통째로 빠지던 버그(세로 병합 미동작 포함)와 텍스트박스 내용 전체 유실을 수정 — 신고서류·KS표준안류 회수율 0.67/0.92 → **1.0/0.998**. - **🔒 개인정보 마스킹 별표 보호**: `******`·`홍**` 같은 마스킹 별표가 마크다운 수평선/볼드로 오독되던 것을 이스케이프로 보존합니다 (별표 각주 `* 단, …`의 리스트 오인도 해소). - **🔁 md→HWPX 왕복 충실도 0.947→0.9996**: 재변환한 HWPX를 다시 파싱해도 헤딩 레벨·리스트 번호(2. 3. 4. 시작 보존)·마스킹 문자가 그대로 살아납니다. 생성 문서는 한컴 "문서 찾아가기"에 개요 구조로 표시됩니다. - **#️⃣ 개요 번호 발명 수정**: 번호 서식을 비운 개요 문단(한컴 "번호 없음")에 파서가 "1." 접두를 만들어 붙이던 버그 수정. ## v3.8.3 변경사항 - **📰 2단 조판 문서(속기록류) 읽기 복원**: 2단 본문이 2열 표로 흡수돼 좌우 단의 문장이 뒤섞이던 버그 수정 — 단을 분리해 올바른 순서로 읽습니다. - **🛡️ 손상 PDF 처리 시간 폭주 가드**: 좌표가 오염된 비정상 PDF에서 파싱이 144초까지 걸리던 것을 2초대로 차단합니다 (정상 문서 출력 무변화). - **📗 한셀(HCell)로 저장한 XLSX 복구**: "시트가 없습니다"로 실패하던 한셀 저장 파일이 정상 파싱됩니다. - **📋 HML 문서의 표 소실 수정**: 문단에 앵커된 표가 통째로 빠지고 중첩표 내용이 사라지던 버그 수정 — 표 텍스트 회수율 0.23 → 0.99. ## v3.8.2 변경사항 - **📐 변환(축소/플립) 깔린 PDF의 괘선 표 복구**: 성과계획서류처럼 콘텐츠에 변환 행렬이 깔린 문서에서 표 감지가 통째로 실패하던 버그 수정 — 2줄 머리글 셀도 rowspan 병합으로 정상 복원됩니다. - **📄 스캔 PDF의 임베디드 텍스트층 복구**: CID 폰트 텍스트가 조용히 소실되던 문제 수정 — "스캔본"으로 보이던 의사록에서 전문 텍스트를 추출합니다 (일부 문서는 pdftotext보다 잘 읽습니다). ## v3.8.1 변경사항 - **🔄 PDF 회전 텍스트 복구**: 90°로 눕힌 사이드탭 목차·세로 표(계속비 총괄표 등)가 숨김 텍스트로 오인돼 통째로 빠지던 버그 수정 — 이제 보이는 회전 텍스트도 추출됩니다. (숨김텍스트 prompt-injection 방어는 그대로) - **🧱 내부 구조 정리**: PDF 선 감지(1,247줄)·HWPX 파서(1,619줄) 대형 파일을 목적별 15개 모듈로 분리 — 공개 API·출력 100% 동일 (실파일 87건 해시 검증). ## v3.8.0 변경사항 - **✏️ HWP 5.x 빈 셀 채우기** (`patchHwp`): 원본에서 비어 있던 표 셀에 마크다운 편집으로 값을 넣으면 이제 HWP 바이너리에도 삽입됩니다. 한컴이 빈 문단을 저장하는 방식(텍스트 레코드 생략형 포함)을 실파일 실측으로 지원. *(실파일 12건 무손상 검증)* - **🏛️ 공문 항목 사이 표**: "1. 항목 → 근거 표 → 2. 항목"처럼 리스트 사이에 표가 끼어도 항목 번호가 이어집니다 (공문서 모드). - **🚀 이미지 대량 참조 메모리 폭발 해소**: 같은 이미지를 수천 개 도형이 참조하는 문서(HWP·HWPX)에서 참조마다 데이터를 복사하다 **피크 17GB로 죽던 것을 445MB·0.2초 완주**로 수정. - **📢 DOCX 관측성**: 이미지/스타일/번호/각주/메타 파싱 실패를 조용히 넘기지 않고 `warnings`로 보고합니다. ## v3.7.0 변경사항 - **📋 표 행 추가/삭제** (`patchHwpx`): 마크다운에서 표에 행을 새로 넣거나 지워도 이제 원본에 반영됩니다. 새 행은 **인접 행의 서식(테두리·글꼴·높이)을 그대로 복제**해 셀 텍스트만 바꿔 넣고, `rowCnt`·셀 좌표·표 높이까지 함께 갱신합니다. 세로 병합을 가로지르거나 행에 이미지/중첩표가 있는 등 위험한 경우엔 문서를 건드리지 않고 사유와 함께 skip합니다. *(실제 결재문서 45건 검증 — 손상 0)* - **✏️ 양식 채우기 정확도**: 라벨 칸이 병합(colspan)된 서식에서 값이 **소리 없이 사라지던 버그** 수정, 표 안의 표(중첩표) 속 라벨도 채웁니다. `fillFormFields`(IR)와 `fillHwpx`(원본 보존) 두 경로가 같은 결과를 내도록 정합. - **🔎 라벨 인식 확장**: "연번1"·"제1항목"처럼 숫자가 낀 라벨, "제1소위원회위원장" 같은 9자 이상 라벨, "Name"·"Date of Birth" 같은 콜론 없는 영문 라벨을 인식합니다. "6개월"·"1억원"·"해당없음" 같은 값을 라벨로 오인하지 않는 거름망 포함. - **📢 정직한 부분 적용 보고**: `PatchSkip.partial` 신설 — "적용은 됐지만 원형 그대로는 아님"(셀 내 줄 병합·빈 문단 잔존 등)을 구분해 보고합니다. ## v3.6.0 변경사항 - **📐 실측 텍스트 메트릭 엔진**: 함초롬바탕 정품 TTF에서 글자 폭을 전수 추출해 한글 프로그램 없이 줄폭·줄바꿈을 계산합니다. 실제 결재문서의 조판 결과와 대조해 **줄바꿈점 98% 일치** 검증. - **🪗 자동 장평(`autoFit`)**: 한두 글자가 다음 줄로 넘어가는(orphan) 문단만 골라 장평을 95→90%로 줄여 한 줄에 담습니다. 공문서 작성 관행 그대로. - **📊 HTML 표 생성**: 병합(colspan/rowspan)·중첩 표가 든 마크다운도 `markdownToHwpx`로 구조 그대로 HWPX 표가 됩니다 — parse↔generate 표 라운드트립 완성. - **🗂️ 다중값 채우기**: `fillForm` 값에 배열(`string[]`)을 주면 같은 라벨의 등장 순서대로 하나씩 소진 — 반복 양식·명부형 표(헤더+여러 행) 채우기. - **🛡️ 무결성 픽스**: 채우기/패치 후 한컴이 "문서가 변조되었습니다" 경고를 띄우던 문제(줄 레이아웃 캐시 잔존), 생성 표 테두리가 보이지 않던 문제(borderFill id 규약) 수정. ## v3.5.0 변경사항 - **📊 문장을 표로 — 인플레이스 변환** (`patchHwpx`): 기존 한글파일(HWPX) 안의 문단을 마크다운 표(`| … |`)로 편집해 `patch`에 넘기면, **원본 서식을 그대로 둔 채 그 문장만 표로** 바꿔줍니다. 셀 테두리는 자동 생성, 나머지 문단·표·서식은 1바이트도 건드리지 않고 무손실 검증을 통과합니다. CLI `kordoc patch`·MCP `patch_document`가 자동 지원. *(HWP 5.x 바이너리는 미지원 — `generate`로 새 문서 생성 권장)* - **🆕 MCP `generate_document` 도구**: AI 에이전트가 마크다운(표 포함)을 바로 HWPX로 생성. `parse_document`로 읽은 내용을 표로 재구성해 다시 한글파일로 출력하는 워크플로가 완성됩니다. 공문서 프리셋(`보고서`·`기안문`…)·글꼴·글자크기 옵션 지원. - **🐛 공문서 한글 프리셋 크래시 수정**: `markdownToHwpx(md, { gongmun: { preset: "보고서" } })`처럼 라이브러리/MCP에서 한글 프리셋명을 직접 넘기면 터지던 버그 수정(`normalizeGongmunPreset`). CLI는 영향 없었음. ## v3.2.0 변경사항 - **🏛️ 공문서 모드 `markdownToHwpx(md, { gongmun })`** — 마크다운을 한국 행정 공문서 표준 서식의 HWPX로 렌더링. 행정안전부 「행정업무운영편람」·시행규칙 근거. - **항목부호 8단계 자동화** — 중첩 리스트 깊이 → `1. 가. 1) 가) (1) (가) ① ㉮` (마크다운 마커 종류 무시, 깊이로 강제). 가나다 소진 시 단모음 연속(거·너·더), 상위 항목 진행 시 하위 카운터 리셋, 단일 형제 부호 생략. - **둘째 줄 내어쓰기 정렬** — OWPML ``(음수 hanging) + ``(단계별 누적)로 둘째 줄이 내용 첫 글자에 정렬. *(실제 한컴 공문서 paraPr 구조와 동일하게 검증)* - 프리셋별 실측 여백·글자 크기 적용(기안문 본문 12pt, 보고서·계획서 15pt) + 맑은 고딕 옵션. - **문서종류 프리셋** `official`(기안문)·`report`(보고서, □○-ㆍ 불릿)·`plan`·`notice`·`minutes`. ```ts import { markdownToHwpx } from "kordoc" const md = "1. 첫째 항목\n - 둘째 항목\n - 셋째 항목" const hwpx = await markdownToHwpx(md, { gongmun: { preset: "보고서" } }) // → 1. / 가. / 1) 항목부호 + 내어쓰기 + 공식 여백 자동 적용 ``` CLI: `kordoc generate doc.md -o out.hwpx --preset 보고서` (별칭 `gen`, `--font`/`--pt`/`--line-spacing`/`--plain`). 표준 레퍼런스: `docs/gongmunseo-reference.md`, 작성 스킬: `.claude/skills/gongmunseo/`. ## v3.1.0 변경사항 - **🖊️ 에디터 통합 API `HwpxSession`** — 블록 클릭-편집형 에디터를 위한 증분 패치 세션. `openHwpxDocument(bytes)`로 열고, `session.patchBlocks(edits)`로 블록 인덱스 기반 직접 편집 (문단 텍스트 / 표 셀). **n회 연속 증분 패치 ≡ 일괄 `patchHwpx`** 바이트 동일 동등성을 CI 게이트로 보장합니다. ```ts import { openHwpxDocument } from "kordoc" const session = await openHwpxDocument(new Uint8Array(buf)) session.capability(3) // "text" | "cell-text" | "locked" — 편집 전 잠금 판정 const res = await session.patchBlocks([ { blockIndex: 3, newText: "개최 완료" }, { blockIndex: 5, cells: [{ row: 1, col: 2, text: "홍길동" }] }, ]) // session.bytes — 서식 그대로, 텍스트만 바뀐 HWPX (증분 누적) ``` - **📋 양식 필드 스키마 `extractFormSchema(blocks)`** — 양식 인식에 타입 추론을 더해 폼 UI 자동 생성 지원. 필드 타입 7종(`text`/`date`/`phone`/`email`/`amount`/`checkbox`/`idnum`) + `required`(필수 표시 감지) + `empty`(채움 대상 판정). - **`fillHwpx` splice 전환** — 수정 범위 외 섹션 XML을 원본 바이트 그대로 보존하도록 전면 재작성 (동작·결과는 v3.0과 패리티). - **CJS 빌드 수정** — `require("kordoc")` 시 `import.meta` SyntaxError 나던 버그 수정. ## v3.0.1 변경사항 - **🔄 HWP 5.x 바이너리 서식 보존 패치** — `patchHwp(원본HWP, 편집된마크다운)` 신규 API. HWPX 패치(`patchHwpx`)의 HWP 5.x(OLE2 바이너리) 대응으로, 변경된 문단/표 셀의 PARA_TEXT만 레코드 안에서 치환합니다 (PARA_HEADER 글자수·CHAR_SHAPE·LINE_SEG 연쇄 갱신). - **섹터 레벨 컨테이너 수술**: CFB 전체 재조립 없이 대상 스트림의 섹터/FAT 체인/디렉토리 엔트리만 갱신 — 수정 외 영역은 원본과 바이트 동일 (실측: 133섹터 중 5섹터만 변경) - 안전 게이트: 레코드 재직렬화 바이트 동일성 검증, 순수 텍스트 문단만 수정, 암호화/배포용/DRM 거부, 미지원 편집은 `skipped[]`로 graceful skip - CLI `kordoc patch`가 .hwp/.hwpx를 매직바이트로 자동 분기 - **CI**: Node 18 ESM `__dirname` 미정의로 테스트 매트릭스가 실패하던 문제 수정 ## v3.0.0 변경사항 - **🔄 서식 보존 무손실 라운드트립** — `patchHwpx(원본HWPX, 편집된마크다운)` 신규 API. 변경된 문단/셀의 텍스트만 원본 XML 안에서 in-place 치환하고 나머지 ZIP 엔트리는 바이트 그대로 보존. 미지원 편집(블록 추가/삭제, 표 구조 변경)은 원본을 건드리지 않고 `skipped[]`로 정직하게 보고하며, 패치 후 자동 재파싱 검증 리포트(`verification`)를 제공합니다. ```ts import { parse, patchHwpx } from "kordoc" const r = await parse(buf) // HWPX → 마크다운 const edited = r.markdown.replace("개최 예정", "개최 완료") // LLM이 편집했다고 가정 const res = await patchHwpx(new Uint8Array(buf), edited) // res.data — 서식 그대로, 텍스트만 바뀐 HWPX 바이트 // res.applied / res.skipped / res.verification — 적용·미지원·검증 리포트 ``` - **🎯 "99.9% 정확도" 파서 대도약** — 실측 공문서 코퍼스 324건(정부 보도자료 + 서울시 결재문서 + 2014~2016 옛 문서) 자기참조 채점 기준: | 지표 | v2.9.1 | v3.0.0 | |------|--------|--------| | HWPX 텍스트 재현율 | 99.699% | **99.998%** | | HWPX 표 구조 정확일치 | 99.875% | **100%** (1,421표 · 중첩표 343 포함) | | PDF coverage | 97.013% | **99.16%** | | HWP5↔HWPX 쌍 유사도 | — | **99.94%** | 중첩표 구조 보존(`IRCell.blocks`), 한컴 PUA 매핑, HWP5 이미지 추출(0→90건), 자동번호 카운터, 머리말/각주 정밀 처리 등. 채점기·코퍼스 수집기·게이트는 `bench/`에 포함 — `node bench/score.mjs`로 재현 가능. ## v2.9.0 변경사항 - **📊 PDF 텍스트 품질 신호 + OCR 필요 판정** — PDF는 텍스트층이 있어도 ToUnicode/CMap 이 깨져 한글이 깨진 글리프로 떨어지거나 NUL 등 제어문자가 섞이는 경우가 많습니다. `parsePdf` 결과에 페이지별 품질 신호(`pageQuality`)와 문서 요약(`qualitySummary`)을 추가 — `needsOcr`/`ocrReason` 으로 OCR 큐 자동 라우팅이 가능. (당시에는 신호만 노출 — **v4.2.0부터 내장 OCR 탑재**, 이 신호가 내장 OCR의 자동 발동 조건으로 쓰입니다.) 전국 지자체 주요업무계획 PDF 190건(45,399쪽) 대량 처리 중 도출. (아래 [PDF 텍스트 품질 신호](#pdf-텍스트-품질-신호-v290) 참고) ## v2.8.0 변경사항 - **🎨 `markdownToHwpx` 테마 옵션** (#31) — 헤딩/본문/인용/표 헤더 셀의 텍스트 색상과 표 헤더 굵기를 옵션으로 지정 가능. 새 export 타입 `HwpxTheme`, `MarkdownToHwpxOptions`. 옵션 미지정 시 기존과 동일하게 검정으로 출력(baseline 백워드 호환).
v2.7.2 변경사항 - **🐛 HWPX 양식 채우기 빈 셀 버그픽스** (#29, #30) — 한컴오피스에서 HWP→HWPX 로 변환한 양식의 빈 값 셀(`` 이 `` 자식 없이 self-closing)에 값이 삽입되지 않으면서 결과에는 성공으로 보고되던 false-positive 수정. `setRunText` 가 `` 없는 run 에 새로 생성해 텍스트 삽입. 기여: @amnotyoung
v2.7.1 변경사항 - **🕰️ HWP 3.0 (구버전) 파서 추가** — 1996~2002년 한컴이 쓰던 단일 binary 포맷 (`"HWP Document File V3.00"` 시그니처) 텍스트 추출. 기존 kordoc 이 거부하던 구버전 판결문/공문서 등이 검색 인덱싱 가능. 상용조합형(johab) → 유니코드 + 5,893개 한자/기호 lookup. 표 cell / 머리말 / 각주 의 nested paragraph 재귀 추출. [@edwardkim/rhwp](https://github.com/edwardkim/rhwp) 의 Rust 구현을 TypeScript 로 포팅.
v2.5.0 변경사항 - **🏛️ macOS 한컴오피스 호환 HWPX 생성** (#4) — `markdownToHwpx()` 가 만든 HWPX 가 macOS 한컴에서 "파일이 깨졌다"며 거부되던 문제 해결. 테이블 XML 을 최소 스켈레톤에서 완전 스펙 형태로 재작성 — `` 필수 속성 10종 + ``/``/``/``, `` 안에 `` 래퍼 + ``/``/``/``, paragraph 래핑. `Preview/PrvText.txt` 추가 + `borderFill` id=1(SOLID 0.12mm) 추가. - **🔓 HWP 5.x 배포용 문서 COM fallback** (#25) — `.hwp` 바이너리에서 "이 문서는 상위 버전의 배포용 문서입니다..." 경고 플레이스홀더만 나오는 케이스에서, Windows + 한컴오피스 환경이면 자동으로 `HWPFrame.HwpObject` COM API 로 재시도. v2.4.0 의 HWPX DRM fallback 인프라를 `.hwp` 에도 확장.
v2.4.0 변경사항 - **🔓 HWPX DRM 배포용 문서 자동 추출** — 공공기관 배포용 DRM이 걸린 HWPX 파일을 한컴 오피스 COM API로 자동 텍스트 추출. `manifest.xml`에서 암호화 감지 → `HWPFrame.HwpObject`의 `GetPageText`로 페이지별 추출 → Markdown 변환. Windows + 한컴 오피스 설치 환경에서 별도 설정 없이 동작.
v2.3.0 변경사항 - **📄 HWPML 2.x 파서 추가** — XML 기반 한컴 문서(`.hwp` XML 방식) 파싱 지원. `npx kordoc `에서 `지원하지 않는 파일 형식` 오류가 나던 XML 기반 공문서를 이제 Markdown으로 변환할 수 있습니다. HWP 5.x 바이너리와 자동 구분(XML 시그니처 감지). - **🧩 중첩 테이블 마커** — HWPX/HWP5에서 셀 내부 중첩 테이블이 있던 위치에 `[중첩 테이블 #N]` 마커 삽입. 큰 중첩 테이블(≥3행 + ≥2열)은 별도 블록으로 분리, 작은 것은 셀 내 평탄화. HWP5는 기존에 내용이 완전히 손실되던 것을 마커로 복구. - **🖼️ HWPX 이미지 추출 버그 수정** — `binaryItemIDRef`가 확장자 없이(`"image1"`) 저장된 HWPX에서 이미지 추출이 실패하던 문제 해결. ZIP 내 파일명 regex 매칭으로 복원. - **📄 PDF 머리글/바닥글 감지 개선** — 텍스트 반복 패턴 + y좌표 클러스터링 하이브리드. 페이지마다 달라지는 동적 머리글(챕터명 등)도 위치 기반으로 감지. 감지 영역 10% → 12%로 확장.
v2.2.4 변경사항 - **📝 양식 자동 채우기 (Form Filler)** — 공문서 양식 템플릿에 값을 자동으로 채워넣습니다. 라벨-값 셀 패턴, 체크박스(`□`→`☑`), 괄호 빈칸(`일반( )통`→`일반(3)통`), 어노테이션(`(한자:)`→`(한자:金)`) 지원. - **🏛️ HWPX 원본 서식 보존 모드** — `fillHwpx()`로 HWPX XML을 직접 조작하여 글꼴, 크기, 정렬 등 원본 서식 100% 유지한 채 값만 교체. - **📊 병합 셀 HTML 테이블 출력** — `colspan`/`rowspan`이 있는 복잡한 표를 GFM 대신 HTML ``로 출력하여 구조 보존. - **🔧 markdownToHwpx 서식 강화** — 역변환 시 heading/bold/italic/table 등 서식 지원 대폭 개선. - **🤖 MCP fill_form 도구** — AI 에이전트가 양식을 직접 채울 수 있는 새 MCP 도구 추가 (총 8개).
v2.2.1 변경사항 - **🔧 마크다운 렌더링 개선** — GFM 특수문자(`~`) 이스케이프로 취소선 오해석 방지, 테이블 셀 내 `|` 문자 이스케이프, 중첩 테이블 텍스트 구분자 `|` → `/` 변경으로 GFM 파서 충돌 방지. - **📝 문단 간격 정상화** — paragraph 블록 사이 빈 줄 삽입으로 마크다운에서 별도 문단으로 렌더링.
v2.2.0 변경사항 - **🛡️ 보안 강화 7건** — XLSX/DOCX Billion Laughs(XXE) 방지, Watch SSRF 리다이렉트·10진수IP·symlink 차단, HWP5 lenient decompression bomb 방지, CFB FAT 섹터 상한, buildTableDirect 메모리 폭주 방지. - **💥 Crash 방지** — `Math.min/max(...spread)` 스택 오버플로 수정 (15개소), Watch 동시 처리 제한(MAX_CONCURRENT=3). - **🐛 정확성 개선** — Levenshtein 동일 길이 유사도 1.0 버그 수정, MCP `parse_metadata` XLSX/DOCX 오분류 수정, PDF 폰트 크기 통계 메모리 최적화(40MB→~50엔트리). - **📦 품질** — CLI JSON Uint8Array base64 변환, `isPathTraversal` 합법적 파일명 오탐 수정.
v2.1.0 변경사항 - **📄 대형 HWPX 정부문서 파싱** — `

>>` 구조의 중첩 테이블 파싱 누락 수정. - **📰 PDF 2단 레이아웃 감지** — 다단 논문·보고서의 컬럼 구조를 감지하여 읽기 순서대로 추출. - **🛡️ 입력 검증 강화** — 폰트 크기 NaN/음수 가드, colSpan/rowSpan NaN 가드.

v2.0 변경사항 - **🔓 배포용(열람 제한) HWP 파싱 지원** — 관공서에서 배포용으로 잠근 HWP 파일도 이제 파싱됩니다. AES-128 ECB 복호화, 순수 JS 구현. [rhwp](https://github.com/edwardkim/rhwp)(MIT) 알고리즘 포팅. - **손상된 HWP 파일 복구** — 표준 CFB 모듈이 거부하는 파일을 직접 FAT/디렉토리 파싱으로 복구. rhwp LenientCfbReader 포팅. - **HWP5 각주/미주/하이퍼링크 추출** — 각주 본문 텍스트 연결, 하이퍼링크 URL 추출 및 XSS 살균. - **HWPX 표 병합 밀림 수정** — colspan/rowspan 그리드 계산 버그 수정. - **보안 강화** — CFB 섹터 크기 검증, sanitizeHref 3중 경로 일관 적용.
v1.8.0 변경사항 - **XLSX 파서 추가** — Excel 스프레드시트 파싱. 공유 문자열, 병합 셀, 다중 시트 지원. 시트별 heading + table 블록 생성. - **DOCX 파서 추가** — Word 문서 파싱. 스타일 기반 heading, 번호 매기기(리스트), 각주, 하이퍼링크, 이미지 추출, vMerge/gridSpan 테이블 병합. - **파싱 품질 대폭 개선** — PDF/HWPX/HWP5/XLSX 전 포맷 품질 점수 73→93점. - **프로덕션 리뷰 17건 수정** — CLI `--no-header-footer` 플래그 반전 버그, MCP XLSX/DOCX 확장자 허용, ZIP bomb 보호 공유 유틸화, href XSS 살균 강화, PDF timeout 타이머 정리, HWP5 BinData O(n) 최적화, cluster indexOf O(n²)→O(n), SSRF IPv6 차단 등.
v1.7.x 변경사항 - **이미지 추출 (HWP/HWPX)** — ZIP 엔트리와 HWP5 BinData 스트림에서 바이너리 이미지 추출. - **부분 파싱 (Graceful Degradation)** — 개별 페이지 실패가 전체 파싱을 중단하지 않음. - **진행률 콜백** — `onProgress` 콜백. CLI에서 `[3/15 pages]` 형태 표시. - **파일 경로 직접 입력** — `parse("path/to/file.hwp")` 문자열 오버로드. - **PDF 머리글/바닥글 필터링** — `removeHeaderFooter` 옵션. - **보안 강화** — ZIP bomb 추적, SSRF 방지, XSS 방어, 널바이트 감지, PDF 타임아웃. - **pdfjs-dist v5 호환** — constructPath 연산자 형식 변경 대응.
v1.6.1 수정사항 - **HWP5 테이블 셀 오프셋 수정** — LIST_HEADER 파싱 시 2바이트 오프셋 밀림으로 rowAddr를 colSpan으로 잘못 읽던 치명적 버그 수정. 3열 테이블이 6열로 뻥튀기되던 문제 해결. colAddr/rowAddr 기반 직접 배치로 병합 테이블 정확도 향상. - **HWP5 TAB 제어문자 수정** — TAB(0x0009) 인라인 컨트롤의 14바이트 확장 데이터 스킵 누락으로 `࣐Ā` 쓰레기 문자가 출력되던 버그 수정.
v1.6.0 기능 - **클러스터 기반 테이블 감지 (PDF)** — 선 없는 PDF에서 텍스트 정렬 패턴으로 테이블 구조 추론. baseline 그룹핑 + X좌표 클러스터링으로 2열 이상 테이블 감지. 선 기반 감지가 실패한 경우의 중간 계층 fallback. - **한국어 특수 테이블 감지** — `구분/항목/종류/기준` 등 한국 공문서 key-value 패턴을 자동으로 2열 테이블로 변환. - **한국어 어절 끊김 복원** — PDF 셀 내 한글 문자별 렌더링으로 인한 미세 갭 처리 개선. 셀 줄바꿈 병합 임계값 8자로 확장, 1글자 조사 자동 연결. - **빈 테이블 필터링** — 장식용 선에서 생긴 빈 테이블 자동 제거.
v1.5.0 기능 - **선 기반 테이블 감지 (PDF)** — OpenDataLoader 핵심 알고리즘 포팅. PDF 그래픽 명령에서 수평/수직 선을 추출하고, 교차점으로 그리드 구성, bbox overlap으로 텍스트→셀 매핑. colspan/rowspan 자동 감지. 선 없는 PDF는 기존 휴리스틱 fallback. - **IRBlock v2** — 6가지 블록 타입: `heading`, `paragraph`, `table`, `list`, `image`, `separator`. 새 필드: `bbox`, `style`, `pageNumber`, `level`, `href`, `footnoteText`. - **ParseResult v2** — `outline` (문서 구조), `warnings` (스킵된 요소, 숨김 텍스트) 필드 추가. - **PDF 개선** — XY-Cut 읽기 순서, 폰트 크기 기반 헤딩 감지, hidden text 필터링 (프롬프트 인젝션 방어), 모든 블록에 바운딩 박스. - **HWP5 개선** — CHAR_SHAPE 파싱, 스타일 기반 헤딩 감지, OLE/이미지 스킵 경고. - **HWPX 개선** — header.xml 스타일 파싱, 하이퍼링크/각주 추출. - **리스트 감지** — 테이블 뒤 번호 문단을 ordered list 블록으로 자동 변환. - **MCP 서버** — parse_document 응답에 `outline`, `warnings` 포함.
v1.4.x 기능 - **문서 비교 (Diff)** — IR 레벨 블록 비교로 신구대조표 생성. HWP↔HWPX 크로스 포맷 지원. - **양식 인식** — 공문서 테이블에서 label-value 쌍 자동 추출. 성명, 소속, 전화번호 등. - **구조화 파싱** — `IRBlock[]`과 `DocumentMetadata`에 직접 접근. 마크다운 넘어선 데이터 활용. - **페이지 범위** — `parse(buffer, { pages: "1-3" })` — 필요한 페이지만 빠르게. 한컴 저장본은 실제 쪽 번호 기준(`metadata.pageMode: "layout"`), 조판 캐시 없는 생성 파일은 섹션 근사(`"section"`). - **Markdown → HWPX** — 역변환. AI가 생성한 내용을 바로 공문서로. - **OCR** — 스캔/이미지 PDF 텍스트 추출. 내장 엔진(`ocr: true`, PP-OCRv5 korean) 또는 외부 프로바이더(Tesseract, Claude Vision 등). - **Watch 모드** — `kordoc watch ./수신함 -d ./변환결과 --webhook https://...` - **MCP 7개 도구** — parse_document, detect_format, parse_metadata, parse_pages, parse_table, compare_documents, parse_form - **에러 코드** — `"ENCRYPTED"`, `"ZIP_BOMB"`, `"IMAGE_BASED_PDF"` 등 구조화된 에러 핸들링
--- ## 설치 ```bash npm install kordoc ``` PDF 파싱(pdfjs-dist)·OCR(onnxruntime·sharp·pdfium) 등 선택 의존성은 **기본 설치**됩니다 (optionalDependencies). 설치 용량을 줄이려면 `npm install kordoc --omit=optional` 로 스킵할 수 있습니다 — 이 경우 PDF 파싱·OCR·PNG 래스터 등 일부 기능이 제한됩니다. `markdownToPdf`/`blocksToPdf`(인쇄 렌더)만 `puppeteer-core` 를 **선택적 peer 의존성**으로 쓰며 자동 설치되지 않습니다 — 쓰려면 `npm install puppeteer-core` 를 따로 하세요. ## 빠른 시작 ### 문서 파싱 ```typescript import { parse } from "kordoc" import { readFileSync } from "fs" const buffer = readFileSync("사업계획서.hwpx") const result = await parse(buffer) if (result.success) { console.log(result.markdown) // 마크다운 텍스트 console.log(result.blocks) // IRBlock[] 구조화 데이터 console.log(result.metadata) // { title, author, createdAt, pageMode, ... } console.log(result.pages) // [{ pageNumber, markdown }] — 쪽 단위 본문 (v4.8) } ``` `pages` 는 블록에 쪽 번호가 붙는 포맷(HWP·HWPX·PDF, XLS(X)는 시트=한 쪽)에서만 나옵니다 — DOCX 처럼 쪽을 매기지 않는 포맷에서는 없는 사실을 만들지 않고 필드 자체를 생략합니다. 경계의 신뢰도는 `metadata.pageMode` (`"layout"` = 조판 캐시 기반 실제 쪽 / `"section"` = 섹션 근사)로 구분합니다. ### 문서 비교 (신구대조표) ```typescript import { compare } from "kordoc" const diff = await compare(구버전Buffer, 신버전Buffer) // diff.stats → { added: 3, removed: 1, modified: 5, unchanged: 42 } // diff.diffs → BlockDiff[] (테이블은 셀 단위 diff 포함) ``` HWP vs HWPX 크로스 포맷 비교도 가능합니다. ### 양식 필드 추출 ```typescript import { parse, extractFormFields } from "kordoc" const result = await parse(buffer) if (result.success) { const form = extractFormFields(result.blocks) // form.fields → [{ label: "성명", value: "홍길동", row: 0, col: 0 }, ...] // form.confidence → 0.85 } ``` ### 양식 자동 채우기 ```typescript import { fillForm } from "kordoc" import { readFileSync, writeFileSync } from "fs" const template = readFileSync("신청서.hwpx") // HWPX 원본 서식 보존 모드 — 글꼴, 크기, 정렬 100% 유지 const result = await fillForm(template, { 성명: "홍길동", 주민등록번호: "900101-1234567", 주소: "서울특별시 광진구 능동로 120", }, "hwpx-preserve") writeFileSync("신청서_작성완료.hwpx", Buffer.from(result.output as ArrayBuffer)) // result.fill.filled → [{ label: "성명", value: "홍길동" }, ...] // result.fill.unmatched → 매칭 실패한 키 목록 ``` ### 내장 정부 표준 기안문 서식 + 누름틀 채우기 「행정 효율과 협업 촉진에 관한 규정 시행규칙」 별지 서식 기반 **표준 기안문 HWPX가 패키지에 내장**되어, 파일 없이 이름만으로 실물 배치 품질의 공문서를 만들 수 있습니다 (서식 자산: [rhwp](https://github.com/edwardkim/rhwp) tools/forms, MIT — THIRD_PARTY/rhwp-forms.txt): | 이름 | 서식 | 용도 | 누름틀 | |------|------|------|--------| | `gian` (일반기안문) | 별지 제1호서식 | 대외 시행문·협조문 | 23곳 — 행정기관명·수신자·경유·제목·본문·붙임·발신명의·기안자·검토자·결재권자·시행번호 등 | | `gian-simple` (간이기안문) | 별지 제2호서식 | 내부결재 보고서·계획서 (결재란 표) | 13곳 — 생산등록번호·결재직위1~4·제목·요약설명·작성일 등 | ```bash npx kordoc fill --list-templates # 내장 서식 목록 + 필드 나열 npx kordoc fill --template gian -j 값.json -o 기안문.hwpx npx kordoc fill templates:간이기안문 -f '제목=…' -o 보고.hwpx # 위치 인자 표기도 동일 ``` 채우기 엔진이 **누름틀(CLICK_HERE 필드)을 이름으로 정확 매칭해 우선 채우고**, 남은 키는 기존 라벨 매칭으로 처리합니다 — 누름틀이 있는 어떤 HWPX 서식(메일머지 양식 등)에도 동작합니다. `본문`처럼 `\n`이 든 값은 문단 내 줄바꿈으로 들어가고, 안내문과 동일한 값을 채워도 유실되지 않으며, 원본 charPr(서식)은 그대로 보존됩니다. API로는 `extractClickHereFields(buf)`(필드 조사)와 `readBuiltinTemplate(resolveBuiltinTemplate("gian")!)` (서식 로드) → `fillHwpx(buf, 값)` 조합입니다. MCP `fill_form` 도구도 `template` 파라미터로 같은 서식을 씁니다. ### HWPX 생성 (역변환) ```typescript import { markdownToHwpx } from "kordoc" const hwpxBuffer = await markdownToHwpx("# 제목\n\n본문 텍스트\n\n| 이름 | 직급 |\n| --- | --- |\n| 홍길동 | 과장 |") writeFileSync("출력.hwpx", Buffer.from(hwpxBuffer)) // display math block은 HWPX native 수식()으로 생성됩니다. // 초기 지원 범위는 \frac, \sqrt, 첨자/위첨자, Greek, 적분/극한, // 화살표, 관계 연산자, matrix 계열의 제한된 LaTeX-like subset입니다. const withEquation = await markdownToHwpx("피타고라스\n\n$$a^2 + b^2 = c^2$$") // 공문서 모드 — 항목부호 8단계 + 내어쓰기 + 공식 여백/명조 자동 const gongmun = await markdownToHwpx("1. 추진배경\n - 세부 항목\n2. 추진계획", { gongmun: { preset: "보고서" }, // official | report | plan | notice | minutes | gaejosik | press | ministry(업무보고) }) // 정부 표준 개조식 보고서 (v4.0) — 표지·목차(장식 배너)·로마숫자 장헤더· // 본문 제목박스·쪽번호("- 1 -", 표지·목차 제외)까지 실측 정부 양식 그대로 const report = await markdownToHwpx(md, { gongmun: { preset: "개조식", cover: { org: "기관명", date: "2026. 7. 11." }, toc: true, // h2 목록 → Ⅰ Ⅱ Ⅲ 목차 (개조식 기본 켜짐) approval: ["담당", "팀장", "과장"], // 결재란 (선택) pageNumbers: true, // 쪽번호 (개조식·보고서·계획서 기본 켜짐) endMark: false, // 본문 끝 "끝." (기안문 기본 켜짐) }, }) // 표는 실측 정부 문법 자동 적용: 헤더 음영+bold+하변 이중선, 외곽 0.4mm 위계, // 라벨열 음영, 내용 비례 열폭(수치 열 실폭 고정), 본문폭보다 좁게 + 우측 배치 ``` CLI로도: `kordoc generate 보고서.md -o 보고서.hwpx --preset 개조식 --org 기관명 --approval 담당,팀장,과장` (`--toc/--no-toc` `--cover/--no-cover` `--page-numbers` `--end-mark` `--no-body-title-box` `--fonts` `--sizes`) ### 레이아웃 보존 렌더 (HWPX → SVG) 한컴이 HWPX에 저장하는 조판 캐시(줄 좌표·셀 그리드·개체 앵커)를 그대로 SVG 절대배치로 그립니다. 조판 엔진 없이 빠르고, 서버에 한컴 설치 없이 원본 모양 미리보기를 만들 수 있습니다. 다페이지 세로 스택·검색어 형광펜·그리기 도형 지원(v3.14~15). 조판 캐시가 없는 파일(`markdownToHwpx` 산출물·AI 생성본·편집본)은 `reflow: true`를 주면 **순수 TS reflow 엔진**이 직접 조판합니다(v3.15). 수식 개체는 미지원. ```typescript import { renderHwpxToSvg } from "kordoc" const r = await renderHwpxToSvg(readFileSync("결재문서.hwpx"), { highlights: ["예산"] }) writeFileSync("결재문서.svg", r.svg) // r.width/r.height (pt), r.pageCount, r.stats { texts, images, tables }, r.warnings const g = await renderHwpxToSvg(generatedHwpx, { reflow: true }) // 조판 캐시 없는 생성본 // 통합 렌더 — HWPX·HWP(5.x) 모두, 페이지별 PNG + 표 영역 crop (v4.13, HWP v4.13.1) const { scene, assets } = await renderDocument("결재문서.hwp", { format: "png", pages: "1-2" }) const crops = await extractRenderedRegions("결재문서.hwp", { types: ["table"] }) ``` CLI로도: `kordoc render 결재문서.hwpx -o 결재문서.svg` — 조판 캐시 없는 문서는 기본으로 reflow 조판되며 `--no-reflow`로 끌 수 있습니다 (`--highlight 예산,집행` 지원), 연속 렌더는 `kordoc render-worker`(stdin NDJSON, 미리보기 앱 연동용) ### 글자만 필요할 때 (이미지 끄기·상주 파싱 워커) ```typescript const result = await parse(buffer, { images: false }) // 이미지 바이트 없이 (그림 자리 표시는 남김) ``` CLI 는 `kordoc 문서.pdf --format json --no-images`. 대량 변환은 `kordoc parse-worker` 를 띄워 두고 stdin 으로 한 줄씩 요청합니다 (한 줄 = 한 JSON). ```text 시작 {"ready":true,"version":"4.15.0","protocol":1} 요청 {"id":1,"file":"문서.hwpx","images":false,"ocr":"off"} 응답 {"id":1,"rss":183500800,"result":{ …--format json 과 같은 결과, 실패도 success:false 로… }} 종료 {"cmd":"quit"} (또는 stdin 닫기) ``` `ocr` 은 `"off"`·`"auto"`(OCR 필요 페이지만)·`"force"`, 그 밖에 `formulaOcr`·`password` 를 받습니다. ### 페이지 범위 지정 ```typescript const result = await parse(buffer, { pages: "1-3" }) // 1~3 페이지만 const result = await parse(buffer, { pages: [1, 5, 10] }) // 특정 페이지 ``` ### OCR (스캔/이미지 PDF) — 내장 엔진 (v4.2.0+) ```typescript // 내장 OCR (PP-OCRv5 korean, 첫 사용 시 모델 ~18MB 자동 다운로드) const result = await parse(buffer, { ocr: true }) // OCR 필요 페이지만 자동 판정 const result = await parse(buffer, { ocr: "force" }) // 전 페이지 강제 OCR ``` - **API 키·외부 서비스 불필요** — det(선 검출)+rec(CTC 인식) ONNX 를 로컬 CPU 로 추론합니다 (PaddlePaddle 공식 변환본, Apache-2.0 / 한국어 사전 11,945자 — 완성형 한글 11,172자 전량 + 자모·라틴·기호). - **페이지 단위 정밀 적용** — 텍스트층이 없는 스캔 페이지, ToUnicode 가 깨진 페이지 (`needsOcr` 신호)만 OCR 하고 정상 페이지의 파싱 결과는 그대로 유지합니다. - **표 복원** — OCR 라인 좌표를 기존 블록 파이프라인(xy-cut 읽기 순서 + 클러스터 표 감지)에 태우므로 스캔본에서도 표 구조가 복원됩니다. - 외부 OCR 을 쓰고 싶으면 종전대로 프로바이더 함수를 전달하세요: ```typescript const result = await parse(buffer, { ocr: async (pageImage, pageNumber, mimeType) => { return await myOcrService.recognize(pageImage) // Claude Vision, Tesseract 등 } }) ``` ### PDF 텍스트 품질 신호 (v2.9.0+) PDF는 텍스트층이 있어도 ToUnicode/CMap이 깨졌거나 NUL 등 제어문자가 섞이는 경우가 많다. `parsePdf` 결과는 페이지별 품질 신호를 함께 반환한다. ```typescript const r = await parsePdf(buffer) if (r.success && r.qualitySummary?.needsOcr) { // 내장 OCR 로 재시도 (v4.2.0+) — 또는 외부 OCR 큐로 라우팅 const retried = await parse(buffer, { ocr: true }) } // 페이지 단위 신호 for (const p of r.pageQuality ?? []) { if (p.needsOcr) console.log(`p${p.page} 검토 필요: ${p.ocrReason}`) } ``` 신호 키: `textChars`, `hangulRatio`, `controlCharRatio`, `replacementCharRatio`, `puaRatio` / `needsOcr` (페이지·문서 단위) / `ocrReason` (`low_text` | `high_pua` | `high_control` | `high_replacement` | `garbled_hangul` | `vector_text`). `vector_text` 는 글자를 곡선으로 그려 텍스트층에 글이 없는 쪽입니다(v4.14.4). ## CLI ```bash npx kordoc 사업계획서.hwpx # 터미널 출력 npx kordoc 보고서.hwp -o 보고서.md # 파일 저장 npx kordoc *.pdf -d ./변환결과/ # 일괄 변환 npx kordoc 검토서.hwpx --format json # JSON (blocks + pages + metadata 포함) npx kordoc 검토서.pdf --format chunks # RAG용 구조 청크 JSON (breadcrumb + 표 독립 청크) npx kordoc 보고서.hwpx --pages 1-3 # 페이지 범위 npx kordoc 스캔본.pdf --ocr # 내장 OCR (필요 페이지 자동 판정, --ocr-force로 전 페이지) npx kordoc 잠긴문서.hwpx --password '암호' # 열기 암호가 걸린 HWPX/HWP3/HWP5 npx kordoc 시험지.pdf --no-tables # PDF 표 감지 끄기 (2단 시험지 등 읽기순 우선) npx kordoc fill 신청서.hwpx -f '성명=홍길동,주소=서울' -o 결과.hwpx # 양식 채우기 npx kordoc fill 신청서.hwpx -j values.json -o 결과.hwpx # JSON 파일로 채우기 npx kordoc fill 신청서.hwpx --dry-run # 필드 목록만 확인 (누름틀 포함) npx kordoc fill --template gian -j 값.json -o 기안문.hwpx # 내장 표준 기안문 서식 채우기 npx kordoc fill --list-templates # 내장 서식 목록 + 필드 npx kordoc fill 신청서.hwpx -j 값.json --formats '{"날짜":"yy.mm.dd"}' # 필드별 값 서식 (라벨→포맷) npx kordoc fill 신청서.hwpx -j 값.json --require-unique # 한 키가 2곳 이상 매칭되면 거부 (반복 라벨 오염 방지) npx kordoc fill 신청서.hwpx -j 값.json --mask # 채운 값 미노출 (stdout 에 본문 대신 안내만) npx kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 # 마크다운 → 공문서 HWPX npx kordoc patch 원본.hwpx 편집.md -o 반영.hwpx # 서식 보존 라운드트립 패치 (.hwp도 자동 분기) npx kordoc seal 신청서.hwpx --image 도장.png --anchor "(인)" -o 날인.hwpx # 도장/서명 날인 npx kordoc validate 산출물.hwpx # HWPX 구조 검증 (ZIP·필수 파트·XML) npx kordoc lint 보고서.md # 공문서 표기법 검수 19룰 — 입력은 md/txt('-'=stdin), error 있으면 exit 1 npx kordoc redact 민원서류.hwpx -o 마스킹.hwpx # 개인정보 탐지 + 서식 보존 마스킹 (머리말·각주·미리보기·문서 정보 포함, 잔존 재검사 — 남으면 exit 2) npx kordoc redact 민원서류.hwpx --mask-char '*' -o 마스킹.hwpx # 마스크 문자 지정 (기본 ●) npx kordoc redact 계약서.hwp --rules rrn,phone,crn --json --dry-run # 룰 선택(법인등록번호 crn·IP 는 opt-in) + 위치별 리포트만 npx kordoc redact 민원서류.hwpx --rules rrn,phone,email,name,address -o 마스킹.hwpx # 이름·주소까지 (opt-in) npx kordoc redact 공문.pdf # PDF·DOCX 등은 원본을 고치지 않고 마스킹된 마크다운(.redacted.md)만 — PDF 가림 미지원 npx kordoc profile 기관서식.hwpx # 표 서식 프로필(JSON) 추출 → generate --profile 로 재현 npx kordoc render 결재문서.hwpx -o 미리보기.svg # 레이아웃 보존 SVG 렌더 (캐시 없는 문서는 자동 reflow 조판, --no-reflow로 끔) npx kordoc render 결재문서.hwpx --reflow-mode charAll -o 미리보기.svg # reflow 줄바꿈: keep(어절, 기본) | charAll(글자) npx kordoc models --status # OCR 모델 상태 (--export/--import 로 폐쇄망 사이드로드) npx kordoc check-ocr-models --status-only # OCR 모델 상태만 JSON 출력 (옵션 빼면 없는 모델을 받는다) npx kordoc check-formula-models --status-only # 수식 OCR 모델(MFD+MFR+tokenizer, ~155MB) 상태만 출력 npx kordoc watch ./수신함 -d ./변환결과 # 폴더 감시 모드 npx kordoc watch ./문서 --webhook https://api/hook # 웹훅 알림 ``` `watch -d` 는 감시 폴더 안의 하위 폴더 구조를 출력에도 그대로 둡니다: `수신함/팀/보고서.hwpx` → `변환결과/팀/보고서.md`(또는 `.json`). `수신함` 바로 아래 파일은 종전처럼 `변환결과` 바로 아래에 씁니다. > `check-ocr-models` · `check-formula-models` 는 이름과 달리 **없거나 SHA 가 안 맞으면 내려받습니다**. > 상태만 보려면 `--status-only` 를 붙이세요 (수식 모델은 ~155MB). > > `kordoc lint` 는 **텍스트(마크다운/txt)를 검사합니다** — HWPX 를 바로 넘기면 안 됩니다. > 생성물을 검수하려면 원고 마크다운을 넘기거나, `kordoc 문서.hwpx | kordoc lint -` 로 파이프하세요. > (공문서 생성 시에는 `generate` 가 같은 룰의 경고를 함께 냅니다. `END_MARK_MISSING` 은 완성 원고를 보는 `lint` 에서만 켜집니다.) ### 실패 계약 — 기계 판독 가능한 실패 JSON (v4.10.0+, #69) 변환 실패는 **모든 `--format`(markdown·json·chunks)에서** stdout 에 동일한 실패 JSON 을 내고 exit 1 로 끝납니다. 호출자는 stderr 문구가 아니라 `code` 로 분기하면 됩니다. ```json { "success": false, "fileType": "hwpx", "error": "암호화된 문서입니다 …", "code": "ENCRYPTED" } ``` 성공 출력과 충돌하지 않습니다 — `markdown` 성공은 마크다운 텍스트, `chunks` 성공은 JSON **배열**, 실패는 언제나 `success:false` **객체**입니다. `-o`/`-d` 지정 시 실패한 파일의 출력물은 생성되지 않습니다. 여러 파일 입력 시 실패한 파일마다 실패 JSON 이 한 개씩 나옵니다. | `code` | 의미 | |---|---| | `ENCRYPTED` | 열기 암호 문서 (`--password` 필요 또는 불일치) | | `DRM_PROTECTED` | 한컴 문서보안(DRM) — 열 수 없음 | | `UNSUPPORTED_FORMAT` | 지원하지 않는 파일 형식 | | `CORRUPTED` | 시그니처 불일치·복구 불가 손상 | | `IMAGE_BASED_PDF` | 텍스트층 없는 스캔 PDF (`--ocr` 필요) | | `ZIP_BOMB` / `DECOMPRESSION_BOMB` | 압축 폭탄 방어 발동 | | `NO_SECTIONS` | 본문 섹션 없음 | | `OUTPUT_TOO_LARGE` | 출력 직렬화가 런타임 문자열 한계 초과 (#65) | | `MISSING_DEPENDENCY` | 선택 의존성 미설치 (pdfjs-dist 등) | | `EMPTY_INPUT` | 빈 입력 | | `PARSE_ERROR` | 그 외 파싱 실패 | **안정성 보증**: 종료 코드 규칙(성공 0 / 실패 1)과 실패 JSON 의 필드(`success`·`fileType`·`error`·`code`)는 유지되고, `code` 값 집합은 **추가만** 됩니다(기존 값 변경·제거 없음). `error` 문구는 사람용이라 계약이 아닙니다. ### 이미지 번들 — `images/manifest.json` (v4.10.0+, #70) `-o`/`-d` 로 저장할 때 추출 이미지는 `images/` 에 저장되고, 같은 폴더에 `manifest.json` 이 함께 나옵니다. 소비자는 확장자·매직바이트 추측 없이 manifest 로 형식을 분기하면 됩니다. ```json [ { "name": "image_001.png", "mimeType": "image/png", "bytes": 68, "source": "BinData/image1.png" } ] ``` - `mimeType` 은 **매직바이트 실측 우선**(PNG/JPEG/GIF/BMP/WMF/EMF 판별) — 확장자 유래 선언값과 다르면 실측이 이깁니다. 실측 불가 형식(TIFF·SVG 등)은 선언값을 그대로 둡니다. - `source` 는 원본 컨테이너 항목명(HWPX/DOCX ZIP 경로, HWP5 BinData 스토리지명). PDF 처럼 재인코딩으로 합성된 이미지에는 없습니다. - 나올 수 있는 확장자 집합: **PDF 는 항상 `png`**(순수 JS 재인코딩) · HWP5 는 스니프 유래 `png/jpg/gif/bmp`(WMF/EMF 는 `bin`) · HWPX 는 원본 확장자 유래 `png/jpg/gif/bmp/tif/wmf/emf/svg`(미지 확장자는 `bin`) · DOCX 는 원본 확장자 유지. 이미지 재인코딩은 하지 않습니다(원형 유지) — 형식 판정은 manifest 를 믿으세요. ## MCP 서버 (Claude / Cursor / Windsurf / Codex) **자동 설치 (추천)**: ```bash npx -y kordoc setup ``` 대화형으로 AI 클라이언트를 감지해 설정 파일을 자동 패치. Windows 에서 `cmd /c npx` 래핑도 자동. 상세는 위 [30초 설치](#-30초-설치-ai-에이전트-연동) 섹션. Codex는 설정 파일을 직접 수정하지 않고 `codex mcp add` 명령으로 안전하게 등록합니다. **Codex 수동 등록**: ```bash codex mcp add kordoc -- npx -y kordoc mcp ``` **수동 등록 (macOS / Linux)**: ```json { "mcpServers": { "kordoc": { "command": "npx", "args": ["-y", "kordoc", "mcp"] } } } ``` **수동 등록 (Windows — Claude Desktop 이 `.cmd` 를 못 찾을 때)**: ```json { "mcpServers": { "kordoc": { "command": "cmd", "args": ["/c", "npx", "-y", "kordoc", "mcp"] } } } ``` **17개 도구:** | 도구 | 설명 | |------|------| | `parse_document` | HWP/HWPX/PDF/XLSX/DOCX → 마크다운 (메타데이터 포함) | | `detect_format` | 매직 바이트로 포맷 감지 | | `parse_metadata` | 메타데이터만 빠르게 추출 | | `parse_pages` | 특정 페이지 범위만 파싱 | | `parse_table` | N번째 테이블만 추출 | | `compare_documents` | 두 문서 비교 (크로스 포맷) | | `parse_form` | 양식 필드를 JSON으로 추출 | | `fill_form` | 양식 템플릿에 값 채우기 (HWPX 원본 서식 보존, 서식/유일성 가드) | | `patch_document` | 편집된 마크다운을 원본 HWPX/HWP에 서식 보존 반영 (v3.3) | | `extract_profile` | 참조 HWPX에서 표 서식 프로필(JSON) 추출 — generate_document의 profile_path로 재현 | | `generate_document` | 마크다운(표·수식·차트 포함) → HWPX 생성, 공문서 프리셋 (v3.5) | | `place_seal` | 도장/서명 이미지를 앵커 문구 위에 부유 배치 (v3.16) | | `render_document` | HWPX·HWP를 조판 그대로 PNG/JPEG 이미지(응답)·SVG/HTML/PDF 파일로 렌더 — 생성·수정 결과를 AI가 눈으로 검증 (v4.1, HWP·포맷 확장 v4.13.1) | | `redact_document` | 개인정보(주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허, opt-in 법인등록번호·IP·이름·주소) 탐지 + 서식 보존 마스킹 — HWPX/HWP는 머리말·각주·미리보기·문서 정보까지 가리고 잔존 재검사, 그 외 포맷은 마스킹된 마크다운만 (v4.1) | | `parse_chunks` | RAG용 구조 청크 JSON — 헤딩·개조식 위계 breadcrumb + 표 독립 청크 (v4.1) | | `crop_regions` | 렌더 영역(표·이미지·문단·도형)을 페이지 이미지에서 실배율로 잘라 저장 + regions.json (v4.13) | | `extract_tables` | 표 분류(데이터표/조직도류/불확실) + 페이지·bbox + 정책별 crop — 조직도는 이미지로, 데이터표는 구조로 (v4.13.1) | ## API ### 핵심 함수 | 함수 | 설명 | |------|------| | `parse(buffer, options?)` | 포맷 자동 감지 → Markdown + IRBlock[] | | `parseHwpx(buffer, options?)` | HWPX 전용 | | `parseHwp(buffer, options?)` | HWP 5.x 전용 | | `parseHwp3(buffer, options?)` | HWP 3.x (1996~2002 구버전) 전용 | | `parsePdf(buffer, options?)` | PDF 전용 | | `parseXlsx(buffer, options?)` | XLSX 전용 | | `parseXls(buffer, options?)` | XLS (Excel 97~2003, BIFF8) 전용 | | `parseDocx(buffer, options?)` | DOCX 전용 | | `parseHwpml(buffer, options?)` | HWPML (XML 기반 HWP) 전용 | | `parseImage(buffer, options?)` | 이미지(PNG/JPG/WebP) 전용 — 내장 OCR 상시 적용 (v4.2.1) | | `detectFormat(buffer)` | 동기 매직 바이트 감지 — 하위 호환을 위해 ZIP은 `hwpx`, OLE2는 `hwp` 반환 | | `await detectZipFormat(buffer)` | ZIP 내부 구조로 `hwpx`, `xlsx`, `docx`, `pptx`, `unknown` 구분 | | `detectOle2Format(buffer)` | OLE2 내부 스트림으로 `hwp`, `xls`, `unknown` 구분 | PPTX는 감지만 지원합니다. `parse()`는 PPTX 입력에 `success: false`, `fileType: "pptx"`, `code: "UNSUPPORTED_FORMAT"`을 반환합니다. ZIP을 구분해 라우팅하는 래퍼/API는 `detectFormat()` 결과가 `hwpx`일 때 `await detectZipFormat(buffer)`로 세분화하세요. ### 고급 함수 | 함수 | 설명 | |------|------| | `compare(bufferA, bufferB, options?)` | IR 레벨 문서 비교 | | `extractFormFields(blocks)` | IRBlock[]에서 양식 필드 인식 | | `extractFormSchema(blocks)` | 양식 필드 인식 + 타입/필수/빈값 추론 (v3.1) | | `fillForm(input, values, outputFormat?)` | 양식 템플릿에 값 채우기 — outputFormat: `"markdown"`(기본)/`"hwpx"`/`"hwpx-preserve"`, 반환 `{ output, format, fill }` | | `fillFormFields(blocks, values)` | IRBlock[] 기반 필드 값 교체 | | `fillHwpx(buffer, values)` | HWPX XML 직접 조작 (원본 서식 보존) | | `extractClickHereFields(buffer)` | HWPX 누름틀(CLICK_HERE) 필드 조사 — 이름·안내문 목록 (v4.3) | | `resolveBuiltinTemplate(name)` / `readBuiltinTemplate(t)` | 내장 표준 기안문 서식 조회·로드 (`gian`/`gian-simple`, v4.3) | | `patchHwpx(original, editedMarkdown, options?)` | 편집 마크다운 → 원본 HWPX 서식 보존 in-place 패치 (v3.0) | | `patchHwp(original, editedMarkdown, options?)` | 편집 마크다운 → 원본 HWP 5.x 바이너리 서식 보존 패치 (v3.0.1) | | `openHwpxDocument(bytes, options?)` | 에디터용 블록 단위 증분 패치 세션 `HwpxSession` (v3.1) | | `patchHwpxBlocks(bytes, edits, options?)` | 세션 없이 블록 편집 1회 패치 (v3.1) | | `markdownToHwpx(markdown, options?)` | Markdown → HWPX 역변환 (테마·서식 프로필·페이지 옵션 지원) | | `hwpxToProfile(buffer)` | 참조 HWPX → 표 서식 프로필 JSON — `markdownToHwpx(md, { profile })` 로 재현 (v3.18) | | `markdownToPdf(markdown, options?)` | Markdown → PDF 생성 (Print Renderer — `puppeteer-core` 별도 설치 필요) | | `blocksToPdf(blocks, options?)` | IRBlock[] → PDF 생성 (동일하게 `puppeteer-core` 필요) | | `renderHtml(blocks, options?)` | IRBlock[] → 인쇄용 HTML (puppeteer 불필요) | | `renderHwpxToSvg(buffer, options?)` | HWPX → 레이아웃 보존 SVG — 다페이지·형광펜·도형, 캐시 없으면 `reflow` (v3.10~15) | | `renderDocument(입력, { format, pages?, … })` | HWPX·HWP(5.x) → 페이지별 svg/png/jpeg·문서 html/pdf 자산 + `RenderScene`(페이지 로컬 pt bbox·결정적 region id) (v4.13, HWP v4.13.1) | | `extractRenderedRegions(입력, { types?, pages?, … })` | 표·이미지·문단·도형 region 을 페이지 이미지에서 실배율 crop (v4.13) | | `extractTables(입력, { policy?, … })` | 표 분류(의미표/조직도류/불확실) + 렌더 region 조인 + 정책별 crop (v4.13, HWP v4.13.1) | | `placeSealHwpx(buffer, seals)` | 도장/서명 이미지를 앵커 문구 위에 부유 배치 (v3.16) | | `validateHwpx(buffer)` | HWPX 구조 검증 — ZIP·mimetype·필수 파트·XML 웰폼드 (v3.16) | | `lintGongmunText(text, { document? })` | 공문서 표기법 검수 19룰 + AI 슬롭 2룰 — 텍스트/마크다운 입력 (v4.0.1, v4.12.1 보강). `document: true` 면 붙임/"끝." 문서 단위 검사 포함 | | `redactMarkdown(text, options?)` / `redactText(...)` | 개인정보 탐지 + 마스킹 (기본 룰: 주민·외국인등록번호·전화·이메일·카드·계좌·사업자등록번호·여권·운전면허, opt-in: 법인등록번호·IP — 텍스트 단위, 파일 단위 마스킹은 CLI `redact`/MCP `redact_document`, v4.1) | | `blocksToChunks(blocks, options?)` | RAG용 구조 청크 — 헤딩·개조식 위계 breadcrumb + 표 독립 청크 (v4.1) | | `blocksToMarkdown(blocks)` | IRBlock[] → Markdown 문자열 | | `blocksToPages(blocks)` | IRBlock[] → `[{ pageNumber, markdown }]` 페이지별 마크다운 (v4.8) | ### 타입 ```typescript import type { ParseResult, ParseSuccess, ParseFailure, FileType, IRBlock, IRBlockType, IRTable, IRCell, CellContext, DocumentMetadata, ParseOptions, ErrorCode, OutlineItem, DiffResult, BlockDiff, CellDiff, DiffChangeType, FormField, FormResult, FormFieldType, FormFieldSchema, FormSchemaResult, FillResult, HwpxFillResult, FillOutputFormat, FillFormOutput, ClickHereField, BuiltinTemplate, PatchOptions, PatchResult, PatchSkip, HwpxTheme, MarkdownToHwpxOptions, PageOptions, PrintPreset, PrintOptions, PageMargin, RenderSvgOptions, RenderSvgResult, SealOp, SealPlacement, PlaceSealResult, ValidateResult, ValidateIssue, RedactRule, RedactOptions, RedactHit, RedactTextResult, DocChunk, ChunkOptions, GongmunLintFinding, OcrProvider, WatchOptions, } from "kordoc" ``` ## 지원 포맷 | 포맷 | 엔진 | 특징 | |------|------|------| | **HWPX** (한컴 2020+) | ZIP + XML DOM | 매니페스트, 중첩 테이블, 병합 셀, 손상 ZIP 복구, 조판 캐시 기반 실제 페이지 경계, 열기 암호 | | **HWP 5.x** (한컴 레거시) | OLE2 + CFB | 배포용 복호화, 열기 암호, 손상 CFB 복구, 각주/하이퍼링크, 21종 제어문자, 이미지 추출, 실제 페이지 경계 | | **HWP 3.x** (1996~2002) | 단일 binary | 상용조합형→유니코드, 5,893자 한자/기호 lookup, nested paragraph 추출, 아래아(옛한글), 열기 암호 | | **HWPML 2.x** (XML 기반 HWP) | XML DOM | HeadingType 기반 헤딩 감지, 병합 셀, DoS 방어 | | **PDF** | pdfjs-dist | 선 기반 테이블, XY-Cut 읽기 순서, 2단 지면, 헤딩 감지, OCR, 밑줄·링크, 이미지 추출, 텍스트 품질 신호 | | **XLSX** (Excel) | ZIP + XML DOM | 공유 문자열, 병합 셀, 다중 시트, 수식 표시, 날짜 셀 ISO 변환 | | **XLS** (Excel 97~2003) | OLE2 + BIFF8 | Workbook 스트림, SST 공유 문자열, 셀/시트 추출 | | **DOCX** (Word) | ZIP + XML DOM | 스타일 heading, 번호 매기기, 각주, 하이퍼링크, 이미지 추출 | | **이미지** (PNG/JPG/WebP) | sharp + 내장 OCR | 스크린샷·스캔 이미지 직접 입력, 래스터 괘선 감지로 표 복원 | ## 보안 프로덕션급 보안 강화: ZIP bomb 방지, XXE/Billion Laughs 방지, 압축 폭탄 방지, 경로 순회 차단, MCP 에러 정제, 파일 크기 제한(500MB). 자세한 내용은 [SECURITY.md](./SECURITY.md) 참조. **폐쇄망(내부망) 배포** — `KORDOC_OFFLINE=1` 로 모든 아웃바운드 통신(OCR 모델 다운로드·watch webhook)을 차단하고, `KORDOC_ROOT=<디렉토리>` 로 MCP 서버의 파일 접근을 해당 디렉토리 하위로 제한합니다(둘 다 opt-in). 절차·근거는 [docs/offline-deployment.md](docs/offline-deployment.md) 참조. (v4.7.2) ## 만든 사람 대한민국 지방공무원. 광진구청에서 7년간 HWP 파일과 싸우다가 이걸 만들었습니다. 5개 공공 프로젝트에서 수천 건의 실제 관공서 문서를 파싱하며 검증했습니다. ## 라이선스 [MIT](./LICENSE) 이 프로젝트는 아래 오픈소스를 포함합니다: - **rhwp** (MIT, edwardkim) — HWP5 배포용 복호화 및 lenient CFB 파싱 알고리즘, `templates/` 의 기안문 서식 - **claw-hwp** (MIT, DoHyun468) — OOXML chartSpace 조립, 도장 부유 배치 메트릭, secure-fill 포맷엔진, validate 검사셋 - **OpenDataLoader PDF** (Apache 2.0, Hancom Inc.) — PDF 테이블 감지 알고리즘 - **hml-equation-parser** (Apache 2.0, Open Bapul) — HML 수식 파싱 - **PaddleOCR** (Apache 2.0, PaddlePaddle) — 텍스트 OCR 엔진 파생 (PP-OCRv5 korean) - **Pix2Text** (MIT, breezedeus) — 수식 OCR(MFD/MFR) 알고리즘 포팅. 모델은 런타임 다운로드이며 재배포하지 않습니다 — MFD 가중치의 기반인 Ultralytics YOLOv8 은 AGPL-3.0 이므로, 수식 OCR 에 의존하는 상용·비공개 제품은 해당 조건을 별도 확인하세요 - **cfb** (Apache 2.0, SheetJS) — HWP5 OLE2 컨테이너 파싱 - **pdfjs-dist** (Apache 2.0, Mozilla) — PDF 텍스트 추출 - **JSZip** (MIT, Stuart Knightley 외) — ZIP 기반 포맷 파싱 전체 고지는 [NOTICE](./NOTICE), 라이선스 전문은 `THIRD_PARTY/` 를 참조하세요. 둘 다 npm 배포 패키지에 함께 포함됩니다.