kordoc 4.14.0 → 4.14.2
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 +18 -2
- package/dist/{-SLX6IB6Y.js → -AQKXLFIM.js} +10 -10
- package/dist/{chunk-WAPKUYGP.cjs → chunk-247ANM72.cjs} +11 -11
- package/dist/chunk-247ANM72.cjs.map +1 -0
- package/dist/{chunk-EOTAPX2M.js → chunk-3DUADAY2.js} +3 -3
- package/dist/{chunk-B7MOYHVR.cjs → chunk-422427XJ.cjs} +6 -6
- package/dist/chunk-422427XJ.cjs.map +1 -0
- package/dist/{chunk-HG5LXXCC.js → chunk-7IAQ4HOK.js} +1 -1
- package/dist/{chunk-XVIJLHCW.js.map → chunk-7IAQ4HOK.js.map} +1 -1
- package/dist/{chunk-JIQWI7S2.js → chunk-A7QC2ZVP.js} +3 -3
- package/dist/{chunk-HCHA3Y2T.js → chunk-C7FQBSON.js} +2 -2
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-7VUHZFGQ.js → chunk-DOGPOY4B.js} +2 -2
- package/dist/{chunk-6T6MB5ON.js → chunk-EDNJLUSE.js} +2 -2
- package/dist/{chunk-EMQZX5QQ.js → chunk-EISO3POT.js} +301 -124
- package/dist/chunk-EISO3POT.js.map +1 -0
- package/dist/{chunk-LCGAO5LF.js → chunk-EP7KOI2V.js} +3 -3
- package/dist/{chunk-WRIHDGGY.cjs → chunk-EQZI77PP.cjs} +3 -3
- package/dist/chunk-EQZI77PP.cjs.map +1 -0
- package/dist/{chunk-XVIJLHCW.js → chunk-FOJZNMMK.js} +1 -1
- package/dist/{chunk-HG5LXXCC.js.map → chunk-FOJZNMMK.js.map} +1 -1
- package/dist/{chunk-PLXNW3J4.js → chunk-GDW4YP7K.js} +2 -2
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-ANKDK5DF.cjs → chunk-HR2XNERB.cjs} +2 -2
- package/dist/chunk-HR2XNERB.cjs.map +1 -0
- package/dist/{chunk-3U3PJGVO.js → chunk-ILU76UF3.js} +13 -2
- package/dist/chunk-ILU76UF3.js.map +1 -0
- package/dist/{chunk-J3SM7VLM.js → chunk-JQEFP45L.js} +2 -2
- package/dist/{chunk-M5NRJMA4.js → chunk-KVWV4ULP.js} +3 -3
- package/dist/{chunk-COUGOFT3.cjs → chunk-L7DMSMAG.cjs} +1 -1
- package/dist/chunk-L7DMSMAG.cjs.map +1 -0
- package/dist/{chunk-GMX6EKCY.js → chunk-NS55SM7A.js} +2 -2
- package/dist/{chunk-XH34WJKB.js → chunk-QC5T6D4J.js} +2 -2
- package/dist/{chunk-STLNL53H.cjs → chunk-QOMNEWCQ.cjs} +4 -4
- package/dist/chunk-QOMNEWCQ.cjs.map +1 -0
- package/dist/{chunk-CDQJKMZ5.js → chunk-TNCKOL2O.js} +2 -2
- package/dist/{chunk-HH7T6SMB.js → chunk-TSFS5VKD.js} +3072 -1721
- package/dist/chunk-TSFS5VKD.js.map +1 -0
- package/dist/{chunk-RCTWZYAM.js → chunk-UET462HB.js} +2 -2
- package/dist/{chunk-A2JDWBKG.js → chunk-VQ5W4MYO.js} +2 -2
- package/dist/{chunk-ZWTEE63A.js → chunk-ZWD734EY.js} +2 -2
- package/dist/{chunk-UBNJXMYX.js → chunk-ZWOFQRIB.js} +14 -6
- package/dist/chunk-ZWOFQRIB.js.map +1 -0
- package/dist/chunks-SX77P5CV.js +10 -0
- package/dist/cli.js +1066 -1038
- package/dist/cli.js.map +1 -1
- package/dist/{formula-VSZIJZXP.js → formula-5S7WWXGH.js} +4 -4
- package/dist/{formula-VYDTA27M.js → formula-JGFTXWYT.js} +3 -3
- package/dist/{formula-TAYYDV73.cjs → formula-PJJ6S3Z2.cjs} +9 -9
- package/dist/formula-PJJ6S3Z2.cjs.map +1 -0
- package/dist/{image-ocr-5WBAIBPQ.js → image-ocr-FLIL7MGN.js} +6 -6
- package/dist/{image-ocr-N6IBZJAK.js → image-ocr-WCAYXLOA.js} +8 -8
- package/dist/{image-ocr-ZX4W2RBS.cjs → image-ocr-ZTYAGV3W.cjs} +12 -12
- package/dist/image-ocr-ZTYAGV3W.cjs.map +1 -0
- package/dist/index.cjs +3010 -1465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +2547 -1002
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +973 -932
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-5CBFVIXA.js → model-bundle-FSPZZ2EM.js} +5 -5
- package/dist/{models-L74RBKK3.js → models-CJPAQK5R.js} +5 -5
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-66NMJUOG.js → parser-A4TMPJAM.js} +7 -7
- package/dist/{parser-BK66Y5JD.js → parser-SCUTZAIJ.js} +7 -7
- package/dist/{parser-WM2DMVLY.cjs → parser-VCXE4I5A.cjs} +27 -27
- package/dist/parser-VCXE4I5A.cjs.map +1 -0
- package/dist/pdf-ocr-76SAUXMZ.js +13 -0
- package/dist/pdf-ocr-CPU55CVF.js +16 -0
- package/dist/pdf-ocr-MBZZ57LD.cjs +14 -0
- package/dist/pdf-ocr-MBZZ57LD.cjs.map +1 -0
- package/dist/{profile-io-JZ3FDHDK.js → profile-io-LBM263K7.js} +3 -3
- package/dist/{rasterize-33WOOVSM.js → rasterize-46RG4ZF6.js} +3 -3
- package/dist/{render-MLN4ZLVD.js → render-NGP5T24S.js} +7 -7
- package/dist/seal-RGUPOLXD.js +10 -0
- package/dist/{setup-G6AEN4J7.js → setup-AU4OCHNH.js} +3 -3
- package/dist/visual-NZLYIYEM.js +19 -0
- package/dist/{watch-OY6XKGC5.js → watch-MKPUCPXM.js} +11 -11
- package/package.json +2 -2
- package/dist/chunk-3U3PJGVO.js.map +0 -1
- package/dist/chunk-ANKDK5DF.cjs.map +0 -1
- package/dist/chunk-B7MOYHVR.cjs.map +0 -1
- package/dist/chunk-COUGOFT3.cjs.map +0 -1
- package/dist/chunk-EMQZX5QQ.js.map +0 -1
- package/dist/chunk-HH7T6SMB.js.map +0 -1
- package/dist/chunk-STLNL53H.cjs.map +0 -1
- package/dist/chunk-UBNJXMYX.js.map +0 -1
- package/dist/chunk-WAPKUYGP.cjs.map +0 -1
- package/dist/chunk-WRIHDGGY.cjs.map +0 -1
- package/dist/chunks-PEHRXW2P.js +0 -10
- package/dist/formula-TAYYDV73.cjs.map +0 -1
- package/dist/image-ocr-ZX4W2RBS.cjs.map +0 -1
- package/dist/parser-WM2DMVLY.cjs.map +0 -1
- package/dist/pdf-ocr-322MBLDK.js +0 -16
- package/dist/pdf-ocr-A4UBXLM2.js +0 -13
- package/dist/pdf-ocr-G4TBDUYL.cjs +0 -14
- package/dist/pdf-ocr-G4TBDUYL.cjs.map +0 -1
- package/dist/seal-JQWSNHRG.js +0 -10
- package/dist/visual-VZ7QGAUC.js +0 -19
- /package/dist/{-SLX6IB6Y.js.map → -AQKXLFIM.js.map} +0 -0
- /package/dist/{chunk-EOTAPX2M.js.map → chunk-3DUADAY2.js.map} +0 -0
- /package/dist/{chunk-JIQWI7S2.js.map → chunk-A7QC2ZVP.js.map} +0 -0
- /package/dist/{chunk-HCHA3Y2T.js.map → chunk-C7FQBSON.js.map} +0 -0
- /package/dist/{chunk-7VUHZFGQ.js.map → chunk-DOGPOY4B.js.map} +0 -0
- /package/dist/{chunk-6T6MB5ON.js.map → chunk-EDNJLUSE.js.map} +0 -0
- /package/dist/{chunk-LCGAO5LF.js.map → chunk-EP7KOI2V.js.map} +0 -0
- /package/dist/{chunk-PLXNW3J4.js.map → chunk-GDW4YP7K.js.map} +0 -0
- /package/dist/{chunk-J3SM7VLM.js.map → chunk-JQEFP45L.js.map} +0 -0
- /package/dist/{chunk-M5NRJMA4.js.map → chunk-KVWV4ULP.js.map} +0 -0
- /package/dist/{chunk-GMX6EKCY.js.map → chunk-NS55SM7A.js.map} +0 -0
- /package/dist/{chunk-XH34WJKB.js.map → chunk-QC5T6D4J.js.map} +0 -0
- /package/dist/{chunk-CDQJKMZ5.js.map → chunk-TNCKOL2O.js.map} +0 -0
- /package/dist/{chunk-RCTWZYAM.js.map → chunk-UET462HB.js.map} +0 -0
- /package/dist/{chunk-A2JDWBKG.js.map → chunk-VQ5W4MYO.js.map} +0 -0
- /package/dist/{chunk-ZWTEE63A.js.map → chunk-ZWD734EY.js.map} +0 -0
- /package/dist/{chunks-PEHRXW2P.js.map → chunks-SX77P5CV.js.map} +0 -0
- /package/dist/{formula-VSZIJZXP.js.map → formula-5S7WWXGH.js.map} +0 -0
- /package/dist/{formula-VYDTA27M.js.map → formula-JGFTXWYT.js.map} +0 -0
- /package/dist/{image-ocr-5WBAIBPQ.js.map → image-ocr-FLIL7MGN.js.map} +0 -0
- /package/dist/{image-ocr-N6IBZJAK.js.map → image-ocr-WCAYXLOA.js.map} +0 -0
- /package/dist/{model-bundle-5CBFVIXA.js.map → model-bundle-FSPZZ2EM.js.map} +0 -0
- /package/dist/{models-L74RBKK3.js.map → models-CJPAQK5R.js.map} +0 -0
- /package/dist/{parser-66NMJUOG.js.map → parser-A4TMPJAM.js.map} +0 -0
- /package/dist/{parser-BK66Y5JD.js.map → parser-SCUTZAIJ.js.map} +0 -0
- /package/dist/{pdf-ocr-322MBLDK.js.map → pdf-ocr-76SAUXMZ.js.map} +0 -0
- /package/dist/{pdf-ocr-A4UBXLM2.js.map → pdf-ocr-CPU55CVF.js.map} +0 -0
- /package/dist/{profile-io-JZ3FDHDK.js.map → profile-io-LBM263K7.js.map} +0 -0
- /package/dist/{rasterize-33WOOVSM.js.map → rasterize-46RG4ZF6.js.map} +0 -0
- /package/dist/{render-MLN4ZLVD.js.map → render-NGP5T24S.js.map} +0 -0
- /package/dist/{seal-JQWSNHRG.js.map → seal-RGUPOLXD.js.map} +0 -0
- /package/dist/{setup-G6AEN4J7.js.map → setup-AU4OCHNH.js.map} +0 -0
- /package/dist/{visual-VZ7QGAUC.js.map → visual-NZLYIYEM.js.map} +0 -0
- /package/dist/{watch-OY6XKGC5.js.map → watch-MKPUCPXM.js.map} +0 -0
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
assertWithinRoot,
|
|
4
4
|
getAccessRoot,
|
|
5
5
|
isOfflineMode
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GDW4YP7K.js";
|
|
7
7
|
import {
|
|
8
8
|
APPROVAL_MAX,
|
|
9
9
|
BODY_FONTS,
|
|
@@ -42,40 +42,45 @@ import {
|
|
|
42
42
|
resolveBuiltinTemplate,
|
|
43
43
|
unknownFontWarnings,
|
|
44
44
|
usesGaejosikMunche
|
|
45
|
-
} from "./chunk-
|
|
46
|
-
import "./chunk-
|
|
45
|
+
} from "./chunk-EISO3POT.js";
|
|
46
|
+
import "./chunk-ZWOFQRIB.js";
|
|
47
47
|
import "./chunk-DZIXKL7E.js";
|
|
48
|
-
import "./chunk-
|
|
48
|
+
import "./chunk-EDNJLUSE.js";
|
|
49
49
|
import {
|
|
50
50
|
detectFormat,
|
|
51
51
|
detectOle2Format,
|
|
52
52
|
detectZipFormat,
|
|
53
53
|
extractHwp5MetadataOnly
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-TSFS5VKD.js";
|
|
55
55
|
import "./chunk-7FCNOKOR.js";
|
|
56
|
-
import "./chunk-
|
|
56
|
+
import "./chunk-7IAQ4HOK.js";
|
|
57
57
|
import "./chunk-MOL7MDBG.js";
|
|
58
|
-
import "./chunk-
|
|
58
|
+
import "./chunk-ILU76UF3.js";
|
|
59
59
|
import {
|
|
60
60
|
blocksToMarkdown
|
|
61
|
-
} from "./chunk-
|
|
62
|
-
import "./chunk-
|
|
61
|
+
} from "./chunk-QC5T6D4J.js";
|
|
62
|
+
import "./chunk-C7FQBSON.js";
|
|
63
63
|
import {
|
|
64
64
|
KordocError,
|
|
65
65
|
VERSION,
|
|
66
66
|
classifyError,
|
|
67
67
|
sanitizeError,
|
|
68
68
|
toArrayBuffer
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-UET462HB.js";
|
|
70
70
|
|
|
71
71
|
// src/mcp.ts
|
|
72
72
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
73
73
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
74
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
75
|
+
import { pathToFileURL } from "url";
|
|
76
|
+
|
|
77
|
+
// src/mcp/tools-parse.ts
|
|
74
78
|
import { z } from "zod";
|
|
79
|
+
|
|
80
|
+
// src/mcp/shared.ts
|
|
75
81
|
import { realpathSync, openSync, readSync, closeSync, existsSync } from "fs";
|
|
76
|
-
import { readFile,
|
|
77
|
-
import {
|
|
78
|
-
import { resolve, isAbsolute, extname, dirname, basename, join } from "path";
|
|
82
|
+
import { readFile, stat } from "fs/promises";
|
|
83
|
+
import { resolve, isAbsolute, extname, dirname, basename } from "path";
|
|
79
84
|
var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".hwp", ".hwpx", ".hml", ".pdf", ".xls", ".xlsx", ".docx"]);
|
|
80
85
|
var PARSE_EXTENSIONS = /* @__PURE__ */ new Set([...ALLOWED_EXTENSIONS, ".png", ".jpg", ".jpeg", ".webp"]);
|
|
81
86
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".bmp"]);
|
|
@@ -173,338 +178,340 @@ function detectFormatFromHeader(resolved) {
|
|
|
173
178
|
closeSync(fd);
|
|
174
179
|
}
|
|
175
180
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
parts.push(`
|
|
181
|
+
|
|
182
|
+
// src/mcp/tools-parse.ts
|
|
183
|
+
function registerParseTools(server2) {
|
|
184
|
+
server2.tool(
|
|
185
|
+
"parse_document",
|
|
186
|
+
"\uD55C\uAD6D \uBB38\uC11C \uD30C\uC77C(HWP, HWPX, PDF, XLSX, DOCX)\uACFC \uC774\uBBF8\uC9C0(PNG/JPG/WebP)\uB97C \uB9C8\uD06C\uB2E4\uC6B4\uC73C\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. \uD30C\uC77C \uACBD\uB85C\uB97C \uC785\uB825\uD558\uBA74 \uD3EC\uB9F7\uC744 \uC790\uB3D9 \uAC10\uC9C0\uD558\uC5EC \uD14D\uC2A4\uD2B8\uB97C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uC774\uBBF8\uC9C0\uB294 OCR(\uB0B4\uC7A5 PP-OCRv5)\uC774 \uC790\uB3D9 \uC801\uC6A9\uB418\uACE0 \uD45C \uAD18\uC120\uB3C4 \uBCF5\uC6D0\uB429\uB2C8\uB2E4.",
|
|
187
|
+
{
|
|
188
|
+
file_path: z.string().min(1).describe("\uD30C\uC2F1\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX, PNG/JPG/WebP)"),
|
|
189
|
+
ocr: z.union([z.boolean(), z.literal("force")]).optional().describe('\uC2A4\uCE94/\uC774\uBBF8\uC9C0 PDF \uD14D\uC2A4\uD2B8 OCR (\uB0B4\uC7A5 PP-OCRv5 korean, \uCCAB \uC0AC\uC6A9 \uC2DC ~18MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC). true=\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC5C6\uAC70\uB098 \uAE68\uC9C4 \uD398\uC774\uC9C0\uB9CC \uC778\uC2DD\uD558\uACE0 \uC815\uC0C1 \uD398\uC774\uC9C0\uB294 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4. "force"=\uD14D\uC2A4\uD2B8\uCE35\uC774 \uC788\uC5B4\uB3C4 \uBB34\uC2DC\uD558\uACE0 \uC804 \uD398\uC774\uC9C0 \uAC15\uC81C \uC7AC\uC778\uC2DD. parse \uACB0\uACFC\uC5D0 NEEDS_OCR \uACBD\uACE0\uAC00 \uC788\uC73C\uBA74 \uC774 \uC635\uC158\uC73C\uB85C \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694'),
|
|
190
|
+
remove_header_footer: z.boolean().optional().describe("PDF \uBA38\uB9AC\uAE00/\uBC14\uB2E5\uAE00 \uC790\uB3D9 \uC81C\uAC70 (\uAE30\uBCF8 true \u2014 false\uB85C \uB044\uAE30, CLI --no-header-footer \uB300\uC751)"),
|
|
191
|
+
formula_ocr: z.boolean().optional().describe("PDF \uC218\uC2DD OCR \uD65C\uC131\uD654 (MFD+MFR ONNX, \uCCAB \uC0AC\uC6A9 \uC2DC \uBAA8\uB378 ~155MB \uC790\uB3D9 \uB2E4\uC6B4\uB85C\uB4DC, CLI --formula-ocr \uB300\uC751)"),
|
|
192
|
+
dedupe_running_headers: z.boolean().optional().describe("HWP5 \uB808\uC774\uC544\uC6C3 \uD45C \uD398\uC774\uC9C0 \uBC18\uBCF5 \uB7EC\uB2DD \uD5E4\uB354 \uC911\uBCF5 \uC81C\uAC70 (\uAE30\uBCF8 off \u2014 \uBD99\uC784\uBCC4 \uC7AC\uBC88\uD638 \uC624\uC0AD\uC81C \uC8FC\uC758, CLI --dedupe-headers \uB300\uC751)"),
|
|
193
|
+
keep_trailing_empty_cols: z.boolean().optional().describe("\uD45C \uC624\uB978\uCABD \uB05D \uBE48 \uC5F4(\uC11C\uC2DD \uC785\uB825\uB780) \uBCF4\uC874 (#47, \uAE30\uBCF8 off: \uD6C4\uD589 \uBE48 \uC5F4 \uD2B8\uB9BC, CLI --keep-empty-cols \uB300\uC751)"),
|
|
194
|
+
keep_empty_paragraphs: z.boolean().optional().describe("\uBE48 \uBB38\uB2E8 \uBCF4\uC874 \u2014 \uBCF8\uBB38\uC740 \uBE48 paragraph \uBE14\uB85D, \uD45C \uC140\uC740 \uBE48 \uC904 (#57, \uAE30\uBCF8 off, CLI --keep-empty-paragraphs \uB300\uC751)"),
|
|
195
|
+
password: z.string().optional().describe("\uC554\uD638\uB85C \uBCF4\uD638\uB41C \uBB38\uC11C\uC758 \uC5F4\uAE30 \uC554\uD638 (#59, HWPX\xB7HWP3\xB7HWP5 \uC9C0\uC6D0. \uD30C\uC2F1\uC774 ENCRYPTED\uB85C \uC2E4\uD328\uD558\uBA74 \uC774 \uC635\uC158\uC73C\uB85C \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694. \uD55C\uCEF4 DRM \uBCF4\uD638 \uBB38\uC11C\uB294 \uD574\uB2F9 \uC5C6\uC74C)"),
|
|
196
|
+
tables: z.boolean().optional().describe("PDF \uD45C \uAC10\uC9C0 (\uAE30\uBCF8 true \u2014 false\uB85C \uB044\uAE30, CLI --no-tables \uB300\uC751). \uD14C\uB450\uB9AC \uBC15\uC2A4\uB97C \uD45C\uB85C \uC624\uC778\uD574 \uC77D\uAE30 \uC21C\uC11C\uAC00 \uB4A4\uC9D1\uD788\uB294 \uBB38\uC11C(2\uB2E8 \uC2DC\uD5D8\uC9C0 \uB4F1)\uC5D0\uC11C \uC790\uC5F0 \uC77D\uAE30\uC21C \uD14D\uC2A4\uD2B8\uB9CC \uBF51\uC2B5\uB2C8\uB2E4 (#64)")
|
|
197
|
+
},
|
|
198
|
+
async ({ file_path, ocr, remove_header_footer, formula_ocr, dedupe_running_headers, keep_trailing_empty_cols, keep_empty_paragraphs, password, tables }) => {
|
|
199
|
+
try {
|
|
200
|
+
const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
201
|
+
const format = detectFormat(buffer);
|
|
202
|
+
if (format === "unknown") {
|
|
203
|
+
return {
|
|
204
|
+
content: [{ type: "text", text: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4: ${file_path}` }],
|
|
205
|
+
isError: true
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const result = await parse(buffer, {
|
|
209
|
+
filePath: resolved,
|
|
210
|
+
...ocr !== void 0 ? { ocr } : {},
|
|
211
|
+
...remove_header_footer !== void 0 ? { removeHeaderFooter: remove_header_footer } : {},
|
|
212
|
+
...formula_ocr ? { formulaOcr: true } : {},
|
|
213
|
+
...dedupe_running_headers ? { dedupeRunningHeaders: true } : {},
|
|
214
|
+
...keep_trailing_empty_cols ? { keepTrailingEmptyCols: true } : {},
|
|
215
|
+
...keep_empty_paragraphs ? { keepEmptyParagraphs: true } : {},
|
|
216
|
+
...password ? { password } : {},
|
|
217
|
+
...tables === false ? { tables: false } : {}
|
|
218
|
+
});
|
|
219
|
+
if (!result.success) {
|
|
220
|
+
return {
|
|
221
|
+
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328 (${result.fileType}): ${result.error}` }],
|
|
222
|
+
isError: true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const markdown = result.markdown;
|
|
226
|
+
const meta = [
|
|
227
|
+
`\uD3EC\uB9F7: ${result.fileType.toUpperCase()}`,
|
|
228
|
+
result.pageCount ? `\uD398\uC774\uC9C0: ${result.pageCount}` : null,
|
|
229
|
+
result.metadata?.title ? `\uC81C\uBAA9: ${result.metadata.title}` : null,
|
|
230
|
+
result.metadata?.author ? `\uC791\uC131\uC790: ${result.metadata.author}` : null,
|
|
231
|
+
result.isImageBased ? result.warnings?.some((w) => w.code === "OCR_APPLIED") ? "\uC774\uBBF8\uC9C0 \uAE30\uBC18 PDF (OCR \uC801\uC6A9)" : "\uC774\uBBF8\uC9C0 \uAE30\uBC18 PDF (\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uBD88\uAC00 \u2014 ocr: true \uB85C \uC7AC\uC2DC\uB3C4 \uAC00\uB2A5)" : null
|
|
232
|
+
].filter(Boolean).join(" | ");
|
|
233
|
+
const parts = [`[${meta}]`];
|
|
234
|
+
if (result.outline && result.outline.length > 0) {
|
|
235
|
+
const outlineText = result.outline.map((o) => `${" ".repeat(o.level - 1)}- ${o.text}`).join("\n");
|
|
236
|
+
parts.push(`
|
|
233
237
|
\u{1F4D1} \uBB38\uC11C \uAD6C\uC870:
|
|
234
238
|
${outlineText}`);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
+
}
|
|
240
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
241
|
+
const warnText = result.warnings.map((w) => `- [p${w.page || "?"}] ${w.message}`).join("\n");
|
|
242
|
+
parts.push(`
|
|
239
243
|
\u26A0\uFE0F \uACBD\uACE0:
|
|
240
244
|
${warnText}`);
|
|
241
|
-
|
|
242
|
-
|
|
245
|
+
}
|
|
246
|
+
parts.push(`
|
|
243
247
|
|
|
244
248
|
${markdown}`);
|
|
245
|
-
return {
|
|
246
|
-
content: [{ type: "text", text: capResponseText(parts.join("")) }]
|
|
247
|
-
};
|
|
248
|
-
} catch (err) {
|
|
249
|
-
return {
|
|
250
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
251
|
-
isError: true
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
);
|
|
256
|
-
server.tool(
|
|
257
|
-
"detect_format",
|
|
258
|
-
"\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, hwp3, hwpml, pdf, xls, xlsx, docx, unknown).",
|
|
259
|
-
{
|
|
260
|
-
file_path: z.string().min(1).describe("\uAC10\uC9C0\uD560 \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
261
|
-
},
|
|
262
|
-
async ({ file_path }) => {
|
|
263
|
-
try {
|
|
264
|
-
const resolved = safePath(file_path, PARSE_EXTENSIONS);
|
|
265
|
-
let format = detectFormatFromHeader(resolved);
|
|
266
|
-
if (format === "hwpx") {
|
|
267
|
-
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
268
|
-
format = await detectZipFormat(buffer);
|
|
269
|
-
} else if (format === "hwp") {
|
|
270
|
-
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
271
|
-
const ole2Format = detectOle2Format(buffer);
|
|
272
|
-
if (ole2Format !== "unknown") format = ole2Format;
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
content: [{ type: "text", text: `${file_path}: ${format}` }]
|
|
276
|
-
};
|
|
277
|
-
} catch (err) {
|
|
278
|
-
return {
|
|
279
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
280
|
-
isError: true
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
);
|
|
285
|
-
server.tool(
|
|
286
|
-
"parse_metadata",
|
|
287
|
-
"\uBB38\uC11C\uC758 \uBA54\uD0C0\uB370\uC774\uD130(\uC81C\uBAA9, \uC791\uC131\uC790, \uB0A0\uC9DC \uB4F1)\uB9CC \uBE60\uB974\uAC8C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uC804\uCCB4 \uD30C\uC2F1 \uC5C6\uC774 \uD5E4\uB354/\uB9E4\uB2C8\uD398\uC2A4\uD2B8\uB9CC \uC77D\uC2B5\uB2C8\uB2E4.",
|
|
288
|
-
{
|
|
289
|
-
file_path: z.string().min(1).describe("\uBA54\uD0C0\uB370\uC774\uD130\uB97C \uCD94\uCD9C\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
290
|
-
},
|
|
291
|
-
async ({ file_path }) => {
|
|
292
|
-
try {
|
|
293
|
-
const resolved = safePath(file_path, PARSE_EXTENSIONS);
|
|
294
|
-
const format = detectFormatFromHeader(resolved);
|
|
295
|
-
if (format === "unknown") {
|
|
296
249
|
return {
|
|
297
|
-
content: [{ type: "text", text:
|
|
250
|
+
content: [{ type: "text", text: capResponseText(parts.join("")) }]
|
|
251
|
+
};
|
|
252
|
+
} catch (err) {
|
|
253
|
+
return {
|
|
254
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
298
255
|
isError: true
|
|
299
256
|
};
|
|
300
257
|
}
|
|
301
|
-
const { buffer } = await readValidatedFile(file_path, MAX_METADATA_FILE_SIZE, PARSE_EXTENSIONS);
|
|
302
|
-
let metadata;
|
|
303
|
-
let effectiveFormat = format;
|
|
304
|
-
if (format === "hwpx") {
|
|
305
|
-
const zipFormat = await detectZipFormat(buffer);
|
|
306
|
-
if (zipFormat === "xlsx" || zipFormat === "docx") effectiveFormat = zipFormat;
|
|
307
|
-
} else if (format === "hwp") {
|
|
308
|
-
if (detectOle2Format(buffer) === "xls") effectiveFormat = "xls";
|
|
309
|
-
}
|
|
310
|
-
switch (effectiveFormat) {
|
|
311
|
-
case "hwp":
|
|
312
|
-
metadata = extractHwp5MetadataOnly(Buffer.from(buffer));
|
|
313
|
-
break;
|
|
314
|
-
case "hwpx":
|
|
315
|
-
metadata = await extractHwpxMetadataOnly(buffer);
|
|
316
|
-
break;
|
|
317
|
-
case "pdf":
|
|
318
|
-
try {
|
|
319
|
-
const { extractPdfMetadataOnly } = await import("./parser-BK66Y5JD.js");
|
|
320
|
-
metadata = await extractPdfMetadataOnly(buffer);
|
|
321
|
-
} catch {
|
|
322
|
-
metadata = void 0;
|
|
323
|
-
}
|
|
324
|
-
break;
|
|
325
|
-
case "hwp3":
|
|
326
|
-
case "hwpml":
|
|
327
|
-
case "xls":
|
|
328
|
-
case "xlsx":
|
|
329
|
-
case "docx": {
|
|
330
|
-
const result = await parse(buffer);
|
|
331
|
-
metadata = result.success ? result.metadata : void 0;
|
|
332
|
-
break;
|
|
333
|
-
}
|
|
334
|
-
default:
|
|
335
|
-
metadata = void 0;
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
return {
|
|
339
|
-
content: [{ type: "text", text: JSON.stringify({ format, ...metadata }, null, 2) }]
|
|
340
|
-
};
|
|
341
|
-
} catch (err) {
|
|
342
|
-
return {
|
|
343
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
344
|
-
isError: true
|
|
345
|
-
};
|
|
346
258
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
259
|
+
);
|
|
260
|
+
server2.tool(
|
|
261
|
+
"detect_format",
|
|
262
|
+
"\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uC640 \uCEE8\uD14C\uC774\uB108 \uB0B4\uBD80 \uAD6C\uC870\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, hwp3, hwpml, pdf, xls, xlsx, docx, pptx, image, unknown). PPTX\uB294 \uAC10\uC9C0\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4.",
|
|
263
|
+
{
|
|
264
|
+
file_path: z.string().min(1).describe("\uAC10\uC9C0\uD560 \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
265
|
+
},
|
|
266
|
+
async ({ file_path }) => {
|
|
267
|
+
try {
|
|
268
|
+
const resolved = safePath(file_path, PARSE_EXTENSIONS);
|
|
269
|
+
let format = detectFormatFromHeader(resolved);
|
|
270
|
+
if (format === "hwpx") {
|
|
271
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
272
|
+
format = await detectZipFormat(buffer);
|
|
273
|
+
} else if (format === "hwp") {
|
|
274
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
275
|
+
const ole2Format = detectOle2Format(buffer);
|
|
276
|
+
if (ole2Format !== "unknown") format = ole2Format;
|
|
277
|
+
}
|
|
362
278
|
return {
|
|
363
|
-
content: [{ type: "text", text:
|
|
364
|
-
isError: true
|
|
279
|
+
content: [{ type: "text", text: `${file_path}: ${format}` }]
|
|
365
280
|
};
|
|
366
|
-
}
|
|
367
|
-
const result = await parse(buffer, { pages, filePath: resolved });
|
|
368
|
-
if (!result.success) {
|
|
281
|
+
} catch (err) {
|
|
369
282
|
return {
|
|
370
|
-
content: [{ type: "text", text: `\
|
|
283
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
371
284
|
isError: true
|
|
372
285
|
};
|
|
373
286
|
}
|
|
374
|
-
const meta = [
|
|
375
|
-
`\uD3EC\uB9F7: ${result.fileType.toUpperCase()}`,
|
|
376
|
-
`\uBC94\uC704: ${pages}`,
|
|
377
|
-
result.pageCount ? `\uD398\uC774\uC9C0: ${result.pageCount}` : null,
|
|
378
|
-
result.metadata?.pageMode === "section" ? "\uAE30\uC900: \uC139\uC158 \uADFC\uC0AC" : null
|
|
379
|
-
].filter(Boolean).join(" | ");
|
|
380
|
-
return {
|
|
381
|
-
content: [{ type: "text", text: `[${meta}]
|
|
382
|
-
|
|
383
|
-
${result.markdown}` }]
|
|
384
|
-
};
|
|
385
|
-
} catch (err) {
|
|
386
|
-
return {
|
|
387
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
388
|
-
isError: true
|
|
389
|
-
};
|
|
390
287
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
288
|
+
);
|
|
289
|
+
server2.tool(
|
|
290
|
+
"parse_metadata",
|
|
291
|
+
"\uBB38\uC11C\uC758 \uBA54\uD0C0\uB370\uC774\uD130(\uC81C\uBAA9, \uC791\uC131\uC790, \uB0A0\uC9DC \uB4F1)\uB9CC \uBE60\uB974\uAC8C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uC804\uCCB4 \uD30C\uC2F1 \uC5C6\uC774 \uD5E4\uB354/\uB9E4\uB2C8\uD398\uC2A4\uD2B8\uB9CC \uC77D\uC2B5\uB2C8\uB2E4.",
|
|
292
|
+
{
|
|
293
|
+
file_path: z.string().min(1).describe("\uBA54\uD0C0\uB370\uC774\uD130\uB97C \uCD94\uCD9C\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
294
|
+
},
|
|
295
|
+
async ({ file_path }) => {
|
|
296
|
+
try {
|
|
297
|
+
const resolved = safePath(file_path, PARSE_EXTENSIONS);
|
|
298
|
+
const format = detectFormatFromHeader(resolved);
|
|
299
|
+
if (format === "unknown") {
|
|
300
|
+
return {
|
|
301
|
+
content: [{ type: "text", text: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4: ${file_path}` }],
|
|
302
|
+
isError: true
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const { buffer } = await readValidatedFile(file_path, MAX_METADATA_FILE_SIZE, PARSE_EXTENSIONS);
|
|
306
|
+
let metadata;
|
|
307
|
+
let effectiveFormat = format;
|
|
308
|
+
if (format === "hwpx") {
|
|
309
|
+
const zipFormat = await detectZipFormat(buffer);
|
|
310
|
+
if (zipFormat !== "unknown") effectiveFormat = zipFormat;
|
|
311
|
+
} else if (format === "hwp") {
|
|
312
|
+
if (detectOle2Format(buffer) === "xls") effectiveFormat = "xls";
|
|
313
|
+
}
|
|
314
|
+
switch (effectiveFormat) {
|
|
315
|
+
case "pptx":
|
|
316
|
+
throw new KordocError("PPTX \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4.");
|
|
317
|
+
case "hwp":
|
|
318
|
+
metadata = extractHwp5MetadataOnly(Buffer.from(buffer));
|
|
319
|
+
break;
|
|
320
|
+
case "hwpx":
|
|
321
|
+
metadata = await extractHwpxMetadataOnly(buffer);
|
|
322
|
+
break;
|
|
323
|
+
case "pdf":
|
|
324
|
+
try {
|
|
325
|
+
const { extractPdfMetadataOnly } = await import("./parser-SCUTZAIJ.js");
|
|
326
|
+
metadata = await extractPdfMetadataOnly(buffer);
|
|
327
|
+
} catch {
|
|
328
|
+
metadata = void 0;
|
|
329
|
+
}
|
|
330
|
+
break;
|
|
331
|
+
case "hwp3":
|
|
332
|
+
case "hwpml":
|
|
333
|
+
case "xls":
|
|
334
|
+
case "xlsx":
|
|
335
|
+
case "docx": {
|
|
336
|
+
const result = await parse(buffer);
|
|
337
|
+
metadata = result.success ? result.metadata : void 0;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
default:
|
|
341
|
+
metadata = void 0;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
405
344
|
return {
|
|
406
|
-
content: [{ type: "text", text:
|
|
407
|
-
isError: true
|
|
345
|
+
content: [{ type: "text", text: JSON.stringify({ format: effectiveFormat, ...metadata }, null, 2) }]
|
|
408
346
|
};
|
|
409
|
-
}
|
|
410
|
-
const result = await parse(buffer);
|
|
411
|
-
if (!result.success) {
|
|
347
|
+
} catch (err) {
|
|
412
348
|
return {
|
|
413
|
-
content: [{ type: "text", text: `\
|
|
349
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
414
350
|
isError: true
|
|
415
351
|
};
|
|
416
352
|
}
|
|
417
|
-
|
|
418
|
-
|
|
353
|
+
}
|
|
354
|
+
);
|
|
355
|
+
server2.tool(
|
|
356
|
+
"parse_pages",
|
|
357
|
+
"\uBB38\uC11C\uC758 \uD2B9\uC815 \uD398\uC774\uC9C0 \uBC94\uC704\uB9CC \uD30C\uC2F1\uD569\uB2C8\uB2E4. PDF\uC640 \uD55C\uCEF4 \uC800\uC7A5\uBCF8 HWP/HWPX\uB294 \uC2E4\uC81C \uD398\uC774\uC9C0 \uAE30\uC900(metadata.pageMode=layout), \uC870\uD310 \uCE90\uC2DC\uAC00 \uC5C6\uB294 \uC0DD\uC131 \uD30C\uC77C\uC740 \uC139\uC158 \uB2E8\uC704 \uADFC\uC0AC(pageMode=section)\uC785\uB2C8\uB2E4.",
|
|
358
|
+
{
|
|
359
|
+
file_path: z.string().min(1).describe("\uD30C\uC2F1\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
360
|
+
pages: z.string().min(1).describe("\uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: '1-3', '1,3,5-7')")
|
|
361
|
+
},
|
|
362
|
+
async ({ file_path, pages }) => {
|
|
363
|
+
try {
|
|
364
|
+
const resolved = safePath(file_path, PARSE_EXTENSIONS);
|
|
365
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
366
|
+
const format = detectFormat(buffer);
|
|
367
|
+
if (format === "unknown") {
|
|
368
|
+
return {
|
|
369
|
+
content: [{ type: "text", text: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4: ${file_path}` }],
|
|
370
|
+
isError: true
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const result = await parse(buffer, { pages, filePath: resolved });
|
|
374
|
+
if (!result.success) {
|
|
375
|
+
return {
|
|
376
|
+
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328 (${result.fileType}): ${result.error}` }],
|
|
377
|
+
isError: true
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const meta = [
|
|
381
|
+
`\uD3EC\uB9F7: ${result.fileType.toUpperCase()}`,
|
|
382
|
+
`\uBC94\uC704: ${pages}`,
|
|
383
|
+
result.pageCount ? `\uD398\uC774\uC9C0: ${result.pageCount}` : null,
|
|
384
|
+
result.metadata?.pageMode === "section" ? "\uAE30\uC900: \uC139\uC158 \uADFC\uC0AC" : null
|
|
385
|
+
].filter(Boolean).join(" | ");
|
|
419
386
|
return {
|
|
420
|
-
content: [{ type: "text", text:
|
|
421
|
-
|
|
387
|
+
content: [{ type: "text", text: `[${meta}]
|
|
388
|
+
|
|
389
|
+
${result.markdown}` }]
|
|
422
390
|
};
|
|
423
|
-
}
|
|
424
|
-
if (table_index >= tableBlocks.length) {
|
|
391
|
+
} catch (err) {
|
|
425
392
|
return {
|
|
426
|
-
content: [{ type: "text", text: `\
|
|
393
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
427
394
|
isError: true
|
|
428
395
|
};
|
|
429
396
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
server2.tool(
|
|
400
|
+
"parse_table",
|
|
401
|
+
"\uBB38\uC11C\uC5D0\uC11C N\uBC88\uC9F8 \uD14C\uC774\uBE14\uB9CC \uCD94\uCD9C\uD569\uB2C8\uB2E4 (0-based index). \uD14C\uC774\uBE14\uC774 \uC5C6\uAC70\uB098 \uC778\uB371\uC2A4 \uBC94\uC704\uB97C \uCD08\uACFC\uD558\uBA74 \uC624\uB958\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.",
|
|
402
|
+
{
|
|
403
|
+
file_path: z.string().min(1).describe("\uD30C\uC2F1\uD560 \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
404
|
+
table_index: z.number().int().min(0).describe("\uCD94\uCD9C\uD560 \uD14C\uC774\uBE14 \uC778\uB371\uC2A4 (0\uBD80\uD130 \uC2DC\uC791)")
|
|
405
|
+
},
|
|
406
|
+
async ({ file_path, table_index }) => {
|
|
407
|
+
try {
|
|
408
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
409
|
+
const format = detectFormat(buffer);
|
|
410
|
+
if (format === "unknown") {
|
|
411
|
+
return {
|
|
412
|
+
content: [{ type: "text", text: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4: ${file_path}` }],
|
|
413
|
+
isError: true
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const result = await parse(buffer);
|
|
417
|
+
if (!result.success) {
|
|
418
|
+
return {
|
|
419
|
+
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328 (${result.fileType}): ${result.error}` }],
|
|
420
|
+
isError: true
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
const tableBlocks = result.blocks.filter((b) => b.type === "table" && b.table);
|
|
424
|
+
if (tableBlocks.length === 0) {
|
|
425
|
+
return {
|
|
426
|
+
content: [{ type: "text", text: `\uBB38\uC11C\uC5D0 \uD14C\uC774\uBE14\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.` }],
|
|
427
|
+
isError: true
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
if (table_index >= tableBlocks.length) {
|
|
431
|
+
return {
|
|
432
|
+
content: [{ type: "text", text: `\uD14C\uC774\uBE14 \uC778\uB371\uC2A4 \uCD08\uACFC: ${table_index} (\uCD1D ${tableBlocks.length}\uAC1C \uD14C\uC774\uBE14)` }],
|
|
433
|
+
isError: true
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const tableBlock = tableBlocks[table_index];
|
|
437
|
+
const tableMarkdown = blocksToMarkdown([tableBlock]);
|
|
438
|
+
return {
|
|
439
|
+
content: [{ type: "text", text: `[\uD14C\uC774\uBE14 #${table_index} / \uCD1D ${tableBlocks.length}\uAC1C]
|
|
434
440
|
|
|
435
441
|
${tableMarkdown}` }]
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
);
|
|
445
|
-
server.tool(
|
|
446
|
-
"compare_documents",
|
|
447
|
-
"\uB450 \uD55C\uAD6D \uBB38\uC11C \uD30C\uC77C\uC744 \uBE44\uAD50\uD558\uC5EC \uCD94\uAC00/\uC0AD\uC81C/\uBCC0\uACBD\uB41C \uBE14\uB85D\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4. \uC2E0\uAD6C\uB300\uC870\uD45C \uC0DD\uC131\uC5D0 \uD65C\uC6A9\uB429\uB2C8\uB2E4. \uD06C\uB85C\uC2A4 \uD3EC\uB9F7(HWP\u2194HWPX) \uBE44\uAD50 \uAC00\uB2A5.",
|
|
448
|
-
{
|
|
449
|
-
file_path_a: z.string().min(1).describe("\uBE44\uAD50 \uC6D0\uBCF8 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
450
|
-
file_path_b: z.string().min(1).describe("\uBE44\uAD50 \uB300\uC0C1 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
451
|
-
},
|
|
452
|
-
async ({ file_path_a, file_path_b }) => {
|
|
453
|
-
try {
|
|
454
|
-
const { buffer: bufA } = await readValidatedFile(file_path_a);
|
|
455
|
-
const { buffer: bufB } = await readValidatedFile(file_path_b);
|
|
456
|
-
const result = await compare(bufA, bufB);
|
|
457
|
-
const { stats, diffs } = result;
|
|
458
|
-
const lines = [
|
|
459
|
-
`## \uBB38\uC11C \uBE44\uAD50 \uACB0\uACFC`,
|
|
460
|
-
`\uCD94\uAC00: ${stats.added} | \uC0AD\uC81C: ${stats.removed} | \uBCC0\uACBD: ${stats.modified} | \uB3D9\uC77C: ${stats.unchanged}`,
|
|
461
|
-
""
|
|
462
|
-
];
|
|
463
|
-
for (const d of diffs) {
|
|
464
|
-
const prefix = d.type === "added" ? "+" : d.type === "removed" ? "-" : d.type === "modified" ? "~" : " ";
|
|
465
|
-
const text = d.after?.text || d.before?.text || (d.after?.table ? "[\uD14C\uC774\uBE14]" : d.before?.table ? "[\uD14C\uC774\uBE14]" : "");
|
|
466
|
-
const sim = d.similarity !== void 0 ? ` (${(d.similarity * 100).toFixed(0)}%)` : "";
|
|
467
|
-
lines.push(`${prefix} ${text.substring(0, 200)}${sim}`);
|
|
442
|
+
};
|
|
443
|
+
} catch (err) {
|
|
444
|
+
return {
|
|
445
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
446
|
+
isError: true
|
|
447
|
+
};
|
|
468
448
|
}
|
|
469
|
-
return {
|
|
470
|
-
content: [{ type: "text", text: lines.join("\n") }]
|
|
471
|
-
};
|
|
472
|
-
} catch (err) {
|
|
473
|
-
return {
|
|
474
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
475
|
-
isError: true
|
|
476
|
-
};
|
|
477
449
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
450
|
+
);
|
|
451
|
+
server2.tool(
|
|
452
|
+
"compare_documents",
|
|
453
|
+
"\uB450 \uD55C\uAD6D \uBB38\uC11C \uD30C\uC77C\uC744 \uBE44\uAD50\uD558\uC5EC \uCD94\uAC00/\uC0AD\uC81C/\uBCC0\uACBD\uB41C \uBE14\uB85D\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4. \uC2E0\uAD6C\uB300\uC870\uD45C \uC0DD\uC131\uC5D0 \uD65C\uC6A9\uB429\uB2C8\uB2E4. \uD06C\uB85C\uC2A4 \uD3EC\uB9F7(HWP\u2194HWPX) \uBE44\uAD50 \uAC00\uB2A5.",
|
|
454
|
+
{
|
|
455
|
+
file_path_a: z.string().min(1).describe("\uBE44\uAD50 \uC6D0\uBCF8 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
456
|
+
file_path_b: z.string().min(1).describe("\uBE44\uAD50 \uB300\uC0C1 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
457
|
+
},
|
|
458
|
+
async ({ file_path_a, file_path_b }) => {
|
|
459
|
+
try {
|
|
460
|
+
const { buffer: bufA } = await readValidatedFile(file_path_a);
|
|
461
|
+
const { buffer: bufB } = await readValidatedFile(file_path_b);
|
|
462
|
+
const result = await compare(bufA, bufB);
|
|
463
|
+
const { stats, diffs } = result;
|
|
464
|
+
const lines = [
|
|
465
|
+
`## \uBB38\uC11C \uBE44\uAD50 \uACB0\uACFC`,
|
|
466
|
+
`\uCD94\uAC00: ${stats.added} | \uC0AD\uC81C: ${stats.removed} | \uBCC0\uACBD: ${stats.modified} | \uB3D9\uC77C: ${stats.unchanged}`,
|
|
467
|
+
""
|
|
468
|
+
];
|
|
469
|
+
for (const d of diffs) {
|
|
470
|
+
const prefix = d.type === "added" ? "+" : d.type === "removed" ? "-" : d.type === "modified" ? "~" : " ";
|
|
471
|
+
const text = d.after?.text || d.before?.text || (d.after?.table ? "[\uD14C\uC774\uBE14]" : d.before?.table ? "[\uD14C\uC774\uBE14]" : "");
|
|
472
|
+
const sim = d.similarity !== void 0 ? ` (${(d.similarity * 100).toFixed(0)}%)` : "";
|
|
473
|
+
lines.push(`${prefix} ${text.substring(0, 200)}${sim}`);
|
|
474
|
+
}
|
|
491
475
|
return {
|
|
492
|
-
content: [{ type: "text", text:
|
|
476
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
477
|
+
};
|
|
478
|
+
} catch (err) {
|
|
479
|
+
return {
|
|
480
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
493
481
|
isError: true
|
|
494
482
|
};
|
|
495
483
|
}
|
|
496
|
-
const form = extractFormFields(result.blocks);
|
|
497
|
-
return {
|
|
498
|
-
content: [{ type: "text", text: JSON.stringify(form, null, 2) }]
|
|
499
|
-
};
|
|
500
|
-
} catch (err) {
|
|
501
|
-
return {
|
|
502
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
503
|
-
isError: true
|
|
504
|
-
};
|
|
505
484
|
}
|
|
506
|
-
|
|
507
|
-
|
|
485
|
+
);
|
|
486
|
+
server2.tool(
|
|
487
|
+
"parse_chunks",
|
|
488
|
+
"\uBB38\uC11C\uB97C RAG\uC6A9 \uAD6C\uC870 \uCCAD\uD06C JSON\uC73C\uB85C \uD30C\uC2F1\uD569\uB2C8\uB2E4. \uD5E4\uB529\xB7\uAC1C\uC870\uC2DD \uC704\uACC4(\u25A1\u25CB- / 1.\xB7\uAC00.\xB71))\uAC00 breadcrumb \uACBD\uB85C\uB85C \uBCF4\uC874\uB418\uACE0 \uD45C\uB294 \uB3C5\uB9BD \uCCAD\uD06C\uB85C \uB098\uC635\uB2C8\uB2E4 \u2014 \uC784\uBCA0\uB529\xB7\uC778\uB371\uC2F1 \uC804\uCC98\uB9AC\uC6A9. \uC790\uB974\uAE30(\uD1A0\uD070 \uC0C1\uD55C\xB7\uC624\uBC84\uB7A9)\uB294 \uC18C\uBE44\uC790 \uBAAB\uC785\uB2C8\uB2E4.",
|
|
489
|
+
{
|
|
490
|
+
file_path: z.string().min(1).describe("\uB300\uC0C1 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWP/HWPX/PDF/XLSX/DOCX)"),
|
|
491
|
+
granularity: z.enum(["section", "block"]).default("section").describe("section=\uAC19\uC740 breadcrumb \uC544\uB798 \uC5F0\uC18D \uD14D\uC2A4\uD2B8 \uBCD1\uD569(\uAE30\uBCF8), block=IRBlock 1\uAC1C=\uCCAD\uD06C 1\uAC1C"),
|
|
492
|
+
include_table_cells: z.boolean().default(false).describe("\uD45C \uCCAD\uD06C\uC5D0 \uC140 \uD14D\uC2A4\uD2B8 2\uCC28\uC6D0 \uBC30\uC5F4 \uD3EC\uD568 \uC5EC\uBD80")
|
|
493
|
+
},
|
|
494
|
+
async ({ file_path, granularity, include_table_cells }) => {
|
|
495
|
+
try {
|
|
496
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
497
|
+
const parsed = await parse(buffer, { filePath: file_path });
|
|
498
|
+
if (!parsed.success) {
|
|
499
|
+
return { content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}` }], isError: true };
|
|
500
|
+
}
|
|
501
|
+
const { blocksToChunks } = await import("./chunks-SX77P5CV.js");
|
|
502
|
+
const chunks = blocksToChunks(parsed.blocks, { granularity, includeTableCells: include_table_cells });
|
|
503
|
+
return { content: [{ type: "text", text: capResponseText(JSON.stringify(chunks, null, 2)) }] };
|
|
504
|
+
} catch (err) {
|
|
505
|
+
return { content: [{ type: "text", text: `\uCCAD\uD06C \uD30C\uC2F1 \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/mcp/tools-form.ts
|
|
512
|
+
import { z as z2 } from "zod";
|
|
513
|
+
import { readFile as readFile2, writeFile, mkdir, stat as stat2 } from "fs/promises";
|
|
514
|
+
import { extname as extname2, dirname as dirname2 } from "path";
|
|
508
515
|
function buildFillInputs(fields, formats) {
|
|
509
516
|
const out = {};
|
|
510
517
|
for (const [k, v] of Object.entries(fields)) {
|
|
@@ -513,705 +520,739 @@ function buildFillInputs(fields, formats) {
|
|
|
513
520
|
}
|
|
514
521
|
return out;
|
|
515
522
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
},
|
|
529
|
-
async ({ file_path, template, fields, formats, require_unique, mask_values, output_format, output_path }) => {
|
|
530
|
-
try {
|
|
531
|
-
const outExts = output_format === "markdown" ? /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]) : /* @__PURE__ */ new Set([".hwpx"]);
|
|
532
|
-
const outPath = output_path ? safeOutputPath(output_path, outExts) : void 0;
|
|
533
|
-
let buffer;
|
|
534
|
-
if (template) {
|
|
535
|
-
const t = resolveBuiltinTemplate(template);
|
|
536
|
-
if (!t) {
|
|
523
|
+
function registerFormTools(server2) {
|
|
524
|
+
server2.tool(
|
|
525
|
+
"parse_form",
|
|
526
|
+
"\uD55C\uAD6D \uC11C\uC2DD \uBB38\uC11C\uC5D0\uC11C \uB808\uC774\uBE14-\uAC12 \uC30D\uC744 \uAD6C\uC870\uD654\uB41C JSON\uC73C\uB85C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uC591\uC2DD/\uC11C\uC2DD \uBB38\uC11C\uC5D0 \uCD5C\uC801\uD654.",
|
|
527
|
+
{
|
|
528
|
+
file_path: z2.string().min(1).describe("\uC11C\uC2DD \uBB38\uC11C \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
|
|
529
|
+
},
|
|
530
|
+
async ({ file_path }) => {
|
|
531
|
+
try {
|
|
532
|
+
const { buffer } = await readValidatedFile(file_path);
|
|
533
|
+
const result = await parse(buffer, { keepTrailingEmptyCols: true });
|
|
534
|
+
if (!result.success) {
|
|
537
535
|
return {
|
|
538
|
-
content: [{ type: "text", text: `\
|
|
536
|
+
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${result.error}` }],
|
|
539
537
|
isError: true
|
|
540
538
|
};
|
|
541
539
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
540
|
+
const form = extractFormFields(result.blocks);
|
|
541
|
+
return {
|
|
542
|
+
content: [{ type: "text", text: JSON.stringify(form, null, 2) }]
|
|
543
|
+
};
|
|
544
|
+
} catch (err) {
|
|
546
545
|
return {
|
|
547
|
-
content: [{ type: "text", text:
|
|
546
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
548
547
|
isError: true
|
|
549
548
|
};
|
|
550
549
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
550
|
+
}
|
|
551
|
+
);
|
|
552
|
+
server2.tool(
|
|
553
|
+
"fill_form",
|
|
554
|
+
"\uD55C\uAD6D \uC11C\uC2DD \uBB38\uC11C\uC758 \uBE48\uCE78\uC744 \uCC44\uC6CC\uC11C \uC0C8 \uBB38\uC11C\uB85C \uCD9C\uB825\uD569\uB2C8\uB2E4. hwpx-preserve\uB97C \uC0AC\uC6A9\uD558\uBA74 \uC6D0\uBCF8 \uC11C\uC2DD(\uD14C\uB450\uB9AC, \uD3F0\uD2B8, \uBCD1\uD569 \uB4F1)\uC744 100% \uC720\uC9C0\uD569\uB2C8\uB2E4. HWPX \uB204\uB984\uD2C0(CLICK_HERE) \uD544\uB4DC\uB294 \uC774\uB984\uC73C\uB85C \uC815\uD655 \uB9E4\uCE6D\uB418\uC5B4 \uC6B0\uC120 \uCC44\uC6CC\uC9D1\uB2C8\uB2E4. file_path \uB300\uC2E0 template\uC73C\uB85C \uB0B4\uC7A5 \uC815\uBD80 \uD45C\uC900 \uAE30\uC548\uBB38 \uC11C\uC2DD\uC744 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4 \u2014 gian(\uC77C\uBC18\uAE30\uC548\uBB38, \uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD: \uD589\uC815\uAE30\uAD00\uBA85\xB7\uC218\uC2E0\uC790\xB7\uACBD\uC720\xB7\uC81C\uBAA9\xB7\uBCF8\uBB38\xB7\uBD99\uC784\xB7\uBC1C\uC2E0\uBA85\uC758\xB7\uAE30\uC548\uC790\xB7\uAC80\uD1A0\uC790\xB7\uACB0\uC7AC\uAD8C\uC790 \uB4F1 23\uD544\uB4DC) / gian-simple(\uAC04\uC774\uAE30\uC548\uBB38, \uBCC4\uC9C0 \uC81C2\uD638\uC11C\uC2DD: \uB0B4\uBD80\uACB0\uC7AC\uC6A9 13\uD544\uB4DC).",
|
|
555
|
+
{
|
|
556
|
+
file_path: z2.string().min(1).optional().describe("\uC11C\uC2DD \uD15C\uD50C\uB9BF \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWP, HWPX, PDF, XLSX, DOCX). template \uC0AC\uC6A9 \uC2DC \uC0DD\uB7B5"),
|
|
557
|
+
template: z2.enum(["gian", "gian-simple", "\uC77C\uBC18\uAE30\uC548\uBB38", "\uAC04\uC774\uAE30\uC548\uBB38"]).optional().describe("\uB0B4\uC7A5 \uC815\uBD80 \uD45C\uC900 \uC11C\uC2DD \uC774\uB984 \u2014 file_path \uB300\uC2E0 \uC0AC\uC6A9. gian=\uC77C\uBC18\uAE30\uC548\uBB38(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD), gian-simple=\uAC04\uC774\uAE30\uC548\uBB38(\uBCC4\uC9C0 \uC81C2\uD638\uC11C\uC2DD)"),
|
|
558
|
+
fields: z2.record(z2.string(), z2.string()).describe('\uCC44\uC6B8 \uD544\uB4DC \uB9F5 (\uB77C\uBCA8 \u2192 \uAC12). \uC608: {"\uC131\uBA85": "\uD64D\uAE38\uB3D9", "\uC804\uD654\uBC88\uD638": "010-1234-5678"}'),
|
|
559
|
+
formats: z2.record(z2.string(), z2.string()).optional().describe("\uD544\uB4DC\uBCC4 \uAC12 \uC11C\uC2DD (\uB77C\uBCA8 \u2192 \uD3EC\uB9F7). \uC815\uC900\uAC12 \uD558\uB098\uB85C \uC11C\uC2DD\uB9C8\uB2E4 \uB2E4\uB978 \uBAA8\uC591\uC744 \uCC44\uC6B8 \uB54C: date:yy.mm.dd / phone:hyphen\xB7dot\xB7digits / rrn:hyphen\xB7masked / mask:###-## / \uC790\uC720 \uD328\uD134(yyyy\uB144 m\uC6D4 d\uC77C, ###-####-####)"),
|
|
560
|
+
require_unique: z2.boolean().optional().describe("\uD55C \uD0A4\uAC00 \uC11C\uC2DD\uC758 2\uACF3 \uC774\uC0C1\uC5D0 \uB9E4\uCE6D\uB418\uBA74 \uCC44\uC6B0\uC9C0 \uC54A\uACE0 \uAC70\uBD80 \u2014 \uBC18\uBCF5 \uB77C\uBCA8 \uC591\uC2DD\uC5D0\uC11C \uB0A8\uC758 \uBE14\uB85D \uC624\uC5FC \uBC29\uC9C0 (\uBC30\uC5F4 \uAC12\uC740 \uC608\uC678)"),
|
|
561
|
+
mask_values: z2.boolean().optional().describe("\uC751\uB2F5\uC5D0 \uAC12 \uB300\uC2E0 \uAE00\uC790\uC218\uB9CC \uD45C\uC2DC \u2014 \uAC1C\uC778\uC815\uBCF4 \uCC44\uC6C0 \uC2DC \uAC12\uC774 \uB300\uD654 \uB85C\uADF8\uC5D0 \uB0A8\uC9C0 \uC54A\uAC8C"),
|
|
562
|
+
output_format: z2.enum(["markdown", "hwpx", "hwpx-preserve"]).default("hwpx-preserve").describe("\uCD9C\uB825 \uD3EC\uB9F7: hwpx-preserve (\uC6D0\uBCF8 \uC2A4\uD0C0\uC77C \uBCF4\uC874, HWPX \uC804\uC6A9), hwpx (\uC0C8 HWPX \uC0DD\uC131), markdown"),
|
|
563
|
+
output_path: z2.string().optional().describe("\uCD9C\uB825 \uD30C\uC77C \uC800\uC7A5 \uACBD\uB85C (\uC120\uD0DD). \uC9C0\uC815 \uC2DC \uD30C\uC77C\uB85C \uC800\uC7A5, \uBBF8\uC9C0\uC815 \uC2DC \uD14D\uC2A4\uD2B8\uB85C \uBC18\uD658")
|
|
564
|
+
},
|
|
565
|
+
async ({ file_path, template, fields, formats, require_unique, mask_values, output_format, output_path }) => {
|
|
566
|
+
try {
|
|
567
|
+
const outExts = output_format === "markdown" ? /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]) : /* @__PURE__ */ new Set([".hwpx"]);
|
|
568
|
+
const outPath = output_path ? safeOutputPath(output_path, outExts) : void 0;
|
|
569
|
+
let buffer;
|
|
570
|
+
if (template) {
|
|
571
|
+
const t = resolveBuiltinTemplate(template);
|
|
572
|
+
if (!t) {
|
|
573
|
+
return {
|
|
574
|
+
content: [{ type: "text", text: `\uC54C \uC218 \uC5C6\uB294 \uB0B4\uC7A5 \uD15C\uD50C\uB9BF: ${template} (\uC0AC\uC6A9 \uAC00\uB2A5: ${BUILTIN_TEMPLATES.map((x) => `${x.id}(${x.aliases[0]})`).join(", ")})` }],
|
|
575
|
+
isError: true
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
buffer = readBuiltinTemplate(t);
|
|
579
|
+
} else if (file_path) {
|
|
580
|
+
buffer = (await readValidatedFile(file_path)).buffer;
|
|
581
|
+
} else {
|
|
559
582
|
return {
|
|
560
|
-
content: [{ type: "text", text:
|
|
583
|
+
content: [{ type: "text", text: "file_path \uB610\uB294 template \uC911 \uD558\uB098\uB97C \uC9C0\uC815\uD574\uC8FC\uC138\uC694" }],
|
|
561
584
|
isError: true
|
|
562
585
|
};
|
|
563
586
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
587
|
+
if (output_format === "hwpx-preserve") {
|
|
588
|
+
let format = detectFormat(buffer);
|
|
589
|
+
if (format === "hwpx") {
|
|
590
|
+
const z5 = await detectZipFormat(buffer);
|
|
591
|
+
if (z5 !== "unknown") format = z5;
|
|
592
|
+
}
|
|
593
|
+
const isHwpx = format === "hwpx";
|
|
594
|
+
if (!isHwpx) {
|
|
595
|
+
return {
|
|
596
|
+
content: [{ type: "text", text: `hwpx-preserve\uB294 HWPX \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format}). hwpx \uB610\uB294 markdown\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.` }],
|
|
597
|
+
isError: true
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
const inputs = buildFillInputs(fields, formats);
|
|
601
|
+
const hwpxResult = require_unique ? await fillWithUniqueGuard(inputs, (vals, blocked) => fillHwpx(buffer, vals, blocked)) : { ...await fillHwpx(buffer, inputs), rejected: [] };
|
|
602
|
+
let verifyLine = null;
|
|
603
|
+
if (mask_values && hwpxResult.filled.length > 0) {
|
|
604
|
+
const reparsed = await parse(Buffer.from(hwpxResult.buffer));
|
|
605
|
+
const norm = (s) => s.replace(/\\([\\`*_{}[\]()#+.!|~>-])/g, "$1").replace(/\s+/g, " ");
|
|
606
|
+
const normMd = reparsed.success ? norm(reparsed.markdown) : "";
|
|
607
|
+
const okCount = reparsed.success ? hwpxResult.filled.filter((f) => f.value !== "" && normMd.includes(norm(f.value))).length : 0;
|
|
608
|
+
verifyLine = `\uAC80\uC99D(\uB9C8\uC2A4\uD0B9): ${okCount}/${hwpxResult.filled.length} FILLED \u2014 \uC7AC\uD30C\uC2F1 \uB300\uC870, \uAC12 \uBBF8\uB178\uCD9C`;
|
|
609
|
+
}
|
|
610
|
+
const summary2 = [
|
|
611
|
+
`\uCC44\uC6CC\uC9C4 \uD544\uB4DC: ${hwpxResult.filled.length}\uAC1C (\uC6D0\uBCF8 \uC2A4\uD0C0\uC77C \uBCF4\uC874)`,
|
|
612
|
+
hwpxResult.rejected.length > 0 ? `\uBAA8\uD638 \uB77C\uBCA8 \uAC70\uBD80(2\uACF3+ \uB9E4\uCE6D): ${hwpxResult.rejected.join(", ")}` : null,
|
|
613
|
+
hwpxResult.unmatched.length > 0 ? `\uB9E4\uCE6D \uC2E4\uD328: ${hwpxResult.unmatched.join(", ")}` : null,
|
|
614
|
+
verifyLine
|
|
615
|
+
].filter(Boolean).join(" | ");
|
|
616
|
+
const filledList = hwpxResult.filled.map((f) => ` - ${f.label}: ${mask_values ? `[${[...f.value].length}\uC790]` : f.value}`).join("\n");
|
|
617
|
+
if (outPath) {
|
|
618
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
619
|
+
await writeFile(outPath, Buffer.from(hwpxResult.buffer));
|
|
620
|
+
return {
|
|
621
|
+
content: [{ type: "text", text: `[${summary2}]
|
|
586
622
|
|
|
587
623
|
\uCC44\uC6CC\uC9C4 \uD544\uB4DC:
|
|
588
624
|
${filledList}
|
|
589
625
|
|
|
590
626
|
HWPX \uD30C\uC77C \uC800\uC7A5 (\uC6D0\uBCF8 \uC11C\uC2DD \uC720\uC9C0): ${outPath}` }]
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
return {
|
|
630
|
+
content: [{ type: "text", text: `[${summary2}]
|
|
595
631
|
|
|
596
632
|
\uCC44\uC6CC\uC9C4 \uD544\uB4DC:
|
|
597
633
|
${filledList}
|
|
598
634
|
|
|
599
635
|
\u26A0\uFE0F output_path\uB97C \uC9C0\uC815\uD558\uBA74 \uC6D0\uBCF8 \uC11C\uC2DD\uC774 \uC720\uC9C0\uB41C HWPX \uD30C\uC77C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4.` }]
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
return {
|
|
605
|
-
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${result.error}` }],
|
|
606
|
-
isError: true
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
const formInfo = extractFormFields(result.blocks);
|
|
610
|
-
const irInputs = buildFillInputs(fields, formats);
|
|
611
|
-
const fillResult = require_unique ? await fillWithUniqueGuard(irInputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked)) : { ...fillFormFields(result.blocks, irInputs), rejected: [] };
|
|
612
|
-
if (fillResult.filled.length === 0 && formInfo.fields.length === 0) {
|
|
613
|
-
return {
|
|
614
|
-
content: [{ type: "text", text: `\uC11C\uC2DD \uD544\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBC18 \uBB38\uC11C\uC774\uAC70\uB098 \uC11C\uC2DD \uD328\uD134\uC774 \uAC10\uC9C0\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.` }],
|
|
615
|
-
isError: true
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
const markdown = blocksToMarkdown(fillResult.blocks);
|
|
619
|
-
const previewMd = mask_values ? "\u26A0\uFE0F mask_values \uD65C\uC131 \u2014 \uAC1C\uC778\uC815\uBCF4 \uB178\uCD9C \uBC29\uC9C0\uB97C \uC704\uD574 \uBCF8\uBB38\uC744 \uC751\uB2F5\uC5D0 \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. output_path \uB85C \uD30C\uC77C \uC800\uC7A5 \uD6C4 \uD655\uC778\uD558\uC138\uC694." : markdown;
|
|
620
|
-
const summary = [
|
|
621
|
-
`\uCC44\uC6CC\uC9C4 \uD544\uB4DC: ${fillResult.filled.length}\uAC1C`,
|
|
622
|
-
fillResult.rejected.length > 0 ? `\uBAA8\uD638 \uB77C\uBCA8 \uAC70\uBD80(2\uACF3+ \uB9E4\uCE6D): ${fillResult.rejected.join(", ")}` : null,
|
|
623
|
-
fillResult.unmatched.length > 0 ? `\uB9E4\uCE6D \uC2E4\uD328: ${fillResult.unmatched.join(", ")}` : null,
|
|
624
|
-
formInfo.fields.length > 0 ? `\uC11C\uC2DD \uD544\uB4DC: ${formInfo.fields.length}\uAC1C (\uD655\uC2E0\uB3C4 ${(formInfo.confidence * 100).toFixed(0)}%)` : null
|
|
625
|
-
].filter(Boolean).join(" | ");
|
|
626
|
-
if (output_format === "hwpx") {
|
|
627
|
-
const hwpxBuffer = await markdownToHwpx(markdown);
|
|
628
|
-
if (outPath) {
|
|
629
|
-
await mkdir(dirname(outPath), { recursive: true });
|
|
630
|
-
await writeFile(outPath, Buffer.from(hwpxBuffer));
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
const result = await parse(buffer, { keepTrailingEmptyCols: true });
|
|
639
|
+
if (!result.success) {
|
|
631
640
|
return {
|
|
632
|
-
content: [{ type: "text", text:
|
|
633
|
-
|
|
634
|
-
HWPX \uD30C\uC77C \uC800\uC7A5: ${outPath}` }]
|
|
641
|
+
content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${result.error}` }],
|
|
642
|
+
isError: true
|
|
635
643
|
};
|
|
636
644
|
}
|
|
637
|
-
|
|
638
|
-
|
|
645
|
+
const formInfo = extractFormFields(result.blocks);
|
|
646
|
+
const irInputs = buildFillInputs(fields, formats);
|
|
647
|
+
const fillResult = require_unique ? await fillWithUniqueGuard(irInputs, (vals, blocked) => fillFormFields(result.blocks, vals, blocked)) : { ...fillFormFields(result.blocks, irInputs), rejected: [] };
|
|
648
|
+
if (fillResult.filled.length === 0 && formInfo.fields.length === 0) {
|
|
649
|
+
return {
|
|
650
|
+
content: [{ type: "text", text: `\uC11C\uC2DD \uD544\uB4DC\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBC18 \uBB38\uC11C\uC774\uAC70\uB098 \uC11C\uC2DD \uD328\uD134\uC774 \uAC10\uC9C0\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.` }],
|
|
651
|
+
isError: true
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
const markdown = blocksToMarkdown(fillResult.blocks);
|
|
655
|
+
const previewMd = mask_values ? "\u26A0\uFE0F mask_values \uD65C\uC131 \u2014 \uAC1C\uC778\uC815\uBCF4 \uB178\uCD9C \uBC29\uC9C0\uB97C \uC704\uD574 \uBCF8\uBB38\uC744 \uC751\uB2F5\uC5D0 \uD3EC\uD568\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. output_path \uB85C \uD30C\uC77C \uC800\uC7A5 \uD6C4 \uD655\uC778\uD558\uC138\uC694." : markdown;
|
|
656
|
+
const summary = [
|
|
657
|
+
`\uCC44\uC6CC\uC9C4 \uD544\uB4DC: ${fillResult.filled.length}\uAC1C`,
|
|
658
|
+
fillResult.rejected.length > 0 ? `\uBAA8\uD638 \uB77C\uBCA8 \uAC70\uBD80(2\uACF3+ \uB9E4\uCE6D): ${fillResult.rejected.join(", ")}` : null,
|
|
659
|
+
fillResult.unmatched.length > 0 ? `\uB9E4\uCE6D \uC2E4\uD328: ${fillResult.unmatched.join(", ")}` : null,
|
|
660
|
+
formInfo.fields.length > 0 ? `\uC11C\uC2DD \uD544\uB4DC: ${formInfo.fields.length}\uAC1C (\uD655\uC2E0\uB3C4 ${(formInfo.confidence * 100).toFixed(0)}%)` : null
|
|
661
|
+
].filter(Boolean).join(" | ");
|
|
662
|
+
if (output_format === "hwpx") {
|
|
663
|
+
const hwpxBuffer = await markdownToHwpx(markdown);
|
|
664
|
+
if (outPath) {
|
|
665
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
666
|
+
await writeFile(outPath, Buffer.from(hwpxBuffer));
|
|
667
|
+
return {
|
|
668
|
+
content: [{ type: "text", text: `[${summary}]
|
|
669
|
+
|
|
670
|
+
HWPX \uD30C\uC77C \uC800\uC7A5: ${outPath}` }]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
content: [{ type: "text", text: `[${summary}]
|
|
639
675
|
|
|
640
676
|
\u26A0\uFE0F output_path\uB97C \uC9C0\uC815\uD558\uBA74 HWPX \uD30C\uC77C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4. \uBBF8\uB9AC\uBCF4\uAE30:
|
|
641
677
|
|
|
642
678
|
${previewMd}` }]
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (outPath) {
|
|
682
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
683
|
+
await writeFile(outPath, markdown, "utf-8");
|
|
684
|
+
return {
|
|
685
|
+
content: [{ type: "text", text: `[${summary}]
|
|
650
686
|
|
|
651
687
|
\uB9C8\uD06C\uB2E4\uC6B4 \uD30C\uC77C \uC800\uC7A5: ${outPath}
|
|
652
688
|
|
|
653
689
|
${previewMd}` }]
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
content: [{ type: "text", text: `[${summary}]
|
|
658
694
|
|
|
659
695
|
${previewMd}` }]
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
return {
|
|
663
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
664
|
-
isError: true
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
);
|
|
669
|
-
server.tool(
|
|
670
|
-
"place_seal",
|
|
671
|
-
'\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0\uB97C \uC575\uCEE4 \uBB38\uAD6C("(\uC778)"\xB7"\uC11C\uBA85 \uB610\uB294 \uC778" \uB4F1) \uC704\uC5D0 \uBD80\uC720(\uAE00 \uC55E) \uBC30\uCE58\uD569\uB2C8\uB2E4. \uD45C/\uD398\uC774\uC9C0\uB97C \uD0A4\uC6B0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (HWPX \uC804\uC6A9).',
|
|
672
|
-
{
|
|
673
|
-
file_path: z.string().min(1).describe("\uB300\uC0C1 HWPX \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
674
|
-
image_path: z.string().min(1).describe("\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0 \uC808\uB300 \uACBD\uB85C (\uD22C\uBA85 \uBC30\uACBD PNG \uAD8C\uC7A5)"),
|
|
675
|
-
anchor: z.string().default("(\uC778)").describe("\uC575\uCEE4 \uBB38\uAD6C \u2014 \uC774 \uBB38\uAD6C \uAE30\uC900\uC73C\uB85C \uBC30\uCE58"),
|
|
676
|
-
occurrence: z.number().int().min(0).default(0).describe("\uAC19\uC740 \uC575\uCEE4\uAC00 \uC5EC\uB7FF\uC77C \uB54C 0-based \uC120\uD0DD"),
|
|
677
|
-
size_mm: z.number().positive().optional().describe("\uB3C4\uC7A5 \uD55C \uBCC0 \uD06C\uAE30 mm (\uAE30\uBCF8: \uC904\uB192\uC774\xD71.6, 7~18 \uD074\uB7A8\uD504)"),
|
|
678
|
-
mode: z.enum(["overlap", "right", "auto"]).default("auto").describe("overlap=\uBB38\uAD6C \uC704 \uACB9\uCE68, right=\uBB38\uAD6C \uC624\uB978\uCABD \uC606, auto=\uACF5\uAC04 \uC788\uC73C\uBA74 right"),
|
|
679
|
-
dx_mm: z.number().optional().describe("x \uBBF8\uC138\uC870\uC815 mm"),
|
|
680
|
-
dy_mm: z.number().optional().describe("y \uBBF8\uC138\uC870\uC815 mm"),
|
|
681
|
-
output_path: z.string().min(1).describe("\uCD9C\uB825 HWPX \uC800\uC7A5 \uACBD\uB85C")
|
|
682
|
-
},
|
|
683
|
-
async ({ file_path, image_path, anchor, occurrence, size_mm, mode, dx_mm, dy_mm, output_path }) => {
|
|
684
|
-
try {
|
|
685
|
-
const outPath = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx"]));
|
|
686
|
-
const { buffer } = await readValidatedFile(file_path);
|
|
687
|
-
const format = detectFormat(buffer);
|
|
688
|
-
if (format !== "hwpx") {
|
|
696
|
+
};
|
|
697
|
+
} catch (err) {
|
|
689
698
|
return {
|
|
690
|
-
content: [{ type: "text", text:
|
|
699
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
691
700
|
isError: true
|
|
692
701
|
};
|
|
693
702
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
703
|
+
}
|
|
704
|
+
);
|
|
705
|
+
server2.tool(
|
|
706
|
+
"place_seal",
|
|
707
|
+
'\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0\uB97C \uC575\uCEE4 \uBB38\uAD6C("(\uC778)"\xB7"\uC11C\uBA85 \uB610\uB294 \uC778" \uB4F1) \uC704\uC5D0 \uBD80\uC720(\uAE00 \uC55E) \uBC30\uCE58\uD569\uB2C8\uB2E4. \uD45C/\uD398\uC774\uC9C0\uB97C \uD0A4\uC6B0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (HWPX \uC804\uC6A9).',
|
|
708
|
+
{
|
|
709
|
+
file_path: z2.string().min(1).describe("\uB300\uC0C1 HWPX \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
710
|
+
image_path: z2.string().min(1).describe("\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0 \uC808\uB300 \uACBD\uB85C (\uD22C\uBA85 \uBC30\uACBD PNG \uAD8C\uC7A5)"),
|
|
711
|
+
anchor: z2.string().default("(\uC778)").describe("\uC575\uCEE4 \uBB38\uAD6C \u2014 \uC774 \uBB38\uAD6C \uAE30\uC900\uC73C\uB85C \uBC30\uCE58"),
|
|
712
|
+
occurrence: z2.number().int().min(0).default(0).describe("\uAC19\uC740 \uC575\uCEE4\uAC00 \uC5EC\uB7FF\uC77C \uB54C 0-based \uC120\uD0DD"),
|
|
713
|
+
size_mm: z2.number().positive().optional().describe("\uB3C4\uC7A5 \uD55C \uBCC0 \uD06C\uAE30 mm (\uAE30\uBCF8: \uC904\uB192\uC774\xD71.6, 7~18 \uD074\uB7A8\uD504)"),
|
|
714
|
+
mode: z2.enum(["overlap", "right", "auto"]).default("auto").describe("overlap=\uBB38\uAD6C \uC704 \uACB9\uCE68, right=\uBB38\uAD6C \uC624\uB978\uCABD \uC606, auto=\uACF5\uAC04 \uC788\uC73C\uBA74 right"),
|
|
715
|
+
dx_mm: z2.number().optional().describe("x \uBBF8\uC138\uC870\uC815 mm"),
|
|
716
|
+
dy_mm: z2.number().optional().describe("y \uBBF8\uC138\uC870\uC815 mm"),
|
|
717
|
+
output_path: z2.string().min(1).describe("\uCD9C\uB825 HWPX \uC800\uC7A5 \uACBD\uB85C")
|
|
718
|
+
},
|
|
719
|
+
async ({ file_path, image_path, anchor, occurrence, size_mm, mode, dx_mm, dy_mm, output_path }) => {
|
|
720
|
+
try {
|
|
721
|
+
const outPath = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx"]));
|
|
722
|
+
const { buffer } = await readValidatedFile(file_path);
|
|
723
|
+
const format = detectFormat(buffer);
|
|
724
|
+
if (format !== "hwpx") {
|
|
725
|
+
return {
|
|
726
|
+
content: [{ type: "text", text: `place_seal \uC740 HWPX \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format}).` }],
|
|
727
|
+
isError: true
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
const imgResolved = safePath(image_path, IMAGE_EXTENSIONS);
|
|
731
|
+
const imgSize = (await stat2(imgResolved)).size;
|
|
732
|
+
if (imgSize > 500 * 1024 * 1024) {
|
|
733
|
+
return { content: [{ type: "text", text: `\uB3C4\uC7A5 \uC774\uBBF8\uC9C0\uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${(imgSize / 1024 / 1024).toFixed(0)}MB) \u2014 500MB \uC774\uD558\uC5EC\uC57C \uD569\uB2C8\uB2E4.` }], isError: true };
|
|
734
|
+
}
|
|
735
|
+
const image = new Uint8Array(await readFile2(imgResolved));
|
|
736
|
+
const ext = extname2(imgResolved).slice(1).toLowerCase();
|
|
737
|
+
const { placeSealHwpx } = await import("./seal-RGUPOLXD.js");
|
|
738
|
+
const result = await placeSealHwpx(buffer, [{
|
|
739
|
+
anchor,
|
|
740
|
+
occurrence,
|
|
741
|
+
image,
|
|
742
|
+
ext,
|
|
743
|
+
sizeMm: size_mm,
|
|
744
|
+
mode,
|
|
745
|
+
dxMm: dx_mm,
|
|
746
|
+
dyMm: dy_mm
|
|
747
|
+
}]);
|
|
748
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
749
|
+
await writeFile(outPath, Buffer.from(result.buffer));
|
|
750
|
+
const p0 = result.placed[0];
|
|
751
|
+
const warnLines = (p0.warnings ?? []).map((w) => `
|
|
716
752
|
\u26A0\uFE0F ${w}`).join("");
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
753
|
+
return {
|
|
754
|
+
content: [{
|
|
755
|
+
type: "text",
|
|
756
|
+
text: `\uB3C4\uC7A5 \uBC30\uCE58 \uC644\uB8CC: "${p0.anchor}" #${p0.occurrence} \u2192 ${p0.mode} (x ${p0.posXMm}mm, y ${p0.posYMm}mm, ${p0.sizeMm}mm\uAC01, ${p0.entry})
|
|
721
757
|
\uC800\uC7A5: ${outPath}${warnLines}
|
|
722
758
|
\uD45C/\uD398\uC774\uC9C0 \uBD88\uD655\uC7A5(\uAE00 \uC55E \uBD80\uC720) \u2014 \uD55C\uCEF4\uC5D0\uC11C \uC704\uCE58 \uD655\uC778 \uD6C4 dx_mm/dy_mm \uB85C \uBBF8\uC138\uC870\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.`
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
return {
|
|
727
|
-
content: [{ type: "text", text: `\uB3C4\uC7A5 \uBC30\uCE58 \uC2E4\uD328: ${describeError(err)}` }],
|
|
728
|
-
isError: true
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
);
|
|
733
|
-
server.tool(
|
|
734
|
-
"patch_document",
|
|
735
|
-
"\uC6D0\uBCF8 HWPX/HWP\uC758 \uC11C\uC2DD(\uAE00\uAF34\xB7\uD45C\xB7\uB3C4\uC7A5\uCE78\xB7\uC774\uBBF8\uC9C0)\uC744 1\uBC14\uC774\uD2B8\uB3C4 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uACE0, \uD3B8\uC9D1\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC758 \uBC14\uB010 \uD14D\uC2A4\uD2B8\uB9CC \uC81C\uC790\uB9AC \uCE58\uD658\uD574 \uC0C8 \uBB38\uC11C\uB85C \uCD9C\uB825\uD569\uB2C8\uB2E4. parse_document\uB85C \uC5BB\uC740 \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uC218\uC815\uD574 \uB118\uAE30\uC138\uC694 \u2014 \uC591\uC2DD \uBE48\uCE78 \uCC44\uC6B0\uAE30\xB7\uBB38\uAD6C \uC218\uC815\uC5D0 \uC801\uD569\uD558\uBA70 \uD55C\uCEF4 \uD55C\uAE00\uC5D0\uC11C \uBCC0\uC870 \uACBD\uACE0 \uC5C6\uC774 \uC5F4\uB9BD\uB2C8\uB2E4. (\uBE14\uB85D \uCD94\uAC00/\uC0AD\uC81C\xB7\uD45C \uAD6C\uC870 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0, \uBBF8\uC801\uC6A9 \uD56D\uBAA9\uC740 \uACB0\uACFC\uC5D0 \uBCF4\uACE0)",
|
|
736
|
-
{
|
|
737
|
-
file_path: z.string().min(1).describe("\uC6D0\uBCF8 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWPX \uB610\uB294 HWP 5.x)"),
|
|
738
|
-
edited_markdown: z.string().min(1).describe("parse_document \uCD9C\uB825 \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uD3B8\uC9D1\uD55C \uC804\uCCB4 \uB9C8\uD06C\uB2E4\uC6B4. \uBC14\uB010 \uBB38\uB2E8/\uC140 \uD14D\uC2A4\uD2B8\uB9CC \uBC18\uC601\uD558\uACE0 \uBE14\uB85D \uC218\xB7\uC21C\uC11C\uB294 \uC6D0\uBCF8\uACFC \uAC19\uAC8C \uC720\uC9C0\uD558\uC138\uC694"),
|
|
739
|
-
output_path: z.string().min(1).describe("\uCD9C\uB825 \uD30C\uC77C \uC800\uC7A5 \uC808\uB300 \uACBD\uB85C (\uC6D0\uBCF8\uACFC \uAC19\uC740 \uD655\uC7A5\uC790: .hwpx \uB610\uB294 .hwp)")
|
|
740
|
-
},
|
|
741
|
-
async ({ file_path, edited_markdown, output_path }) => {
|
|
742
|
-
try {
|
|
743
|
-
const out = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
744
|
-
const { buffer } = await readValidatedFile(file_path);
|
|
745
|
-
const format = detectFormat(buffer);
|
|
746
|
-
let isHwpx = format === "hwpx";
|
|
747
|
-
if (isHwpx) {
|
|
748
|
-
const zipFormat = await detectZipFormat(buffer);
|
|
749
|
-
isHwpx = zipFormat === "hwpx";
|
|
750
|
-
}
|
|
751
|
-
if (!isHwpx && format !== "hwp") {
|
|
759
|
+
}]
|
|
760
|
+
};
|
|
761
|
+
} catch (err) {
|
|
752
762
|
return {
|
|
753
|
-
content: [{ type: "text", text:
|
|
763
|
+
content: [{ type: "text", text: `\uB3C4\uC7A5 \uBC30\uCE58 \uC2E4\uD328: ${describeError(err)}` }],
|
|
754
764
|
isError: true
|
|
755
765
|
};
|
|
756
766
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
server2.tool(
|
|
770
|
+
"patch_document",
|
|
771
|
+
"\uC6D0\uBCF8 HWPX/HWP\uC758 \uC11C\uC2DD(\uAE00\uAF34\xB7\uD45C\xB7\uB3C4\uC7A5\uCE78\xB7\uC774\uBBF8\uC9C0)\uC744 1\uBC14\uC774\uD2B8\uB3C4 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uACE0, \uD3B8\uC9D1\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC758 \uBC14\uB010 \uD14D\uC2A4\uD2B8\uB9CC \uC81C\uC790\uB9AC \uCE58\uD658\uD574 \uC0C8 \uBB38\uC11C\uB85C \uCD9C\uB825\uD569\uB2C8\uB2E4. parse_document\uB85C \uC5BB\uC740 \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uC218\uC815\uD574 \uB118\uAE30\uC138\uC694 \u2014 \uC591\uC2DD \uBE48\uCE78 \uCC44\uC6B0\uAE30\xB7\uBB38\uAD6C \uC218\uC815\uC5D0 \uC801\uD569\uD558\uBA70 \uD55C\uCEF4 \uD55C\uAE00\uC5D0\uC11C \uBCC0\uC870 \uACBD\uACE0 \uC5C6\uC774 \uC5F4\uB9BD\uB2C8\uB2E4. (\uBE14\uB85D \uCD94\uAC00/\uC0AD\uC81C\xB7\uD45C \uAD6C\uC870 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0, \uBBF8\uC801\uC6A9 \uD56D\uBAA9\uC740 \uACB0\uACFC\uC5D0 \uBCF4\uACE0)",
|
|
772
|
+
{
|
|
773
|
+
file_path: z2.string().min(1).describe("\uC6D0\uBCF8 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWPX \uB610\uB294 HWP 5.x)"),
|
|
774
|
+
edited_markdown: z2.string().min(1).describe("parse_document \uCD9C\uB825 \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uD3B8\uC9D1\uD55C \uC804\uCCB4 \uB9C8\uD06C\uB2E4\uC6B4. \uBC14\uB010 \uBB38\uB2E8/\uC140 \uD14D\uC2A4\uD2B8\uB9CC \uBC18\uC601\uD558\uACE0 \uBE14\uB85D \uC218\xB7\uC21C\uC11C\uB294 \uC6D0\uBCF8\uACFC \uAC19\uAC8C \uC720\uC9C0\uD558\uC138\uC694"),
|
|
775
|
+
output_path: z2.string().min(1).describe("\uCD9C\uB825 \uD30C\uC77C \uC800\uC7A5 \uC808\uB300 \uACBD\uB85C (\uC6D0\uBCF8\uACFC \uAC19\uC740 \uD655\uC7A5\uC790: .hwpx \uB610\uB294 .hwp)")
|
|
776
|
+
},
|
|
777
|
+
async ({ file_path, edited_markdown, output_path }) => {
|
|
778
|
+
try {
|
|
779
|
+
const out = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
780
|
+
const { buffer } = await readValidatedFile(file_path);
|
|
781
|
+
let format = detectFormat(buffer);
|
|
782
|
+
if (format === "hwpx") {
|
|
783
|
+
const z5 = await detectZipFormat(buffer);
|
|
784
|
+
if (z5 !== "unknown") format = z5;
|
|
785
|
+
} else if (format === "hwp") {
|
|
786
|
+
const o = detectOle2Format(buffer);
|
|
787
|
+
if (o !== "unknown") format = o;
|
|
788
|
+
}
|
|
789
|
+
const isHwpx = format === "hwpx";
|
|
790
|
+
if (!isHwpx && format !== "hwp") {
|
|
791
|
+
return {
|
|
792
|
+
content: [{ type: "text", text: `patch_document\uB294 HWPX \uB610\uB294 HWP 5.x\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format}).` }],
|
|
793
|
+
isError: true
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
const original = new Uint8Array(buffer);
|
|
797
|
+
const result = isHwpx ? await patchHwpx(original, edited_markdown) : await patchHwp(original, edited_markdown);
|
|
798
|
+
if (!result.success || !result.data) {
|
|
799
|
+
return {
|
|
800
|
+
content: [{ type: "text", text: `\uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}` }],
|
|
801
|
+
isError: true
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
await mkdir(dirname2(out), { recursive: true });
|
|
805
|
+
await writeFile(out, Buffer.from(result.data));
|
|
806
|
+
const v = result.verification?.stats;
|
|
807
|
+
const lossless = v ? v.modified === 0 && v.added === 0 && v.removed === 0 : void 0;
|
|
808
|
+
const lines = [
|
|
809
|
+
`\u2713 ${result.applied}\uAC1C \uBCC0\uACBD \uC801\uC6A9 (${isHwpx ? "HWPX" : "HWP"}, \uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874) \u2192 ${out}`,
|
|
810
|
+
lossless === true ? "\uAC80\uC99D: \uD3B8\uC9D1 \uB0B4\uC6A9\uACFC \uC7AC\uD30C\uC2F1 \uACB0\uACFC \uC644\uC804 \uC77C\uCE58" : lossless === false ? `\uAC80\uC99D \uC794\uCC28: \uC218\uC815 ${v.modified} \xB7 \uCD94\uAC00 ${v.added} \xB7 \uC0AD\uC81C ${v.removed} (\uBC18\uC601 \uC548 \uB41C \uD3B8\uC9D1 \uC788\uC74C)` : null,
|
|
811
|
+
result.skipped.length > 0 ? `\uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74:
|
|
812
|
+
` + result.skipped.map((s) => ` - ${s.reason}`).join("\n") : null
|
|
813
|
+
].filter(Boolean);
|
|
814
|
+
return {
|
|
815
|
+
content: [{ type: "text", text: lines.join("\n") }]
|
|
816
|
+
};
|
|
817
|
+
} catch (err) {
|
|
760
818
|
return {
|
|
761
|
-
content: [{ type: "text", text: `\
|
|
819
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
762
820
|
isError: true
|
|
763
821
|
};
|
|
764
822
|
}
|
|
765
|
-
await mkdir(dirname(out), { recursive: true });
|
|
766
|
-
await writeFile(out, Buffer.from(result.data));
|
|
767
|
-
const v = result.verification?.stats;
|
|
768
|
-
const lossless = v ? v.modified === 0 && v.added === 0 && v.removed === 0 : void 0;
|
|
769
|
-
const lines = [
|
|
770
|
-
`\u2713 ${result.applied}\uAC1C \uBCC0\uACBD \uC801\uC6A9 (${isHwpx ? "HWPX" : "HWP"}, \uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874) \u2192 ${out}`,
|
|
771
|
-
lossless === true ? "\uAC80\uC99D: \uD3B8\uC9D1 \uB0B4\uC6A9\uACFC \uC7AC\uD30C\uC2F1 \uACB0\uACFC \uC644\uC804 \uC77C\uCE58" : lossless === false ? `\uAC80\uC99D \uC794\uCC28: \uC218\uC815 ${v.modified} \xB7 \uCD94\uAC00 ${v.added} \xB7 \uC0AD\uC81C ${v.removed} (\uBC18\uC601 \uC548 \uB41C \uD3B8\uC9D1 \uC788\uC74C)` : null,
|
|
772
|
-
result.skipped.length > 0 ? `\uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74:
|
|
773
|
-
` + result.skipped.map((s) => ` - ${s.reason}`).join("\n") : null
|
|
774
|
-
].filter(Boolean);
|
|
775
|
-
return {
|
|
776
|
-
content: [{ type: "text", text: lines.join("\n") }]
|
|
777
|
-
};
|
|
778
|
-
} catch (err) {
|
|
779
|
-
return {
|
|
780
|
-
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
781
|
-
isError: true
|
|
782
|
-
};
|
|
783
823
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
const {
|
|
810
|
-
const
|
|
811
|
-
const
|
|
812
|
-
|
|
813
|
-
...
|
|
824
|
+
);
|
|
825
|
+
server2.tool(
|
|
826
|
+
"redact_document",
|
|
827
|
+
"\uBB38\uC11C\uC758 \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uBC88\uD638\xB7\uC804\uD654\xB7\uC774\uBA54\uC77C\xB7\uCE74\uB4DC\xB7\uACC4\uC88C)\uB97C \uD0D0\uC9C0\uD574 \uC11C\uC2DD \uBCF4\uC874 \uB9C8\uC2A4\uD0B9\uD569\uB2C8\uB2E4. HWPX/HWP\uB294 \uC6D0\uBCF8 \uC11C\uC2DD 1\uBC14\uC774\uD2B8 \uADF8\uB300\uB85C patch, \uADF8 \uC678 \uD3EC\uB9F7\uC740 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC73C\uB85C \uCD9C\uB825. \uC790\uB3D9 \uAC80\uCD9C \uBCF4\uC870 \uB3C4\uAD6C \u2014 \uACB0\uACFC \uB9AC\uD3EC\uD2B8\uB97C \uC0AC\uB78C\uC774 \uCD5C\uC885 \uD655\uC778\uD574\uC57C \uD558\uBA70 \uC774\uBBF8\uC9C0 \uC548 \uD14D\uC2A4\uD2B8\uB294 \uD0D0\uC9C0\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4. \uB9C8\uC2A4\uD0B9 \uD6C4 render_document\uB85C \uB208\uC73C\uB85C \uD655\uC778\uD558\uB294 \uAC83\uC744 \uAD8C\uC7A5\uD569\uB2C8\uB2E4.",
|
|
828
|
+
{
|
|
829
|
+
file_path: z2.string().min(1).describe("\uB300\uC0C1 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
830
|
+
rules: z2.array(z2.enum(["rrn", "phone", "email", "card", "account", "passport", "driver"])).optional().describe("\uC801\uC6A9 \uB8F0 (\uAE30\uBCF8: rrn\xB7phone\xB7email\xB7card\xB7account \u2014 passport\xB7driver\uB294 opt-in)"),
|
|
831
|
+
mask_char: z2.string().min(1).max(1).optional().describe("\uB9C8\uC2A4\uD06C \uBB38\uC790 1\uAE00\uC790 (\uAE30\uBCF8: \u25CF)"),
|
|
832
|
+
output_path: z2.string().min(1).optional().describe("\uCD9C\uB825 \uACBD\uB85C (HWPX/HWP\uB294 \uAC19\uC740 \uD655\uC7A5\uC790, \uADF8 \uC678\uB294 .md) \u2014 dry_run\uC774 \uC544\uB2C8\uBA74 \uD544\uC218"),
|
|
833
|
+
dry_run: z2.boolean().default(false).describe("\uD0D0\uC9C0 \uB9AC\uD3EC\uD2B8\uB9CC \uBC18\uD658, \uD30C\uC77C \uBBF8\uC0DD\uC131")
|
|
834
|
+
},
|
|
835
|
+
async ({ file_path, rules, mask_char, output_path, dry_run }) => {
|
|
836
|
+
try {
|
|
837
|
+
const { buffer } = await readValidatedFile(file_path);
|
|
838
|
+
const format = detectFormat(buffer);
|
|
839
|
+
const patchable = format === "hwpx" || format === "hwp";
|
|
840
|
+
if (!dry_run && !output_path) {
|
|
841
|
+
return { content: [{ type: "text", text: "output_path\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uD0D0\uC9C0\uB9CC \uC6D0\uD558\uBA74 dry_run: true)." }], isError: true };
|
|
842
|
+
}
|
|
843
|
+
const outPath = !dry_run ? safeOutputPath(output_path, new Set(patchable ? [format === "hwp" ? ".hwp" : ".hwpx"] : [".md", ".markdown", ".txt"])) : void 0;
|
|
844
|
+
const parsed = await parse(buffer, { filePath: file_path });
|
|
845
|
+
if (!parsed.success) {
|
|
846
|
+
return { content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}` }], isError: true };
|
|
847
|
+
}
|
|
848
|
+
const { redactMarkdown } = await import("./redact-7ILEAUTS.js");
|
|
849
|
+
const r = redactMarkdown(parsed.markdown, { rules, maskChar: mask_char });
|
|
850
|
+
const byRule = /* @__PURE__ */ new Map();
|
|
851
|
+
for (const h of r.hits) byRule.set(h.rule, (byRule.get(h.rule) ?? 0) + 1);
|
|
852
|
+
const lines = [
|
|
853
|
+
`\uD0D0\uC9C0: ${r.hits.length}\uAC74 (${[...byRule.entries()].map(([k, v]) => `${k} ${v}`).join(", ") || "\uC5C6\uC74C"})`,
|
|
854
|
+
...r.hits.map((h) => ` - [${h.rule}] ${h.masked}`)
|
|
814
855
|
];
|
|
815
|
-
if (
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
856
|
+
if (!dry_run && r.hits.length > 0) {
|
|
857
|
+
if (patchable) {
|
|
858
|
+
const original = new Uint8Array(buffer);
|
|
859
|
+
const result = format === "hwp" ? await patchHwp(original, r.text) : await patchHwpx(original, r.text);
|
|
860
|
+
if (!result.success || !result.data) {
|
|
861
|
+
return { content: [{ type: "text", text: `\uB9C8\uC2A4\uD0B9 \uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}` }], isError: true };
|
|
862
|
+
}
|
|
863
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
864
|
+
await writeFile(outPath, Buffer.from(result.data));
|
|
865
|
+
lines.push(`\uC800\uC7A5: ${outPath} (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874)`);
|
|
866
|
+
if (result.skipped.length > 0) {
|
|
867
|
+
lines.push(`\u26A0\uFE0F \uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74 \u2014 \uD574\uB2F9 \uC704\uCE58\uB294 \uC6D0\uBB38\uC774 \uB0A8\uC544 \uC788\uC73C\uB2C8 \uBC18\uB4DC\uC2DC \uC218\uB3D9 \uD655\uC778:`);
|
|
868
|
+
for (const s of result.skipped) lines.push(` - ${s.reason}`);
|
|
869
|
+
}
|
|
870
|
+
lines.push("render_document\uB85C \uB9C8\uC2A4\uD0B9 \uACB0\uACFC\uB97C \uB208\uC73C\uB85C \uD655\uC778\uD558\uC138\uC694.");
|
|
871
|
+
} else {
|
|
872
|
+
await mkdir(dirname2(outPath), { recursive: true });
|
|
873
|
+
await writeFile(outPath, r.text, "utf-8");
|
|
874
|
+
lines.push(`\uC800\uC7A5: ${outPath} (${format}\uB294 \uC11C\uC2DD \uBCF4\uC874 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC2A4\uD0B9\uB41C \uB9C8\uD06C\uB2E4\uC6B4)`);
|
|
875
|
+
}
|
|
876
|
+
} else if (!dry_run) {
|
|
877
|
+
lines.push("\uD0D0\uC9C0 0\uAC74 \u2014 \uCD9C\uB825 \uD30C\uC77C\uC744 \uB9CC\uB4E4\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
820
878
|
}
|
|
821
|
-
|
|
822
|
-
|
|
879
|
+
lines.push("\uC8FC\uC758: \uC790\uB3D9 \uAC80\uCD9C\uC740 \uBCF4\uC870 \uC218\uB2E8\uC785\uB2C8\uB2E4. \uC774\uBBF8\uC9C0 \uC18D \uD14D\uC2A4\uD2B8\xB7\uD45C\uAE30 \uBCC0\uD615\uC740 \uB193\uCE60 \uC218 \uC788\uC73C\uB2C8 \uCD5C\uC885 \uACF5\uAC1C \uC804 \uC0AC\uB78C \uAC80\uD1A0\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
880
|
+
return { content: [{ type: "text", text: capResponseText(lines.join("\n")) }] };
|
|
881
|
+
} catch (err) {
|
|
882
|
+
return { content: [{ type: "text", text: `\uB9C8\uC2A4\uD0B9 \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// src/mcp/tools-render.ts
|
|
889
|
+
import { z as z3 } from "zod";
|
|
890
|
+
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
891
|
+
import { dirname as dirname3, join } from "path";
|
|
892
|
+
function registerRenderTools(server2) {
|
|
893
|
+
server2.tool(
|
|
894
|
+
"render_document",
|
|
895
|
+
"HWPX\xB7HWP \uBB38\uC11C\uB97C \uC2E4\uC81C \uC870\uD310 \uADF8\uB300\uB85C \uB80C\uB354\uD574 PNG/JPEG \uC774\uBBF8\uC9C0\uB85C \uC751\uB2F5\uD558\uAC70\uB098 SVG\xB7HTML\xB7PDF \uD30C\uC77C\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4. generate_document\xB7fill_form\xB7patch_document\xB7place_seal \uACB0\uACFC\uBB3C\uC744 \uB208\uC73C\uB85C \uD655\uC778\uD558\uB294 \uC6A9\uB3C4 \u2014 \uC0DD\uC131/\uC218\uC815 \uD6C4 \uC774 \uB3C4\uAD6C\uB85C \uB80C\uB354\uD574 \uAE68\uC9D0\xB7\uC798\uB9BC\xB7\uBC30\uCE58\uB97C \uAC80\uC99D\uD558\uACE0 \uB2E4\uC2DC \uACE0\uCE58\uB294 \uB8E8\uD504\uB97C \uAD8C\uC7A5\uD569\uB2C8\uB2E4. \uD55C\uCEF4 \uC800\uC7A5\uBCF8(HWPX\xB7HWP \uBAA8\uB450)\uC740 \uC870\uD310 \uCE90\uC2DC\uB85C \uC815\uD655\uD788, AI \uC0DD\uC131\uBCF8(\uCE90\uC2DC \uC5C6\uC74C)\uC740 \uC21C\uC218 \uC870\uD310 \uC5D4\uC9C4(reflow)\uC73C\uB85C \uB80C\uB354\uB418\uBA70 \uD6C4\uC790\uB294 \uD55C\uCEF4 \uC2E4\uC870\uD310\uC758 \uADFC\uC0AC\uC785\uB2C8\uB2E4 (\uCC38\uACE0\uC6A9 \uBBF8\uB9AC\uBCF4\uAE30).",
|
|
896
|
+
{
|
|
897
|
+
file_path: z3.string().min(1).describe("\uB80C\uB354\uD560 HWPX \uB610\uB294 HWP(5.x) \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
898
|
+
format: z3.enum(["png", "jpeg", "svg", "html", "pdf"]).default("png").describe("png/jpeg=\uC774\uBBF8\uC9C0\uB85C \uC751\uB2F5\uC5D0 \uC9C1\uC811 \uBC18\uD658(output_path \uB294 \uC120\uD0DD) / svg\xB7html\xB7pdf=output_path \uC5D0 \uD30C\uC77C \uC800\uC7A5(\uD544\uC218). svg \uB294 pages \uBBF8\uC9C0\uC815 HWPX \uBA74 \uC804\uCCB4 \uC138\uB85C \uC2A4\uD0DD 1\uD30C\uC77C, \uADF8 \uC678 \uD398\uC774\uC9C0\uBCC4 \uD30C\uC77C. html=\uC790\uAE09\uC790\uC871 \uB808\uC774\uC544\uC6C3 HTML 1\uD30C\uC77C, pdf=Chromium \uD544\uC694"),
|
|
899
|
+
output_path: z3.string().min(1).optional().describe("\uACB0\uACFC \uC800\uC7A5 \uACBD\uB85C (\uD655\uC7A5\uC790\uB294 format \uACFC \uC77C\uCE58 \u2014 .png/.jpg/.svg/.html/.pdf). \uD398\uC774\uC9C0\uBCC4 \uC0B0\uCD9C\uC740 _page_NNN \uC811\uBBF8"),
|
|
900
|
+
highlights: z3.array(z3.string().min(1)).optional().describe("\uD615\uAD11\uD39C \uD45C\uC2DC\uD560 \uAC80\uC0C9\uC5B4 \uBAA9\uB85D \u2014 \uCC44\uC6B4 \uAC12\xB7\uC218\uC815 \uBB38\uAD6C \uC704\uCE58 \uD655\uC778\uC6A9"),
|
|
901
|
+
reflow_mode: z3.enum(["keep", "charAll"]).default("keep").describe("reflow \uC904\uBC14\uAFC8: keep=\uC5B4\uC808 \uB2E8\uC704, charAll=\uAE00\uC790 \uB2E8\uC704"),
|
|
902
|
+
pages: z3.string().min(1).optional().describe("\uD398\uC774\uC9C0 \uC120\uD0DD(1-based: '3', '1-3', '1,3,7-9') \u2014 \uC9C0\uC815\uD558\uBA74 \uD398\uC774\uC9C0\uBCC4 \uC0B0\uCD9C(\uC774\uBBF8\uC9C0 \uC751\uB2F5\uC740 \uCD5C\uB300 8\uCABD). HWPX png/svg \uC5D0\uC11C \uBBF8\uC9C0\uC815\uC774\uBA74 \uC804\uCCB4\uB97C \uC138\uB85C \uC2A4\uD0DD 1\uC7A5\uC73C\uB85C"),
|
|
903
|
+
max_width_px: z3.number().int().min(200).max(4e3).optional().describe("\uB798\uC2A4\uD130(png/jpeg) \uCD5C\uB300 \uD3ED px \u2014 \uD070 \uBB38\uC11C \uC751\uB2F5 \uBD80\uD53C \uC870\uC808")
|
|
904
|
+
},
|
|
905
|
+
async ({ file_path, format, output_path, highlights, reflow_mode, pages, max_width_px }) => {
|
|
906
|
+
try {
|
|
907
|
+
const EXT = { png: [".png"], jpeg: [".jpg", ".jpeg"], svg: [".svg"], html: [".html", ".htm"], pdf: [".pdf"] };
|
|
908
|
+
const needsFile = format === "svg" || format === "html" || format === "pdf";
|
|
909
|
+
if (needsFile && !output_path) {
|
|
910
|
+
return { content: [{ type: "text", text: `format: "${format}" \uC740 output_path(${EXT[format][0]})\uAC00 \uD544\uC218\uC785\uB2C8\uB2E4 \u2014 \uC6D0\uBB38\uC740 \uCEE4\uC11C \uC751\uB2F5\uC5D0 \uC9C1\uC811 \uB2F4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.` }], isError: true };
|
|
911
|
+
}
|
|
912
|
+
const outPath = output_path ? safeOutputPath(output_path, new Set(EXT[format])) : void 0;
|
|
913
|
+
const { buffer, resolved } = await readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
914
|
+
const isHwp5 = resolved.toLowerCase().endsWith(".hwp");
|
|
915
|
+
if (!isHwp5 && !pages && (format === "png" || format === "svg")) {
|
|
916
|
+
const { renderHwpxToSvg } = await import("./render-NGP5T24S.js");
|
|
917
|
+
const result = await renderHwpxToSvg(buffer, { highlights, reflow: true, reflowMode: reflow_mode });
|
|
918
|
+
const summary2 = [
|
|
919
|
+
`\uB80C\uB354 \uC644\uB8CC: ${result.pageCount}\uD398\uC774\uC9C0, ${Math.round(result.width)}x${Math.round(result.height)}pt (\uD14D\uC2A4\uD2B8 ${result.stats.texts}\xB7\uC774\uBBF8\uC9C0 ${result.stats.images}\xB7\uD45C ${result.stats.tables})`,
|
|
920
|
+
...result.warnings.map((w) => `\u26A0\uFE0F ${w}`)
|
|
921
|
+
];
|
|
922
|
+
if (format === "svg") {
|
|
923
|
+
await mkdir2(dirname3(outPath), { recursive: true });
|
|
924
|
+
await writeFile2(outPath, result.svg, "utf-8");
|
|
925
|
+
summary2.push(`\uC800\uC7A5: ${outPath}`);
|
|
926
|
+
return { content: [{ type: "text", text: summary2.join("\n") }] };
|
|
927
|
+
}
|
|
928
|
+
const { rasterizeSvg } = await import("./rasterize-46RG4ZF6.js");
|
|
929
|
+
const raster = await rasterizeSvg(result.svg, result.width, result.height, max_width_px ? { maxWidthPx: max_width_px } : void 0);
|
|
930
|
+
if (outPath) {
|
|
931
|
+
await mkdir2(dirname3(outPath), { recursive: true });
|
|
932
|
+
await writeFile2(outPath, raster.png);
|
|
933
|
+
summary2.push(`\uC800\uC7A5: ${outPath}`);
|
|
934
|
+
}
|
|
935
|
+
summary2.push(`\uC774\uBBF8\uC9C0 ${raster.widthPx}x${raster.heightPx}px \u2014 \uC798\uB9BC\xB7\uACB9\uCE68\xB7\uBE48\uCE78\xB7\uD398\uC774\uC9C0 \uB118\uCE68\uC774 \uBCF4\uC774\uBA74 \uC6D0\uC778 \uD14D\uC2A4\uD2B8\uB97C \uC218\uC815\uD574 \uB2E4\uC2DC \uC0DD\uC131/\uD328\uCE58\uD558\uC138\uC694.`);
|
|
936
|
+
return {
|
|
937
|
+
content: [
|
|
938
|
+
{ type: "image", data: raster.png.toString("base64"), mimeType: "image/png" },
|
|
939
|
+
{ type: "text", text: summary2.join("\n") }
|
|
940
|
+
]
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
const { renderDocument } = await import("./render-NGP5T24S.js");
|
|
944
|
+
const { scene, assets } = await renderDocument(buffer, { format, pages, highlights, reflow: true, reflowMode: reflow_mode, maxWidthPx: max_width_px });
|
|
945
|
+
const summary = [
|
|
946
|
+
`\uB80C\uB354 \uC644\uB8CC: \uBB38\uC11C ${scene.pages.length}\uD398\uC774\uC9C0 \uC911 ${assets.filter((a) => a.page !== void 0).length || 1}\uAC74 (\uD14D\uC2A4\uD2B8 ${scene.stats.texts}\xB7\uC774\uBBF8\uC9C0 ${scene.stats.images}\xB7\uD45C ${scene.stats.tables}\xB7\uB3C4\uD615 ${scene.stats.shapes})`,
|
|
947
|
+
...scene.warnings.map((w) => `\u26A0\uFE0F ${w}`)
|
|
948
|
+
];
|
|
949
|
+
const suffixed = (p, page) => p.replace(/(\.[^.]+)$/, `_page_${String(page).padStart(3, "0")}$1`);
|
|
823
950
|
if (outPath) {
|
|
824
|
-
await
|
|
825
|
-
|
|
826
|
-
|
|
951
|
+
await mkdir2(dirname3(outPath), { recursive: true });
|
|
952
|
+
for (const a of assets) {
|
|
953
|
+
const p = a.page === void 0 || assets.length === 1 ? outPath : suffixed(outPath, a.page);
|
|
954
|
+
await writeFile2(p, a.data);
|
|
955
|
+
summary.push(`\uC800\uC7A5: ${p}`);
|
|
956
|
+
}
|
|
827
957
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const summary = [
|
|
839
|
-
`\uB80C\uB354 \uC644\uB8CC: \uBB38\uC11C ${scene.pages.length}\uD398\uC774\uC9C0 \uC911 ${assets.filter((a) => a.page !== void 0).length || 1}\uAC74 (\uD14D\uC2A4\uD2B8 ${scene.stats.texts}\xB7\uC774\uBBF8\uC9C0 ${scene.stats.images}\xB7\uD45C ${scene.stats.tables}\xB7\uB3C4\uD615 ${scene.stats.shapes})`,
|
|
840
|
-
...scene.warnings.map((w) => `\u26A0\uFE0F ${w}`)
|
|
841
|
-
];
|
|
842
|
-
const suffixed = (p, page) => p.replace(/(\.[^.]+)$/, `_page_${String(page).padStart(3, "0")}$1`);
|
|
843
|
-
if (outPath) {
|
|
844
|
-
await mkdir(dirname(outPath), { recursive: true });
|
|
845
|
-
for (const a of assets) {
|
|
846
|
-
const p = a.page === void 0 || assets.length === 1 ? outPath : suffixed(outPath, a.page);
|
|
847
|
-
await writeFile(p, a.data);
|
|
848
|
-
summary.push(`\uC800\uC7A5: ${p}`);
|
|
958
|
+
if (format === "png" || format === "jpeg") {
|
|
959
|
+
const MAX_PAGES = 8;
|
|
960
|
+
const shown = assets.slice(0, MAX_PAGES);
|
|
961
|
+
if (assets.length > MAX_PAGES) summary.push(`\u26A0\uFE0F ${MAX_PAGES}\uCABD\uAE4C\uC9C0\uB9CC \uC751\uB2F5\uC5D0 \uB2F4\uC558\uC2B5\uB2C8\uB2E4 \u2014 pages \uB97C \uC881\uD788\uC138\uC694`);
|
|
962
|
+
return {
|
|
963
|
+
content: [
|
|
964
|
+
...shown.map((a) => ({ type: "image", data: a.data.toString("base64"), mimeType: format === "jpeg" ? "image/jpeg" : "image/png" })),
|
|
965
|
+
{ type: "text", text: summary.join("\n") }
|
|
966
|
+
]
|
|
967
|
+
};
|
|
849
968
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const MAX_PAGES = 8;
|
|
853
|
-
const shown = assets.slice(0, MAX_PAGES);
|
|
854
|
-
if (assets.length > MAX_PAGES) summary.push(`\u26A0\uFE0F ${MAX_PAGES}\uCABD\uAE4C\uC9C0\uB9CC \uC751\uB2F5\uC5D0 \uB2F4\uC558\uC2B5\uB2C8\uB2E4 \u2014 pages \uB97C \uC881\uD788\uC138\uC694`);
|
|
969
|
+
return { content: [{ type: "text", text: summary.join("\n") }] };
|
|
970
|
+
} catch (err) {
|
|
855
971
|
return {
|
|
856
|
-
content: [
|
|
857
|
-
|
|
858
|
-
{ type: "text", text: summary.join("\n") }
|
|
859
|
-
]
|
|
972
|
+
content: [{ type: "text", text: `\uB80C\uB354 \uC2E4\uD328: ${describeError(err)}` }],
|
|
973
|
+
isError: true
|
|
860
974
|
};
|
|
861
975
|
}
|
|
862
|
-
return { content: [{ type: "text", text: summary.join("\n") }] };
|
|
863
|
-
} catch (err) {
|
|
864
|
-
return {
|
|
865
|
-
content: [{ type: "text", text: `\uB80C\uB354 \uC2E4\uD328: ${describeError(err)}` }],
|
|
866
|
-
isError: true
|
|
867
|
-
};
|
|
868
976
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
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 });
|
|
895
|
-
}
|
|
896
|
-
await writeFile(join(dir, "regions.json"), JSON.stringify(manifest, null, 2));
|
|
897
|
-
return { content: [{ type: "text", text: `crop ${regions.length}\uAC74 \u2192 ${dir}
|
|
898
|
-
` + manifest.map((m) => `${m.file} p${m.page} (${m.bbox.x},${m.bbox.y} ${m.bbox.width}\xD7${m.bbox.height}pt)${m.sourceId ? ` src=${m.sourceId}` : ""}`).join("\n") }] };
|
|
899
|
-
} catch (err) {
|
|
900
|
-
return { content: [{ type: "text", text: `crop \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
);
|
|
904
|
-
server.tool(
|
|
905
|
-
"extract_tables",
|
|
906
|
-
"HWPX\xB7HWP \uBB38\uC11C\uC758 \uD45C\uB97C \uCD94\uCD9C\xB7\uBD84\uB958\uD569\uB2C8\uB2E4(#76). \uD45C\uB9C8\uB2E4 semantic-table(\uB370\uC774\uD130\uD45C) / non-tabular-layout(\uC870\uC9C1\uB3C4\xB7\uC5F0\uB77D\uB9DD\xB7\uACB0\uC7AC\uB780\uCC98\uB7FC \uD45C\uB97C \uCE94\uBC84\uC2A4\uB85C \uC4F4 \uAC83) / uncertain \uBD84\uB958\uC640 \uADFC\uAC70 \uC2E0\uD638, \uD398\uC774\uC9C0\xB7bbox(pt, \uB80C\uB354 region \uC870\uC778), \uC815\uCC45(visual)\uC5D0 \uB530\uB978 crop \uC774\uBBF8\uC9C0\uB97C \uB3CC\uB824\uC90D\uB2C8\uB2E4 \u2014 \uC870\uC9C1\uB3C4\uB294 \uC774\uBBF8\uC9C0\uB85C, \uB370\uC774\uD130\uD45C\uB294 \uC140 \uAD6C\uC870\uB85C \uB118\uAE30\uB294 \uBA40\uD2F0\uBAA8\uB2EC \uD30C\uC774\uD504\uB77C\uC778\uC6A9. \uD734\uB9AC\uC2A4\uD2F1(\uB124\uD2B8\uC6CC\uD06C\xB7LLM \uC5C6\uC74C), \uC911\uCCA9\uD45C\uB3C4 \uB3C5\uB9BD \uBD84\uB958. crop \uC740 output_dir \uC5D0 \uC800\uC7A5\uD558\uACE0 8\uC7A5\uAE4C\uC9C0 \uC751\uB2F5\uC5D0 \uD568\uAED8 \uB2F4\uC2B5\uB2C8\uB2E4.",
|
|
907
|
-
{
|
|
908
|
-
file_path: z.string().min(1).describe("HWPX \uB610\uB294 HWP(5.x) \uD30C\uC77C \uC808\uB300 \uACBD\uB85C"),
|
|
909
|
-
output_dir: z.string().min(1).optional().describe("crop \uD30C\uC77C\xB7tables.json \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC (visual \uC774 none \uC774 \uC544\uB2C8\uBA74 \uD544\uC218)"),
|
|
910
|
-
visual: z.enum(["none", "non-tabular", "non-tabular-and-uncertain", "all"]).default("none").describe("crop \uB300\uC0C1: none=\uBD84\uB958\xB7bbox \uB9CC / non-tabular=\uC870\uC9C1\uB3C4\uB958\uB9CC / non-tabular-and-uncertain(\uAD8C\uC7A5) / all"),
|
|
911
|
-
format: z.enum(["png", "jpeg"]).default("png"),
|
|
912
|
-
padding_pt: z.number().min(0).max(100).default(0).describe("crop \uB458\uB808 \uC5EC\uBC31 pt"),
|
|
913
|
-
cells: z.boolean().default(false).describe("\uC751\uB2F5 JSON \uC5D0 \uC140 \uD14D\uC2A4\uD2B8 \uACA9\uC790 \uD3EC\uD568")
|
|
914
|
-
},
|
|
915
|
-
async ({ file_path, output_dir, visual, format, padding_pt, cells }) => {
|
|
916
|
-
try {
|
|
917
|
-
if (visual !== "none" && !output_dir) {
|
|
918
|
-
return { content: [{ type: "text", text: "visual \uC774 none \uC774 \uC544\uB2C8\uBA74 crop \uD30C\uC77C\uC744 \uC800\uC7A5\uD560 output_dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4." }], isError: true };
|
|
919
|
-
}
|
|
920
|
-
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
921
|
-
const dir = output_dir ? safeOutputPath(join(output_dir, "tables.json"), /* @__PURE__ */ new Set([".json"])).replace(/[\\/]tables\.json$/, "") : void 0;
|
|
922
|
-
const { extractTables } = await import("./visual-VZ7QGAUC.js");
|
|
923
|
-
const tables = await extractTables(buffer, { policy: visual, format, paddingPt: padding_pt });
|
|
924
|
-
if (dir) await mkdir(dir, { recursive: true });
|
|
925
|
-
const ext = format === "jpeg" ? "jpg" : "png";
|
|
926
|
-
const images = [];
|
|
927
|
-
const report = [];
|
|
928
|
-
for (const t of tables) {
|
|
929
|
-
const crops = [];
|
|
930
|
-
for (const c of t.crops) {
|
|
931
|
-
const name = `${t.id.replace(/[^\w.-]/g, "_")}_page_${String(c.page).padStart(3, "0")}.${ext}`;
|
|
932
|
-
if (dir) await writeFile(join(dir, name), c.data);
|
|
933
|
-
if (images.length < 8) images.push({ type: "image", data: c.data.toString("base64"), mimeType: c.mimeType });
|
|
934
|
-
crops.push({ file: dir ? name : void 0, page: c.page, bbox: c.bbox });
|
|
977
|
+
);
|
|
978
|
+
server2.tool(
|
|
979
|
+
"crop_regions",
|
|
980
|
+
"HWPX\xB7HWP \uBB38\uC11C\uB97C \uB80C\uB354\uD574 \uD45C\xB7\uC774\uBBF8\uC9C0\xB7\uBB38\uB2E8\xB7\uB3C4\uD615 \uC601\uC5ED\uC744 \uD398\uC774\uC9C0 \uC774\uBBF8\uC9C0\uC5D0\uC11C \uC798\uB77C \uD30C\uC77C\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4(render_document \uC640 \uAC19\uC740 \uC870\uD310 \uC5D4\uC9C4, \uD398\uC774\uC9C0 \uB85C\uCEEC pt bbox \uB97C \uC2E4\uBC30\uC728\uB85C \uD658\uC0B0). \uD45C\uAC00 \uC9C4\uC9DC \uB370\uC774\uD130\uD45C\uC778\uC9C0 \uC870\uC9C1\uB3C4\uC778\uC9C0\uB294 \uD310\uB2E8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uADF8\uAC74 extract_tables) \u2014 \uB80C\uB354\uB7EC\uAC00 \uC544\uB294 \uAC1C\uCCB4\uB97C \uC790\uB97C \uBFD0. \uACB0\uACFC: output_dir/<\uC720\uD615>_<\uBC88\uD638>_page_<\uCABD>.png + regions.json(id\xB7\uC720\uD615\xB7\uD398\uC774\uC9C0\xB7bbox pt).",
|
|
981
|
+
{
|
|
982
|
+
file_path: z3.string().min(1).describe("HWPX \uB610\uB294 HWP(5.x) \uD30C\uC77C \uC808\uB300 \uACBD\uB85C"),
|
|
983
|
+
output_dir: z3.string().min(1).describe("crop \uD30C\uC77C \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC"),
|
|
984
|
+
target: z3.array(z3.enum(["table", "image", "paragraph", "shape"])).default(["table"]).describe("\uC798\uB77C\uB0BC \uAC1C\uCCB4 \uC720\uD615"),
|
|
985
|
+
format: z3.enum(["png", "jpeg"]).default("png"),
|
|
986
|
+
pages: z3.string().min(1).optional().describe("\uB300\uC0C1 \uD398\uC774\uC9C0(1-based \uBC94\uC704)"),
|
|
987
|
+
padding_pt: z3.number().min(0).max(100).default(0).describe("bbox \uB458\uB808 \uC5EC\uBC31 pt")
|
|
988
|
+
},
|
|
989
|
+
async ({ file_path, output_dir, target, format, pages, padding_pt }) => {
|
|
990
|
+
try {
|
|
991
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
992
|
+
const dir = safeOutputPath(join(output_dir, "regions.json"), /* @__PURE__ */ new Set([".json"])).replace(/[\\/]regions\.json$/, "");
|
|
993
|
+
const { extractRenderedRegions } = await import("./render-NGP5T24S.js");
|
|
994
|
+
const regions = await extractRenderedRegions(buffer, { types: target, format, pages, paddingPt: padding_pt, reflow: true });
|
|
995
|
+
await mkdir2(dir, { recursive: true });
|
|
996
|
+
const ext = format === "jpeg" ? "jpg" : "png";
|
|
997
|
+
const manifest = [];
|
|
998
|
+
for (const r of regions) {
|
|
999
|
+
const name = `${r.region.id.replace("-", "_")}_page_${String(r.page).padStart(3, "0")}.${ext}`;
|
|
1000
|
+
await writeFile2(join(dir, name), r.data);
|
|
1001
|
+
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 });
|
|
935
1002
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
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)) } : {} },
|
|
942
|
-
regions: t.regions,
|
|
943
|
-
crops,
|
|
944
|
-
warnings: t.warnings
|
|
945
|
-
});
|
|
1003
|
+
await writeFile2(join(dir, "regions.json"), JSON.stringify(manifest, null, 2));
|
|
1004
|
+
return { content: [{ type: "text", text: `crop ${regions.length}\uAC74 \u2192 ${dir}
|
|
1005
|
+
` + manifest.map((m) => `${m.file} p${m.page} (${m.bbox.x},${m.bbox.y} ${m.bbox.width}\xD7${m.bbox.height}pt)${m.sourceId ? ` src=${m.sourceId}` : ""}`).join("\n") }] };
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
return { content: [{ type: "text", text: `crop \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
946
1008
|
}
|
|
947
|
-
const json = JSON.stringify(report, null, 2);
|
|
948
|
-
if (dir) await writeFile(join(dir, "tables.json"), json + "\n");
|
|
949
|
-
const kinds = report.reduce((m, r) => {
|
|
950
|
-
m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1;
|
|
951
|
-
return m;
|
|
952
|
-
}, {});
|
|
953
|
-
const head = `\uD45C ${report.length}\uAC1C (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(", ") || "\uC5C6\uC74C"}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}\uAC74${dir ? ` \u2192 ${dir}` : ""}${images.length < report.reduce((n, r) => n + r.crops.length, 0) ? " (\uC751\uB2F5\uC5D0\uB294 8\uC7A5\uAE4C\uC9C0)" : ""}`;
|
|
954
|
-
return { content: [...images, { type: "text", text: `${head}
|
|
955
|
-
${json}` }] };
|
|
956
|
-
} catch (err) {
|
|
957
|
-
return { content: [{ type: "text", text: `\uD45C \uCD94\uCD9C \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
958
1009
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
];
|
|
992
|
-
if (!dry_run && r.hits.length > 0) {
|
|
993
|
-
if (patchable) {
|
|
994
|
-
const original = new Uint8Array(buffer);
|
|
995
|
-
const result = format === "hwp" ? await patchHwp(original, r.text) : await patchHwpx(original, r.text);
|
|
996
|
-
if (!result.success || !result.data) {
|
|
997
|
-
return { content: [{ type: "text", text: `\uB9C8\uC2A4\uD0B9 \uD328\uCE58 \uC2E4\uD328: ${result.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}` }], isError: true };
|
|
998
|
-
}
|
|
999
|
-
await mkdir(dirname(outPath), { recursive: true });
|
|
1000
|
-
await writeFile(outPath, Buffer.from(result.data));
|
|
1001
|
-
lines.push(`\uC800\uC7A5: ${outPath} (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874)`);
|
|
1002
|
-
if (result.skipped.length > 0) {
|
|
1003
|
-
lines.push(`\u26A0\uFE0F \uBBF8\uC801\uC6A9 ${result.skipped.length}\uAC74 \u2014 \uD574\uB2F9 \uC704\uCE58\uB294 \uC6D0\uBB38\uC774 \uB0A8\uC544 \uC788\uC73C\uB2C8 \uBC18\uB4DC\uC2DC \uC218\uB3D9 \uD655\uC778:`);
|
|
1004
|
-
for (const s of result.skipped) lines.push(` - ${s.reason}`);
|
|
1010
|
+
);
|
|
1011
|
+
server2.tool(
|
|
1012
|
+
"extract_tables",
|
|
1013
|
+
"HWPX\xB7HWP \uBB38\uC11C\uC758 \uD45C\uB97C \uCD94\uCD9C\xB7\uBD84\uB958\uD569\uB2C8\uB2E4(#76). \uD45C\uB9C8\uB2E4 semantic-table(\uB370\uC774\uD130\uD45C) / non-tabular-layout(\uC870\uC9C1\uB3C4\xB7\uC5F0\uB77D\uB9DD\xB7\uACB0\uC7AC\uB780\uCC98\uB7FC \uD45C\uB97C \uCE94\uBC84\uC2A4\uB85C \uC4F4 \uAC83) / uncertain \uBD84\uB958\uC640 \uADFC\uAC70 \uC2E0\uD638, \uD398\uC774\uC9C0\xB7bbox(pt, \uB80C\uB354 region \uC870\uC778), \uC815\uCC45(visual)\uC5D0 \uB530\uB978 crop \uC774\uBBF8\uC9C0\uB97C \uB3CC\uB824\uC90D\uB2C8\uB2E4 \u2014 \uC870\uC9C1\uB3C4\uB294 \uC774\uBBF8\uC9C0\uB85C, \uB370\uC774\uD130\uD45C\uB294 \uC140 \uAD6C\uC870\uB85C \uB118\uAE30\uB294 \uBA40\uD2F0\uBAA8\uB2EC \uD30C\uC774\uD504\uB77C\uC778\uC6A9. \uD734\uB9AC\uC2A4\uD2F1(\uB124\uD2B8\uC6CC\uD06C\xB7LLM \uC5C6\uC74C), \uC911\uCCA9\uD45C\uB3C4 \uB3C5\uB9BD \uBD84\uB958. crop \uC740 output_dir \uC5D0 \uC800\uC7A5\uD558\uACE0 8\uC7A5\uAE4C\uC9C0 \uC751\uB2F5\uC5D0 \uD568\uAED8 \uB2F4\uC2B5\uB2C8\uB2E4.",
|
|
1014
|
+
{
|
|
1015
|
+
file_path: z3.string().min(1).describe("HWPX \uB610\uB294 HWP(5.x) \uD30C\uC77C \uC808\uB300 \uACBD\uB85C"),
|
|
1016
|
+
output_dir: z3.string().min(1).optional().describe("crop \uD30C\uC77C\xB7tables.json \uC800\uC7A5 \uB514\uB809\uD1A0\uB9AC (visual \uC774 none \uC774 \uC544\uB2C8\uBA74 \uD544\uC218)"),
|
|
1017
|
+
visual: z3.enum(["none", "non-tabular", "non-tabular-and-uncertain", "all"]).default("none").describe("crop \uB300\uC0C1: none=\uBD84\uB958\xB7bbox \uB9CC / non-tabular=\uC870\uC9C1\uB3C4\uB958\uB9CC / non-tabular-and-uncertain(\uAD8C\uC7A5) / all"),
|
|
1018
|
+
format: z3.enum(["png", "jpeg"]).default("png"),
|
|
1019
|
+
padding_pt: z3.number().min(0).max(100).default(0).describe("crop \uB458\uB808 \uC5EC\uBC31 pt"),
|
|
1020
|
+
cells: z3.boolean().default(false).describe("\uC751\uB2F5 JSON \uC5D0 \uC140 \uD14D\uC2A4\uD2B8 \uACA9\uC790 \uD3EC\uD568")
|
|
1021
|
+
},
|
|
1022
|
+
async ({ file_path, output_dir, visual, format, padding_pt, cells }) => {
|
|
1023
|
+
try {
|
|
1024
|
+
if (visual !== "none" && !output_dir) {
|
|
1025
|
+
return { content: [{ type: "text", text: "visual \uC774 none \uC774 \uC544\uB2C8\uBA74 crop \uD30C\uC77C\uC744 \uC800\uC7A5\uD560 output_dir \uC774 \uD544\uC694\uD569\uB2C8\uB2E4." }], isError: true };
|
|
1026
|
+
}
|
|
1027
|
+
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, /* @__PURE__ */ new Set([".hwpx", ".hwp"]));
|
|
1028
|
+
const dir = output_dir ? safeOutputPath(join(output_dir, "tables.json"), /* @__PURE__ */ new Set([".json"])).replace(/[\\/]tables\.json$/, "") : void 0;
|
|
1029
|
+
const { extractTables } = await import("./visual-NZLYIYEM.js");
|
|
1030
|
+
const tables = await extractTables(buffer, { policy: visual, format, paddingPt: padding_pt });
|
|
1031
|
+
if (dir) await mkdir2(dir, { recursive: true });
|
|
1032
|
+
const ext = format === "jpeg" ? "jpg" : "png";
|
|
1033
|
+
const images = [];
|
|
1034
|
+
const report = [];
|
|
1035
|
+
for (const t of tables) {
|
|
1036
|
+
const crops = [];
|
|
1037
|
+
for (const c of t.crops) {
|
|
1038
|
+
const name = `${t.id.replace(/[^\w.-]/g, "_")}_page_${String(c.page).padStart(3, "0")}.${ext}`;
|
|
1039
|
+
if (dir) await writeFile2(join(dir, name), c.data);
|
|
1040
|
+
if (images.length < 8) images.push({ type: "image", data: c.data.toString("base64"), mimeType: c.mimeType });
|
|
1041
|
+
crops.push({ file: dir ? name : void 0, page: c.page, bbox: c.bbox });
|
|
1005
1042
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1043
|
+
report.push({
|
|
1044
|
+
id: t.id,
|
|
1045
|
+
sourceId: t.sourceId,
|
|
1046
|
+
page: t.page,
|
|
1047
|
+
classification: t.classification,
|
|
1048
|
+
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)) } : {} },
|
|
1049
|
+
regions: t.regions,
|
|
1050
|
+
crops,
|
|
1051
|
+
warnings: t.warnings
|
|
1052
|
+
});
|
|
1011
1053
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
)
|
|
1022
|
-
|
|
1023
|
-
"parse_chunks",
|
|
1024
|
-
"\uBB38\uC11C\uB97C RAG\uC6A9 \uAD6C\uC870 \uCCAD\uD06C JSON\uC73C\uB85C \uD30C\uC2F1\uD569\uB2C8\uB2E4. \uD5E4\uB529\xB7\uAC1C\uC870\uC2DD \uC704\uACC4(\u25A1\u25CB- / 1.\xB7\uAC00.\xB71))\uAC00 breadcrumb \uACBD\uB85C\uB85C \uBCF4\uC874\uB418\uACE0 \uD45C\uB294 \uB3C5\uB9BD \uCCAD\uD06C\uB85C \uB098\uC635\uB2C8\uB2E4 \u2014 \uC784\uBCA0\uB529\xB7\uC778\uB371\uC2F1 \uC804\uCC98\uB9AC\uC6A9. \uC790\uB974\uAE30(\uD1A0\uD070 \uC0C1\uD55C\xB7\uC624\uBC84\uB7A9)\uB294 \uC18C\uBE44\uC790 \uBAAB\uC785\uB2C8\uB2E4.",
|
|
1025
|
-
{
|
|
1026
|
-
file_path: z.string().min(1).describe("\uB300\uC0C1 \uBB38\uC11C\uC758 \uC808\uB300 \uACBD\uB85C (HWP/HWPX/PDF/XLSX/DOCX)"),
|
|
1027
|
-
granularity: z.enum(["section", "block"]).default("section").describe("section=\uAC19\uC740 breadcrumb \uC544\uB798 \uC5F0\uC18D \uD14D\uC2A4\uD2B8 \uBCD1\uD569(\uAE30\uBCF8), block=IRBlock 1\uAC1C=\uCCAD\uD06C 1\uAC1C"),
|
|
1028
|
-
include_table_cells: z.boolean().default(false).describe("\uD45C \uCCAD\uD06C\uC5D0 \uC140 \uD14D\uC2A4\uD2B8 2\uCC28\uC6D0 \uBC30\uC5F4 \uD3EC\uD568 \uC5EC\uBD80")
|
|
1029
|
-
},
|
|
1030
|
-
async ({ file_path, granularity, include_table_cells }) => {
|
|
1031
|
-
try {
|
|
1032
|
-
const { buffer } = await readValidatedFile(file_path, MAX_FILE_SIZE, PARSE_EXTENSIONS);
|
|
1033
|
-
const parsed = await parse(buffer, { filePath: file_path });
|
|
1034
|
-
if (!parsed.success) {
|
|
1035
|
-
return { content: [{ type: "text", text: `\uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}` }], isError: true };
|
|
1054
|
+
const json = JSON.stringify(report, null, 2);
|
|
1055
|
+
if (dir) await writeFile2(join(dir, "tables.json"), json + "\n");
|
|
1056
|
+
const kinds = report.reduce((m, r) => {
|
|
1057
|
+
m[r.classification.kind] = (m[r.classification.kind] ?? 0) + 1;
|
|
1058
|
+
return m;
|
|
1059
|
+
}, {});
|
|
1060
|
+
const head = `\uD45C ${report.length}\uAC1C (${Object.entries(kinds).map(([k, v]) => `${k} ${v}`).join(", ") || "\uC5C6\uC74C"}) crop ${report.reduce((n, r) => n + r.crops.length, 0)}\uAC74${dir ? ` \u2192 ${dir}` : ""}${images.length < report.reduce((n, r) => n + r.crops.length, 0) ? " (\uC751\uB2F5\uC5D0\uB294 8\uC7A5\uAE4C\uC9C0)" : ""}`;
|
|
1061
|
+
return { content: [...images, { type: "text", text: `${head}
|
|
1062
|
+
${json}` }] };
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
return { content: [{ type: "text", text: `\uD45C \uCD94\uCD9C \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
1036
1065
|
}
|
|
1037
|
-
const { blocksToChunks } = await import("./chunks-PEHRXW2P.js");
|
|
1038
|
-
const chunks = blocksToChunks(parsed.blocks, { granularity, includeTableCells: include_table_cells });
|
|
1039
|
-
return { content: [{ type: "text", text: capResponseText(JSON.stringify(chunks, null, 2)) }] };
|
|
1040
|
-
} catch (err) {
|
|
1041
|
-
return { content: [{ type: "text", text: `\uCCAD\uD06C \uD30C\uC2F1 \uC2E4\uD328: ${describeError(err)}` }], isError: true };
|
|
1042
1066
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/mcp/tools-generate.ts
|
|
1071
|
+
import { z as z4 } from "zod";
|
|
1072
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, realpath as realpath3 } from "fs/promises";
|
|
1073
|
+
import { resolve as resolve2, dirname as dirname4, join as join2 } from "path";
|
|
1074
|
+
function registerGenerateTools(server2) {
|
|
1075
|
+
server2.tool(
|
|
1076
|
+
"extract_profile",
|
|
1077
|
+
'\uCC38\uC870 HWPX \uBB38\uC11C\uC5D0\uC11C \uD45C \uC11C\uC2DD \uD504\uB85C\uD544(\uD14C\uB450\uB9AC\xB7\uC74C\uC601\xB7\uC5F4 \uB108\uBE44\xB7\uC140 \uAE00\uAF34)\uC744 JSON\uC73C\uB85C \uCD94\uCD9C\uD569\uB2C8\uB2E4. \uCD94\uCD9C\uD55C \uD504\uB85C\uD544\uC744 generate_document\uC758 profile_path\uB85C \uB118\uAE30\uBA74 \uC6D0\uBCF8 \uBB38\uC11C \uC5C6\uC774 \uAC19\uC740 \uD45C \uC11C\uC2DD\uC744 \uC7AC\uD604\uD569\uB2C8\uB2E4 \u2014 "\uC774 \uBB38\uC11C \uD45C \uC11C\uC2DD \uADF8\uB300\uB85C \uB9CC\uB4E4\uC5B4\uC918" \uC6CC\uD06C\uD50C\uB85C\uC758 1\uB2E8\uACC4.',
|
|
1078
|
+
{
|
|
1079
|
+
hwpx_path: z4.string().min(1).describe("\uC11C\uC2DD\uC744 \uCD94\uCD9C\uD560 \uCC38\uC870 HWPX \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C"),
|
|
1080
|
+
output_path: z4.string().min(1).describe("\uD504\uB85C\uD544 JSON \uCD9C\uB825 \uC808\uB300 \uACBD\uB85C (.json \uAD8C\uC7A5)")
|
|
1081
|
+
},
|
|
1082
|
+
async ({ hwpx_path, output_path }) => {
|
|
1083
|
+
try {
|
|
1084
|
+
const out = safeOutputPath(output_path, PROFILE_EXTENSIONS);
|
|
1085
|
+
const { buffer } = await readValidatedFile(hwpx_path);
|
|
1086
|
+
const { hwpxToProfile } = await import("./-AQKXLFIM.js");
|
|
1087
|
+
const profile = await hwpxToProfile(buffer);
|
|
1088
|
+
await mkdir3(dirname4(out), { recursive: true });
|
|
1089
|
+
await writeFile3(out, JSON.stringify(profile, null, 2));
|
|
1090
|
+
return {
|
|
1091
|
+
content: [{ type: "text", text: `\uC11C\uC2DD \uD504\uB85C\uD544 \uCD94\uCD9C \uC644\uB8CC: \uD45C ${profile.tables.length}\uAC1C \u2192 ${out}
|
|
1062
1092
|
(generate_document\uC758 profile_path\uB85C \uC0AC\uC6A9)` }]
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
);
|
|
1072
|
-
server.tool(
|
|
1073
|
-
"generate_document",
|
|
1074
|
-
"\uB9C8\uD06C\uB2E4\uC6B4\uC744 HWPX \uD55C\uAE00 \uBB38\uC11C\uB85C \uC0DD\uC131\uD569\uB2C8\uB2E4. \"\uBCF4\uACE0\uC11C\uB85C/\uACF5\uBB38\uC11C\uB85C/\uAC1C\uC870\uC2DD\uC73C\uB85C/\uACC4\uD68D\uC11C\uB85C \uBF51\uC544\uC918\xB7\uB9CC\uB4E4\uC5B4\uC918\" \uC694\uCCAD\uC774 \uC774 \uB3C4\uAD6C\uC785\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uB9E4\uD551: \uC815\uBD80 \uD45C\uC900 \uBCF4\uACE0\uC11C(\uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uB85C\uB9C8\uC22B\uC790 \uC7A5\uD5E4\uB354 \uC790\uB3D9)='\uAC1C\uC870\uC2DD', \uC911\uC559\uBD80\uCC98 \uC5C5\uBB34\uBCF4\uACE0\xB7\uAD6D\uD68C \uC11C\uBA74\uBCF4\uACE0(\uC7AC\uACBD\uBD80 \uC2E4\uCE21: \uC7A5 \uB760\xB7\uC808 \uC22B\uC790\uCE78\xB7\uC18C\uC81C\uBAA9 \uBC15\uC2A4\xB7\u2460 \uD56D\uBAA9 \uB760\xB7\uC5F0\uB178\uB791 \uC131\uACFC \uC694\uC57D\uBC15\uC2A4\xB7\uBCC4\uCCA8 \uB760, \u25A1 \uB4A4 (\uD0A4\uC6CC\uB4DC) \uD30C\uB791)='\uC5C5\uBB34\uBCF4\uACE0', \uAE30\uC548\uBB38\xB7\uC2DC\uD589\uBB38\xB7\uC54C\uB9BC\uACF5\uBB38='\uAE30\uC548\uBB38', 1\uD398\uC774\uC9C0 \uC694\uC57D\uBCF4\uACE0\uC11C='\uBCF4\uACE0\uC11C', \uCD94\uC9C4\uACC4\uD68D='\uACC4\uD68D\uC11C'. \uD45C\uB294 \uC2E4\uCE21 \uC815\uBD80 \uC11C\uC2DD(\uD5E4\uB354 \uC74C\uC601+\uC774\uC911\uC120\xB7\uC678\uACFD \uAD75\uC740\uC120\xB7\uB0B4\uC6A9 \uBE44\uB840 \uC5F4\uD3ED), \uCABD\uBC88\uD638\xB7\uACB0\uC7AC\uB780\xB7'\uB05D.' \uD45C\uC2DC \uC9C0\uC6D0. \u26A0 \uC0DD\uC131 \uC804 \uD655\uC778 \uAD8C\uC7A5: \uBB38\uC11C\uC885\uB958(\uBCF4\uACE0\uC11C/\uAE30\uC548\uBB38)\xB7\uC81C\uBAA9\xB7\uAE30\uAD00\uBA85(org)\xB7\uB0A0\uC9DC\xB7\uBAA9\uCC28 \uC5EC\uBD80\uAC00 \uBD88\uBA85\uD655\uD558\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3C\uC5B4\uBCF4\uC138\uC694 \u2014 \uC5C9\uB6B1\uD55C \uD504\uB9AC\uC14B \uC120\uD0DD\uC774 \uAC00\uC7A5 \uD754\uD55C \uC624\uC0DD\uC131 \uC6D0\uC778. \uB9C8\uD06C\uB2E4\uC6B4 \uADDC\uCE59(v4.13 \uC11C\uC6B8 \uC2E4\uACB0\uC7AC \uC2E4\uCE21 \uC704\uACC4): #(h1)=\uBB38\uC11C \uC81C\uBAA9, ##(h2)=\uC7A5(\uBCF4\uACE0\uC11C \u2160 \u2161 / \uAE30\uC548\uBB38\xB7\uD1B5\uC9C0\uB294 \uBC95\uC815 1.), ###(h3)=\u25A1 \uB300\uD56D\uBAA9(\uAE30\uC548\uBB38 \uAC00.), \uADF8 \uC544\uB798 \uB9AC\uC2A4\uD2B8=\u3147 \u2192 - \u2192 \u318D(\uAE30\uC548\uBB38 \uAC00. \u2192 1) \u2192 \uAC00)), \uBCF8\uBB38\uC5D0 \u25A1/\u3147/-/1./\uAC00. \uB97C \uC9C1\uC811 \uC368\uB3C4 \uAC19\uC740 \uC704\uACC4\uB85C \uC815\uADDC\uD654, \u203B\uC2DC\uC791\xB7'\uCD9C\uCC98:'\xB7'\uC790\uB8CC:'=\uCC38\uACE0(13pt), \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(>)=\uBCF4\uACE0\uC11C \uC694\uC57D\uBC15\uC2A4 \u2014 \u2605\uBCF4\uACE0\uC11C\uB294 \uBC18\uB4DC\uC2DC \uC81C\uBAA9 \uC9C1\uD6C4 `> \u2026\uD558\uACE0\uC790 \uD568` \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9\xB7\uBD80\uD638 \uC5C6\uC74C\xB73\uC904 \uC774\uB0B4 \uC57D 90~100\uC790)\uB85C \uBCF4\uACE0 \uBAA9\uC801\uC744 \uB123\uC744 \uAC83(\uC5C6\uAC70\uB098 3\uC904 \uCD08\uACFC\uBA74 \uACBD\uACE0), <right>\uD14D\uC2A4\uD2B8</right>=\uC6B0\uCE21\uC815\uB82C. \u25A1\xB7\uC81C\uBAA9\uC740 \uD55C \uC904\uC5D0 \uC790\uB3D9 \uCD95\uC18C, \uB458\uC9F8 \uC904 20% \uC774\uB0B4 \uACE0\uC544 \uC904\uC740 \uC790\uAC04 \uCD95\uC18C\uB85C \uD55C \uC904. \uBC95\uB839 \uCF54\uB4DC (282791)\xB7KOSIS \uD45C ID DT_\u2026\xB7(\uBC95\uC815\uB3D9\uCF54\uB4DC \u2026)\xB7\u25CB\u25CB MCP \uC870\uD68C \uAC19\uC740 \uB0B4\uBD80 \uC2DD\uBCC4\uC790\xB7\uB3C4\uAD6C \uC5B8\uAE09\uC740 \uC790\uB3D9 \uC81C\uAC70 \u2014 \uCD9C\uCC98\uB294 \uAE30\uAD00\xB7\uC790\uB8CC\uBA85\uB9CC \uC4F8 \uAC83. (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874 \uC81C\uC790\uB9AC \uC218\uC815\uC740 patch_document, \uC11C\uC2DD \uBE48\uCE78 \uCC44\uC6B0\uAE30\uB294 fill_form)",
|
|
1075
|
-
{
|
|
1076
|
-
markdown: z.string().min(1).describe("HWPX\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uC804\uBB38. \uD45C\uB294 GFM \uBB38\uBC95 \uC0AC\uC6A9 (\uC608: '| \uC774\uB984 | \uBD80\uC11C |\\n| --- | --- |\\n| \uD64D\uAE38\uB3D9 | \uAE30\uD68D\uD300 |')"),
|
|
1077
|
-
output_path: z.string().min(1).describe("\uCD9C\uB825 HWPX \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C (.hwpx \uAD8C\uC7A5)"),
|
|
1078
|
-
profile_path: z.string().optional().describe("\uC11C\uC2DD \uD504\uB85C\uD544 JSON \uACBD\uB85C (extract_profile\uB85C \uCD94\uCD9C) \u2014 \uCC38\uC870 \uBB38\uC11C\uC758 \uD45C \uD14C\uB450\uB9AC\xB7\uC74C\uC601\xB7\uC5F4\uD3ED\xB7\uC140 \uAE00\uAF34\uC744 \uC7AC\uD604. \uD45C \uD589\xB7\uC5F4 \uC218\uC640 \uCCAB \uC140 \uD14D\uC2A4\uD2B8\uAC00 \uC77C\uCE58\uD558\uB294 \uD45C\uC5D0\uB9CC \uC801\uC6A9"),
|
|
1079
|
-
// 값 집합·범위는 gongmun-surface SSOT에서 파생 (CLI와 드리프트 불가 — v4.0.4 영역1-1)
|
|
1080
|
-
preset: z.enum(Object.keys(PRESET_ALIAS)).optional().describe("\uACF5\uBB38\uC11C \uD504\uB9AC\uC14B \u2014 \uC9C0\uC815 \uC2DC \uD55C\uAD6D \uD589\uC815 \uACF5\uBB38\uC11C \uD45C\uC900 \uC11C\uC2DD \uC801\uC6A9. '\uAC1C\uC870\uC2DD'=\uC815\uBD80 \uD45C\uC900 \uAC1C\uC870\uC2DD \uBCF4\uACE0\uC11C(\uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uB85C\uB9C8\uC22B\uC790 \uC7A5 \uD5E4\uB354 \uC790\uB3D9 + \u25A1\u25CB-\u203B \uBD80\uD638\uBCC4 \uD3F0\uD2B8), '\uC5C5\uBB34\uBCF4\uACE0'=\uC911\uC559\uBD80\uCC98 \uC5C5\uBB34\uBCF4\uACE0(##=\u2160 \uC7A5 \uB760, ###=\uD30C\uB780 \uC22B\uC790\uCE78 \uC808, ####=\uB0A8\uC0C9 \uC18C\uC81C\uBAA9 \uBC15\uC2A4, #####=\u2460 \uD558\uB298\uC0C9 \uD56D\uBAA9 \uB760, > \u25AA\u2026=\uC5F0\uB178\uB791 \uC131\uACFC \uC694\uC57D\uBC15\uC2A4, ## \uBCC4\uCCA8 \u2026=\uBCC4\uCCA8 \uB760, \u2776\u21D2 \uBD80\uD638 \uBCF4\uC874, \uD568\uCD08\uB86C\uBC14\uD0D5 15\xB7\uAC01\uC8FC \uB9D1\uC740 \uACE0\uB515 12), '\uBCF4\uB3C4\uC790\uB8CC'=\uBA38\uB9AC\uBC15\uC2A4+\uC81C\uBAA9 25pt+\u25A1\u2192\u3147\u2192*(\uAC01\uC8FC) \uCCB4\uACC4. \uBBF8\uC9C0\uC815 \uC2DC \uBC94\uC6A9 \uB9C8\uD06C\uB2E4\uC6B4 \uBCC0\uD658"),
|
|
1081
|
-
font: z.enum(BODY_FONTS).optional().describe("\uBCF8\uBB38 \uAE00\uAF34(\uACF5\uBB38\uC11C \uBAA8\uB4DC): myeongjo=\uBA85\uC870 \uACC4\uC5F4(\uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\uB294 \uC2E4\uCE21 \uD734\uBA3C\uBA85\uC870, \uADF8 \uC678 \uD568\uCD08\uB86C\uBC14\uD0D5), gothic=\uB9D1\uC740 \uACE0\uB515"),
|
|
1082
|
-
body_pt: z.number().int().min(BODY_PT_RANGE.min).max(BODY_PT_RANGE.max).optional().describe("\uBCF8\uBB38 \uAE00\uC790 \uD06C\uAE30(pt, \uACF5\uBB38\uC11C \uBAA8\uB4DC). \uAE30\uBCF8: \uAE30\uC548\uBB38 12, \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uD1B5\uC9C0 15"),
|
|
1083
|
-
line_spacing: z.number().int().min(LINE_SPACING_RANGE.min).max(LINE_SPACING_RANGE.max).optional().describe("\uBCF8\uBB38 \uC904\uAC04\uACA9(%, \uACF5\uBB38\uC11C \uBAA8\uB4DC). \uAE30\uBCF8: \uD504\uB9AC\uC14B\uBCC4 \uC2E4\uCE21\uAC12(\uAE30\uC548\uBB38 160, \uD68C\uC758\uB85D 130 \uB4F1)"),
|
|
1084
|
-
org: z.string().optional().describe("\uD45C\uC9C0 \uAE30\uAD00\uBA85 (\uD45C\uC9C0\uB97C \uCF1C\uB294 \uBAA8\uB4E0 \uD504\uB9AC\uC14B\uC5D0\uC11C \uC0AC\uC6A9 \uAC00\uB2A5). \uBBF8\uC9C0\uC815 \uC2DC \uD45C\uC9C0\uC5D0 \uAE30\uAD00\uBA85 \uC0DD\uB7B5"),
|
|
1085
|
-
date: z.string().optional().describe("\uD45C\uC9C0 \uB0A0\uC9DC ('YYYY. M. D.' \uD45C\uAE30 \uAD8C\uC7A5). \uBBF8\uC9C0\uC815 \uC2DC \uC624\uB298 \uB0A0\uC9DC"),
|
|
1086
|
-
toc: z.boolean().optional().describe("\uBAA9\uCC28 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC5EC\uBD80 \u2014 h2 \uBAA9\uB85D\uC744 \u2160 \u2161 \u2162 \uC7A5\uC73C\uB85C \uC790\uB3D9 \uAD6C\uC131. \uC804 \uD504\uB9AC\uC14B \uC0AC\uC6A9 \uAC00\uB2A5(\uBCF4\uB3C4\uC790\uB8CC \uC81C\uC678). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B\uB9CC \uCF1C\uC9D0"),
|
|
1087
|
-
cover: z.boolean().optional().describe("\uD45C\uC9C0 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC5EC\uBD80 \u2014 \uCCAB h1\uC744 \uC81C\uBAA9\uC73C\uB85C \uD30C\uB791 \uC7A5\uC2DD \uD45C\uC9C0. \uC804 \uD504\uB9AC\uC14B \uC0AC\uC6A9 \uAC00\uB2A5(\uBCF4\uB3C4\uC790\uB8CC \uC81C\uC678 \u2014 \uBA38\uB9AC\uBC15\uC2A4 \uC11C\uC2DD\uACFC \uC591\uB9BD \uBD88\uAC00). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B\uB9CC \uCF1C\uC9D0 (org/date \uC9C0\uC815 \uC2DC \uC790\uB3D9 \uCF1C\uC9D0)"),
|
|
1088
|
-
approval: z.array(z.string()).max(APPROVAL_MAX).optional().describe("\uACB0\uC7AC\uB780 \uC9C1\uC704 \uB77C\uBCA8 (\uCD5C\uB300 6\uAC1C, \uC608: ['\uB2F4\uB2F9','\uD300\uC7A5','\uACFC\uC7A5']) \u2014 \uBB38\uC11C \uCD5C\uC0C1\uB2E8 \uC6B0\uCE21\uC5D0 \uC11C\uBA85 \uACF5\uB780 \uACB0\uC7AC \uD45C \uC0DD\uC131"),
|
|
1089
|
-
page_numbers: z.boolean().optional().describe("\uCABD\uBC88\uD638(\uD558\uB2E8 \uC911\uC559 '- 1 -', \uD45C\uC9C0\xB7\uBAA9\uCC28 \uCE74\uC6B4\uD2B8 \uC81C\uC678). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uCF1C\uC9D0"),
|
|
1090
|
-
end_mark: z.boolean().optional().describe("\uBCF8\uBB38 \uB05D '\uB05D.' \uD45C\uC2DC (\uD589\uC815\uC5C5\uBB34\uADDC\uC815). \uBBF8\uC9C0\uC815 \uC2DC \uAE30\uC548\uBB38\uB9CC \uCF1C\uC9D0, \uBCF8\uBB38\uC774 \uC774\uBBF8 '\uB05D.'\uC73C\uB85C \uB05D\uB098\uBA74 \uC911\uBCF5 \uC0DD\uC131 \uC548 \uD568"),
|
|
1091
|
-
body_title_box: z.boolean().optional().describe("\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4 (\uAC1C\uC870\uC2DD \uC2E4\uCE21 \uAD00\uD589). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD+\uD45C\uC9C0 \uC870\uD569\uC5D0\uC11C \uCF1C\uC9D0"),
|
|
1092
|
-
h2_marker: z.enum(H2_MARKERS).optional().describe("h2 \uC7A5 \uC81C\uBAA9 \uD45C\uAE30: band=\uB85C\uB9C8\uC790 \uCC44\uC6C0 \uCE78+\uC81C\uBAA9 \uB760 \uD45C(\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8), roman='\u2160. \uC81C\uBAA9' \uD14D\uC2A4\uD2B8, number='1. \uC81C\uBAA9'(\uD1B5\uC9C0 \uAE30\uBCF8), box=\uC7A5 \uC5C6\uC774 \u25A1 \uB300\uD56D\uBAA9\uC73C\uB85C, none=\uBC88\uD638 \uC5C6\uC74C. \uAE30\uC548\uBB38 \uBCF8\uBB38\uC758 h2\uB294 \uD56D\uC0C1 \uBC95\uC815 '1.' \uD56D\uBAA9"),
|
|
1093
|
-
band_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("\uB760 \uC81C\uBAA9 \uBC88\uD638\uCE78 \uCC44\uC6C0\uC0C9 #RRGGBB (\uAE30\uBCF8 #003366 \uC2E4\uCE21 \uCD5C\uB2E4. \uAD50\uC721\uCCAD\uD615 \uBC1D\uC740 \uB760\uB294 #DFE6F7 + band_text_color #000000)"),
|
|
1094
|
-
band_text_color: z.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("\uB760 \uC81C\uBAA9 \uBC88\uD638 \uAE00\uC790\uC0C9 #RRGGBB (\uAE30\uBCF8 #FFFFFF)"),
|
|
1095
|
-
summary: z.string().optional().describe("\uBCF4\uACE0\uC11C \uC694\uC57D \uBC15\uC2A4 \u2014 \uC81C\uBAA9\uD45C \uC544\uB798 #DFE6F7 \uC74C\uC601 \uC0C1\uC790(\uC11C\uC6B8 \uC2E4\uACB0\uC7AC \uAD00\uD589). \uB9C8\uD06C\uB2E4\uC6B4 \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(> \u2026)\uC73C\uB85C\uB3C4 \uC9C0\uC815 \uAC00\uB2A5"),
|
|
1096
|
-
doc_info: z.object(Object.fromEntries(DOC_INFO_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uBCF4\uACE0\uC11C \uD45C\uC9C0 \uBB38\uC11C\uC815\uBCF4\uD45C \u2014 docNum=\uBB38\uC11C\uBC88\uD638/date=\uACB0\uC7AC\uC77C\uC790/disclosure=\uACF5\uAC1C\uC5EC\uBD80/policyNo=\uBC29\uCE68\uBC88\uD638 (cover=true\uC640 \uD568\uAED8)"),
|
|
1097
|
-
dept: z.string().optional().describe("\uD45C\uC9C0 \uBD80\uC11C\uBA85 \u2014 \uAE30\uAD00\uBA85 \uC544\uB798 '(\uC2A4\uB9C8\uD2B8\uB3C4\uC2DC\uACFC)' (cover\uC640 \uD568\uAED8)"),
|
|
1098
|
-
cover_label: z.string().optional().describe("\uD45C\uC9C0 \uC6B0\uC0C1\uB2E8 \uCDE8\uAE09 \uD45C\uC2DC \u2014 '\uB300\uC678\uC8FC\uC758'\xB7'\uBE44\uACF5\uAC1C' \uBE68\uAC04 \uD14C\uB450\uB9AC \uBC15\uC2A4 (\uC5C5\uBB34\uBCF4\uACE0 \uD504\uB9AC\uC14B \uC2E4\uCE21, cover\uC640 \uD568\uAED8)"),
|
|
1099
|
-
fonts: z.object(Object.fromEntries(FONT_ROLE_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uC694\uC18C\uBCC4 \uAE00\uAF34 \uC624\uBC84\uB77C\uC774\uB4DC(\uACF5\uBB38\uC11C \uBAA8\uB4DC) \u2014 body=\uBCF8\uBB38(\u25CB\xB7-)/heading=\uC81C\uBAA9 \uACC4\uC5F4(\u25A1\xB7\uC7A5\uD5E4\uB354\xB7\uD45C\uC9C0\xB7\uBAA9\uCC28)/ref=\u203B \uCC38\uACE0/table=\uD45C \uC140. \uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\uB294 \uB124 \uC5ED\uD560 \uC804\uBD80, \uADF8 \uC678 \uD504\uB9AC\uC14B\uC740 body\uB9CC \uC801\uC6A9"),
|
|
1100
|
-
sizes: z.object(Object.fromEntries(SIZE_KEYS.map((k) => [k, z.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional()]))).optional().describe("\uAC1C\uC870\uC2DD \uC694\uC18C\uBCC4 \uAE00\uC790 \uD06C\uAE30(pt) \uC624\uBC84\uB77C\uC774\uB4DC \u2014 dae=\u25A1/cham=\u203B/chapter=\uC7A5\uD5E4\uB354/coverTitle\xB7coverSub=\uD45C\uC9C0/tocLabel\xB7tocRoman\xB7tocItem=\uBAA9\uCC28/table=\uD45C \uC140/bodyTitle=\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4. \uBBF8\uC9C0\uC815 \uC694\uC18C\uB294 body_pt \uBE44\uB840 \uAE30\uBCF8\uAC12"),
|
|
1101
|
-
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()])))).optional().describe('\uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uBCC4 \uC704\uACC4 \uD0C0\uC774\uD3EC(\uACF5\uBB38\uC11C \uBAA8\uB4DC, v4.12.3) \u2014 {"0":{font:"HY\uACAC\uACE0\uB515",pt:17,bold:true},"1":{font:"\uD55C\uCEF4\uB3CB\uC6C0",bold:true}} \uAF34(depth 0~7). \uC2E4\uCE21: \uC804\uC790\uACB0\uC7AC \uAE30\uC548\uBB38 \u25A1/\u3147/- \uACC4\uC5F4\uC740 \u25A1=HY\uACAC\uACE0\uB515 +2~3pt \uAD75\uAC8C\xB7\u3147=\uD55C\uCEF4\uB3CB\uC6C0 \uAD75\uAC8C\xB7-=\uD734\uBA3C\uBA85\uC870 \uBCF8\uBB38. \uBC95\uC815 8\uB2E8\uACC4(1. \uAC00.)\uB294 \uBCF8\uBB38 \uB3D9\uC77C\uC774 \uAD00\uD589\uC774\uB77C \uAE30\uBCF8 \uBBF8\uC801\uC6A9'),
|
|
1102
|
-
bullet2: z.enum(BULLET2_CHARS).optional().describe("2\uB2E8\uACC4 \uD56D\uBAA9\uBD80\uD638 \u2014 '\u3147'(\uC774\uC751, \uC804\uC790\uACB0\uC7AC \uAE30\uC548\uBB38\xB7\uACF5\uACE0\uBB38 \uC2E4\uCE21 \uC9C0\uBC30) / '\u25CB'(\uC6D0, \uBCF4\uACE0\uC11C \uC591\uC2DD). \uBBF8\uC9C0\uC815 \uC2DC \uD1B5\uC9C0\xB7\uBCF4\uB3C4\uC790\uB8CC \u3147, \uADF8 \uC678 \u25CB"),
|
|
1103
|
-
suppress_single: z.boolean().optional().describe("\uB2E8\uC77C \uD615\uC81C \uD56D\uBAA9 \uBD80\uD638 \uC0DD\uB7B5(\uD3B8\uB78C \uADDC\uC815, \uBC95\uC815 \uBC88\uD638 standard \uC804\uC6A9 \u2014 \uBD88\uB9BF \uCCB4\uACC4\uC778 \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uAC1C\uC870\uC2DD\xB7\uBCF4\uB3C4\uC790\uB8CC\uC5D4 \uBB34\uD6A8). \uAE30\uBCF8 false \u2014 \uD558\uB098\uBFD0\uC778 \uD56D\uBAA9\uC5D0\uB3C4 \uBD80\uD638(1. \uAC00.)\uB97C \uBD80\uC5EC (\uBD80\uD638 \uC5C6\uB294 \uACC4\uB2E8 \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC2E4\uBB34 \uB208\uC5D0 \uC5B4\uC0C9)"),
|
|
1104
|
-
doc_head: z.object(Object.fromEntries(DOC_HEAD_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uB450\uBB38\uD45C(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD\xB7\uC11C\uC6B8 \uC2E4\uACB0\uC7AC 6\uD589 \uD45C) \u2014 org=\uD589\uC815\uAE30\uAD00\uBA85(\uAD74\uB9BC 20pt bold \uC790\uAC04\uB744\uC6C0)/slogan=\uC6D0\uD6C8(\uC0C1\uB2E8 10pt)/to=\uC218\uC2E0('\uB0B4\uBD80\uACB0\uC7AC'\uBA74 \uBC1C\uC2E0\uBA85\uC758 \uC0DD\uB7B5)/via=\uACBD\uC720/title=\uC81C\uBAA9(\uBBF8\uC9C0\uC815 \uC2DC \uCCAB h1). \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1105
|
-
doc_foot: z.object(Object.fromEntries(DOC_FOOT_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uACB0\uBB38\uD45C \u2014 sender=\uBC1C\uC2E0\uBA85\uC758(18pt bold \uC911\uC559)/drafter\xB7reviewer\xB7approver='\uC9C1\uC704 \uC131\uBA85' \uACB0\uC7AC\uC120/cooperator=\uD611\uC870\uC790/recipients=\uC218\uC2E0\uC790 \uBAA9\uB85D/docNum=\uC2DC\uD589 '\uACFC-\uBC88\uD638 (\uB0A0\uC9DC)'/receive=\uC811\uC218/zip\xB7address\xB7site/phone\xB7fax\xB7email/disclosure=\uACF5\uAC1C\uAD6C\uBD84. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1106
|
-
report_info: z.string().optional().describe("\uBCF4\uACE0\uC11C: \uC81C\uBAA9\uD45C \uC544\uB798 \uB2F4\uB2F9\uC790 \uD589 '(2026. 9. 6., \uC2A4\uB9C8\uD2B8\uB3C4\uC2DC\uACFC \uD64D\uAE38\uB3D9, \u260E450-1234)' / \uAE30\uC548\uBB38: \uC6B0\uC0C1\uB2E8 12pt \uBCF4\uACE0\uC815\uBCF4 \uD589"),
|
|
1107
|
-
notice_head: z.object(Object.fromEntries(NOTICE_HEAD_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uACF5\uACE0\uBB38 \uB450\uBB38\xB7\uACB0\uBB38 \u2014 no=\uACF5\uACE0\uBC88\uD638(\uBCF8\uBB38 \uC704 bold)/date=\uB0A0\uC9DC(\uBCF8\uBB38 \uC544\uB798 \uC6B0\uCE21)/sender=\uBC1C\uC2E0\uBA85\uC758(\uC6B0\uCE21 bold). \uD1B5\uC9C0 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1108
|
-
press: z.object({
|
|
1109
|
-
release: z.string().optional(),
|
|
1110
|
-
distribute: z.string().optional(),
|
|
1111
|
-
sub: z.array(z.string()).optional(),
|
|
1112
|
-
contact: z.object(Object.fromEntries(PRESS_CONTACT_KEYS.map((k) => [k, z.string().optional()]))).optional()
|
|
1113
|
-
}).optional().describe("\uBCF4\uB3C4\uC790\uB8CC \uC635\uC158 \u2014 release=\uBCF4\uB3C4\uC2DC\uC810/distribute=\uBC30\uD3EC\uC77C(\uBA38\uB9AC\uBC15\uC2A4)/sub=\uBD80\uC81C \uBC30\uC5F4('- \u2026 -')/contact=\uB2F4\uB2F9 \uBD80\uC11C\xB7\uB2F4\uB2F9\uC790\xB7\uC5F0\uB77D\uCC98 \uD45C"),
|
|
1114
|
-
paper: z.enum(["A4", "A3", "B4", "B5", "Letter"]).optional().describe("\uC6A9\uC9C0 \uD06C\uAE30 (v4.5.0). \uAE30\uBCF8 A4"),
|
|
1115
|
-
landscape: z.boolean().optional().describe("\uC6A9\uC9C0 \uAC00\uB85C \uBC29\uD5A5 (v4.5.0). \uAE30\uBCF8 \uC138\uB85C"),
|
|
1116
|
-
columns: z.number().int().min(1).max(8).optional().describe("\uB2E4\uB2E8 \uAC1C\uC218 (v4.5.0). \uAE30\uBCF8 1\uB2E8"),
|
|
1117
|
-
header: z.string().optional().describe("\uBA38\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8 \u2014 \uBAA8\uB4E0 \uCABD \uC0C1\uB2E8, \uC778\uB77C\uC778 \uB9C8\uD06C\uB2E4\uC6B4 \uD5C8\uC6A9 (v4.5.0)"),
|
|
1118
|
-
footer: z.string().optional().describe("\uAF2C\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8 \u2014 \uBAA8\uB4E0 \uCABD \uD558\uB2E8 (v4.5.0)"),
|
|
1119
|
-
image_dir: z.string().optional().describe("\uB9C8\uD06C\uB2E4\uC6B4 \uC774\uBBF8\uC9C0 \uCC38\uC870()\uB97C \uC774 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC77D\uC5B4 \uC2E4\uB370\uC774\uD130 \uC784\uBCA0\uB4DC (v4.5.0, PNG/JPEG/GIF/BMP). \uBBF8\uC9C0\uC815 \uC2DC \uCC38\uC870\uB9CC placeholder\uB85C \uBCF4\uC874")
|
|
1120
|
-
},
|
|
1121
|
-
async ({ markdown, output_path, profile_path, preset, font, body_pt, line_spacing, org, date, toc, cover, approval, page_numbers, end_mark, body_title_box, h2_marker, band_color, band_text_color, summary, doc_info, 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 }) => {
|
|
1122
|
-
try {
|
|
1123
|
-
let gongmun;
|
|
1124
|
-
if (preset) {
|
|
1125
|
-
gongmun = buildGongmunOptions({
|
|
1126
|
-
preset: PRESET_ALIAS[preset],
|
|
1127
|
-
font,
|
|
1128
|
-
bodyPt: body_pt,
|
|
1129
|
-
lineSpacing: line_spacing,
|
|
1130
|
-
org,
|
|
1131
|
-
date,
|
|
1132
|
-
cover,
|
|
1133
|
-
toc,
|
|
1134
|
-
approval,
|
|
1135
|
-
pageNumbers: page_numbers,
|
|
1136
|
-
endMark: end_mark,
|
|
1137
|
-
bodyTitleBox: body_title_box,
|
|
1138
|
-
h2Marker: h2_marker,
|
|
1139
|
-
bandColor: band_color,
|
|
1140
|
-
bandTextColor: band_text_color,
|
|
1141
|
-
fonts,
|
|
1142
|
-
sizes,
|
|
1143
|
-
levels,
|
|
1144
|
-
bullet2,
|
|
1145
|
-
suppressSingle: suppress_single,
|
|
1146
|
-
docHead: doc_head,
|
|
1147
|
-
docFoot: doc_foot,
|
|
1148
|
-
reportInfo: report_info,
|
|
1149
|
-
noticeHead: notice_head,
|
|
1150
|
-
press,
|
|
1151
|
-
summary,
|
|
1152
|
-
docInfo: doc_info,
|
|
1153
|
-
dept,
|
|
1154
|
-
coverLabel: cover_label
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
1157
|
-
let profile;
|
|
1158
|
-
if (profile_path) {
|
|
1159
|
-
const { parseFormatProfileJson } = await import("./profile-io-JZ3FDHDK.js");
|
|
1160
|
-
profile = parseFormatProfileJson(await readFile(safePath(profile_path, PROFILE_EXTENSIONS), "utf-8"));
|
|
1093
|
+
};
|
|
1094
|
+
} catch (err) {
|
|
1095
|
+
return {
|
|
1096
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
1097
|
+
isError: true
|
|
1098
|
+
};
|
|
1161
1099
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1100
|
+
}
|
|
1101
|
+
);
|
|
1102
|
+
server2.tool(
|
|
1103
|
+
"generate_document",
|
|
1104
|
+
"\uB9C8\uD06C\uB2E4\uC6B4\uC744 HWPX \uD55C\uAE00 \uBB38\uC11C\uB85C \uC0DD\uC131\uD569\uB2C8\uB2E4. \"\uBCF4\uACE0\uC11C\uB85C/\uACF5\uBB38\uC11C\uB85C/\uAC1C\uC870\uC2DD\uC73C\uB85C/\uACC4\uD68D\uC11C\uB85C \uBF51\uC544\uC918\xB7\uB9CC\uB4E4\uC5B4\uC918\" \uC694\uCCAD\uC774 \uC774 \uB3C4\uAD6C\uC785\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uB9E4\uD551: \uC815\uBD80 \uD45C\uC900 \uBCF4\uACE0\uC11C(\uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uB85C\uB9C8\uC22B\uC790 \uC7A5\uD5E4\uB354 \uC790\uB3D9)='\uAC1C\uC870\uC2DD', \uC911\uC559\uBD80\uCC98 \uC5C5\uBB34\uBCF4\uACE0\xB7\uAD6D\uD68C \uC11C\uBA74\uBCF4\uACE0(\uC7AC\uACBD\uBD80 \uC2E4\uCE21: \uC7A5 \uB760\xB7\uC808 \uC22B\uC790\uCE78\xB7\uC18C\uC81C\uBAA9 \uBC15\uC2A4\xB7\u2460 \uD56D\uBAA9 \uB760\xB7\uC5F0\uB178\uB791 \uC131\uACFC \uC694\uC57D\uBC15\uC2A4\xB7\uBCC4\uCCA8 \uB760, \u25A1 \uB4A4 (\uD0A4\uC6CC\uB4DC) \uD30C\uB791)='\uC5C5\uBB34\uBCF4\uACE0', \uAE30\uC548\uBB38\xB7\uC2DC\uD589\uBB38\xB7\uC54C\uB9BC\uACF5\uBB38='\uAE30\uC548\uBB38', 1\uD398\uC774\uC9C0 \uC694\uC57D\uBCF4\uACE0\uC11C='\uBCF4\uACE0\uC11C', \uCD94\uC9C4\uACC4\uD68D='\uACC4\uD68D\uC11C'. \uD45C\uB294 \uC2E4\uCE21 \uC815\uBD80 \uC11C\uC2DD(\uD5E4\uB354 \uC74C\uC601+\uC774\uC911\uC120\xB7\uC678\uACFD \uAD75\uC740\uC120\xB7\uB0B4\uC6A9 \uBE44\uB840 \uC5F4\uD3ED), \uCABD\uBC88\uD638\xB7\uACB0\uC7AC\uB780\xB7'\uB05D.' \uD45C\uC2DC \uC9C0\uC6D0. \u26A0 \uC0DD\uC131 \uC804 \uD655\uC778 \uAD8C\uC7A5: \uBB38\uC11C\uC885\uB958(\uBCF4\uACE0\uC11C/\uAE30\uC548\uBB38)\xB7\uC81C\uBAA9\xB7\uAE30\uAD00\uBA85(org)\xB7\uB0A0\uC9DC\xB7\uBAA9\uCC28 \uC5EC\uBD80\uAC00 \uBD88\uBA85\uD655\uD558\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBB3C\uC5B4\uBCF4\uC138\uC694 \u2014 \uC5C9\uB6B1\uD55C \uD504\uB9AC\uC14B \uC120\uD0DD\uC774 \uAC00\uC7A5 \uD754\uD55C \uC624\uC0DD\uC131 \uC6D0\uC778. \uB9C8\uD06C\uB2E4\uC6B4 \uADDC\uCE59(v4.13 \uC11C\uC6B8 \uC2E4\uACB0\uC7AC \uC2E4\uCE21 \uC704\uACC4): #(h1)=\uBB38\uC11C \uC81C\uBAA9, ##(h2)=\uC7A5(\uBCF4\uACE0\uC11C \u2160 \u2161 / \uAE30\uC548\uBB38\xB7\uD1B5\uC9C0\uB294 \uBC95\uC815 1.), ###(h3)=\u25A1 \uB300\uD56D\uBAA9(\uAE30\uC548\uBB38 \uAC00.), \uADF8 \uC544\uB798 \uB9AC\uC2A4\uD2B8=\u3147 \u2192 - \u2192 \u318D(\uAE30\uC548\uBB38 \uAC00. \u2192 1) \u2192 \uAC00)), \uBCF8\uBB38\uC5D0 \u25A1/\u3147/-/1./\uAC00. \uB97C \uC9C1\uC811 \uC368\uB3C4 \uAC19\uC740 \uC704\uACC4\uB85C \uC815\uADDC\uD654, \u203B\uC2DC\uC791\xB7'\uCD9C\uCC98:'\xB7'\uC790\uB8CC:'=\uCC38\uACE0(13pt), \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(>)=\uBCF4\uACE0\uC11C \uC694\uC57D\uBC15\uC2A4 \u2014 \u2605\uBCF4\uACE0\uC11C\uB294 \uBC18\uB4DC\uC2DC \uC81C\uBAA9 \uC9C1\uD6C4 `> \u2026\uD558\uACE0\uC790 \uD568` \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9\xB7\uBD80\uD638 \uC5C6\uC74C\xB73\uC904 \uC774\uB0B4 \uC57D 90~100\uC790)\uB85C \uBCF4\uACE0 \uBAA9\uC801\uC744 \uB123\uC744 \uAC83(\uC5C6\uAC70\uB098 3\uC904 \uCD08\uACFC\uBA74 \uACBD\uACE0), <right>\uD14D\uC2A4\uD2B8</right>=\uC6B0\uCE21\uC815\uB82C. \u25A1\xB7\uC81C\uBAA9\uC740 \uD55C \uC904\uC5D0 \uC790\uB3D9 \uCD95\uC18C, \uBCF8\uBB38\uC740 \uC5B4\uC808 \uB2E8\uC704 \uC904\uBC14\uAFC8(\uB0B1\uB9D0\xB7\uB0A0\uC9DC\uAC00 \uC904 \uB05D\uC5D0\uC11C \uC548 \uCABC\uAC1C\uC9D0)\xB7\uBD80\uD638 \uB4A4 \uD0ED \uC815\uB82C(\uB458\uC9F8 \uC904\uC774 \uCCAB \uC904 \uB0B4\uC6A9\uACFC \uAC19\uC740 \uC704\uCE58), \uB9C8\uC9C0\uB9C9 \uC904\uC774 \uC9E7\uC740 \uACE0\uC544 \uC904\uACFC \uACF5\uBC31\uC774 \uD06C\uAC8C \uBC8C\uC5B4\uC9C0\uB294 \uC904\uC740 \uC790\uAC04 \uCD95\uC18C\uB85C \uC815\uB9AC, \uACE7\uC740\uB530\uC634\uD45C\uB294 \u2018\u2019\u201C\u201D\uB85C. \uBC95\uB839 \uCF54\uB4DC (282791)\xB7KOSIS \uD45C ID DT_\u2026\xB7(\uBC95\uC815\uB3D9\uCF54\uB4DC \u2026)\xB7\u25CB\u25CB MCP \uC870\uD68C \uAC19\uC740 \uB0B4\uBD80 \uC2DD\uBCC4\uC790\xB7\uB3C4\uAD6C \uC5B8\uAE09\uC740 \uC790\uB3D9 \uC81C\uAC70 \u2014 \uCD9C\uCC98\uB294 \uAE30\uAD00\xB7\uC790\uB8CC\uBA85\uB9CC \uC4F8 \uAC83. (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874 \uC81C\uC790\uB9AC \uC218\uC815\uC740 patch_document, \uC11C\uC2DD \uBE48\uCE78 \uCC44\uC6B0\uAE30\uB294 fill_form)",
|
|
1105
|
+
{
|
|
1106
|
+
markdown: z4.string().min(1).describe("HWPX\uB85C \uBCC0\uD658\uD560 \uB9C8\uD06C\uB2E4\uC6B4 \uC804\uBB38. \uD45C\uB294 GFM \uBB38\uBC95 \uC0AC\uC6A9 (\uC608: '| \uC774\uB984 | \uBD80\uC11C |\\n| --- | --- |\\n| \uD64D\uAE38\uB3D9 | \uAE30\uD68D\uD300 |')"),
|
|
1107
|
+
output_path: z4.string().min(1).describe("\uCD9C\uB825 HWPX \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C (.hwpx \uAD8C\uC7A5)"),
|
|
1108
|
+
profile_path: z4.string().optional().describe("\uC11C\uC2DD \uD504\uB85C\uD544 JSON \uACBD\uB85C (extract_profile\uB85C \uCD94\uCD9C) \u2014 \uCC38\uC870 \uBB38\uC11C\uC758 \uD45C \uD14C\uB450\uB9AC\xB7\uC74C\uC601\xB7\uC5F4\uD3ED\xB7\uC140 \uAE00\uAF34\uC744 \uC7AC\uD604. \uD45C \uD589\xB7\uC5F4 \uC218\uC640 \uCCAB \uC140 \uD14D\uC2A4\uD2B8\uAC00 \uC77C\uCE58\uD558\uB294 \uD45C\uC5D0\uB9CC \uC801\uC6A9"),
|
|
1109
|
+
// 값 집합·범위는 gongmun-surface SSOT에서 파생 (CLI와 드리프트 불가 — v4.0.4 영역1-1)
|
|
1110
|
+
preset: z4.enum(Object.keys(PRESET_ALIAS)).optional().describe("\uACF5\uBB38\uC11C \uD504\uB9AC\uC14B \u2014 \uC9C0\uC815 \uC2DC \uD55C\uAD6D \uD589\uC815 \uACF5\uBB38\uC11C \uD45C\uC900 \uC11C\uC2DD \uC801\uC6A9. '\uAC1C\uC870\uC2DD'=\uC815\uBD80 \uD45C\uC900 \uAC1C\uC870\uC2DD \uBCF4\uACE0\uC11C(\uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uB85C\uB9C8\uC22B\uC790 \uC7A5 \uD5E4\uB354 \uC790\uB3D9 + \u25A1\u25CB-\u203B \uBD80\uD638\uBCC4 \uD3F0\uD2B8), '\uC5C5\uBB34\uBCF4\uACE0'=\uC911\uC559\uBD80\uCC98 \uC5C5\uBB34\uBCF4\uACE0(##=\u2160 \uC7A5 \uB760, ###=\uD30C\uB780 \uC22B\uC790\uCE78 \uC808, ####=\uB0A8\uC0C9 \uC18C\uC81C\uBAA9 \uBC15\uC2A4, #####=\u2460 \uD558\uB298\uC0C9 \uD56D\uBAA9 \uB760, > \u25AA\u2026=\uC5F0\uB178\uB791 \uC131\uACFC \uC694\uC57D\uBC15\uC2A4, ## \uBCC4\uCCA8 \u2026=\uBCC4\uCCA8 \uB760, \u2776\u21D2 \uBD80\uD638 \uBCF4\uC874, \uD568\uCD08\uB86C\uBC14\uD0D5 15\xB7\uAC01\uC8FC \uB9D1\uC740 \uACE0\uB515 12), '\uBCF4\uB3C4\uC790\uB8CC'=\uBA38\uB9AC\uBC15\uC2A4+\uC81C\uBAA9 25pt+\u25A1\u2192\u3147\u2192*(\uAC01\uC8FC) \uCCB4\uACC4. \uBBF8\uC9C0\uC815 \uC2DC \uBC94\uC6A9 \uB9C8\uD06C\uB2E4\uC6B4 \uBCC0\uD658"),
|
|
1111
|
+
font: z4.enum(BODY_FONTS).optional().describe("\uBCF8\uBB38 \uAE00\uAF34(\uACF5\uBB38\uC11C \uBAA8\uB4DC): myeongjo=\uBA85\uC870 \uACC4\uC5F4(\uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\uB294 \uC2E4\uCE21 \uD734\uBA3C\uBA85\uC870, \uADF8 \uC678 \uD568\uCD08\uB86C\uBC14\uD0D5), gothic=\uB9D1\uC740 \uACE0\uB515"),
|
|
1112
|
+
body_pt: z4.number().int().min(BODY_PT_RANGE.min).max(BODY_PT_RANGE.max).optional().describe("\uBCF8\uBB38 \uAE00\uC790 \uD06C\uAE30(pt, \uACF5\uBB38\uC11C \uBAA8\uB4DC). \uAE30\uBCF8: \uAE30\uC548\uBB38 12, \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uD1B5\uC9C0 15"),
|
|
1113
|
+
line_spacing: z4.number().int().min(LINE_SPACING_RANGE.min).max(LINE_SPACING_RANGE.max).optional().describe("\uBCF8\uBB38 \uC904\uAC04\uACA9(%, \uACF5\uBB38\uC11C \uBAA8\uB4DC). \uAE30\uBCF8: \uD504\uB9AC\uC14B\uBCC4 \uC2E4\uCE21\uAC12(\uAE30\uC548\uBB38 160, \uD68C\uC758\uB85D 130 \uB4F1)"),
|
|
1114
|
+
org: z4.string().optional().describe("\uD45C\uC9C0 \uAE30\uAD00\uBA85 (\uD45C\uC9C0\uB97C \uCF1C\uB294 \uBAA8\uB4E0 \uD504\uB9AC\uC14B\uC5D0\uC11C \uC0AC\uC6A9 \uAC00\uB2A5). \uBBF8\uC9C0\uC815 \uC2DC \uD45C\uC9C0\uC5D0 \uAE30\uAD00\uBA85 \uC0DD\uB7B5"),
|
|
1115
|
+
date: z4.string().optional().describe("\uD45C\uC9C0 \uB0A0\uC9DC ('YYYY. M. D.' \uD45C\uAE30 \uAD8C\uC7A5). \uBBF8\uC9C0\uC815 \uC2DC \uC624\uB298 \uB0A0\uC9DC"),
|
|
1116
|
+
toc: z4.boolean().optional().describe("\uBAA9\uCC28 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC5EC\uBD80 \u2014 h2 \uBAA9\uB85D\uC744 \u2160 \u2161 \u2162 \uC7A5\uC73C\uB85C \uC790\uB3D9 \uAD6C\uC131. \uC804 \uD504\uB9AC\uC14B \uC0AC\uC6A9 \uAC00\uB2A5(\uBCF4\uB3C4\uC790\uB8CC \uC81C\uC678). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B\uB9CC \uCF1C\uC9D0"),
|
|
1117
|
+
cover: z4.boolean().optional().describe("\uD45C\uC9C0 \uD398\uC774\uC9C0 \uC0DD\uC131 \uC5EC\uBD80 \u2014 \uCCAB h1\uC744 \uC81C\uBAA9\uC73C\uB85C \uD30C\uB791 \uC7A5\uC2DD \uD45C\uC9C0. \uC804 \uD504\uB9AC\uC14B \uC0AC\uC6A9 \uAC00\uB2A5(\uBCF4\uB3C4\uC790\uB8CC \uC81C\uC678 \u2014 \uBA38\uB9AC\uBC15\uC2A4 \uC11C\uC2DD\uACFC \uC591\uB9BD \uBD88\uAC00). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B\uB9CC \uCF1C\uC9D0 (org/date \uC9C0\uC815 \uC2DC \uC790\uB3D9 \uCF1C\uC9D0)"),
|
|
1118
|
+
approval: z4.array(z4.string()).max(APPROVAL_MAX).optional().describe("\uACB0\uC7AC\uB780 \uC9C1\uC704 \uB77C\uBCA8 (\uCD5C\uB300 6\uAC1C, \uC608: ['\uB2F4\uB2F9','\uD300\uC7A5','\uACFC\uC7A5']) \u2014 \uBB38\uC11C \uCD5C\uC0C1\uB2E8 \uC6B0\uCE21\uC5D0 \uC11C\uBA85 \uACF5\uB780 \uACB0\uC7AC \uD45C \uC0DD\uC131"),
|
|
1119
|
+
page_numbers: z4.boolean().optional().describe("\uCABD\uBC88\uD638(\uD558\uB2E8 \uC911\uC559 '- 1 -', \uD45C\uC9C0\xB7\uBAA9\uCC28 \uCE74\uC6B4\uD2B8 \uC81C\uC678). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uCF1C\uC9D0"),
|
|
1120
|
+
end_mark: z4.boolean().optional().describe("\uBCF8\uBB38 \uB05D '\uB05D.' \uD45C\uC2DC (\uD589\uC815\uC5C5\uBB34\uADDC\uC815). \uBBF8\uC9C0\uC815 \uC2DC \uAE30\uC548\uBB38\uB9CC \uCF1C\uC9D0, \uBCF8\uBB38\uC774 \uC774\uBBF8 '\uB05D.'\uC73C\uB85C \uB05D\uB098\uBA74 \uC911\uBCF5 \uC0DD\uC131 \uC548 \uD568"),
|
|
1121
|
+
body_title_box: z4.boolean().optional().describe("\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4 (\uAC1C\uC870\uC2DD \uC2E4\uCE21 \uAD00\uD589). \uBBF8\uC9C0\uC815 \uC2DC \uAC1C\uC870\uC2DD+\uD45C\uC9C0 \uC870\uD569\uC5D0\uC11C \uCF1C\uC9D0"),
|
|
1122
|
+
h2_marker: z4.enum(H2_MARKERS).optional().describe("h2 \uC7A5 \uC81C\uBAA9 \uD45C\uAE30: band=\uB85C\uB9C8\uC790 \uCC44\uC6C0 \uCE78+\uC81C\uBAA9 \uB760 \uD45C(\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8), roman='\u2160. \uC81C\uBAA9' \uD14D\uC2A4\uD2B8, number='1. \uC81C\uBAA9'(\uD1B5\uC9C0 \uAE30\uBCF8), box=\uC7A5 \uC5C6\uC774 \u25A1 \uB300\uD56D\uBAA9\uC73C\uB85C, none=\uBC88\uD638 \uC5C6\uC74C. \uAE30\uC548\uBB38 \uBCF8\uBB38\uC758 h2\uB294 \uD56D\uC0C1 \uBC95\uC815 '1.' \uD56D\uBAA9"),
|
|
1123
|
+
band_color: z4.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("\uB760 \uC81C\uBAA9 \uBC88\uD638\uCE78 \uCC44\uC6C0\uC0C9 #RRGGBB (\uAE30\uBCF8 #003366 \uC2E4\uCE21 \uCD5C\uB2E4. \uAD50\uC721\uCCAD\uD615 \uBC1D\uC740 \uB760\uB294 #DFE6F7 + band_text_color #000000)"),
|
|
1124
|
+
band_text_color: z4.string().regex(/^#[0-9A-Fa-f]{6}$/).optional().describe("\uB760 \uC81C\uBAA9 \uBC88\uD638 \uAE00\uC790\uC0C9 #RRGGBB (\uAE30\uBCF8 #FFFFFF)"),
|
|
1125
|
+
summary: z4.string().optional().describe("\uBCF4\uACE0\uC11C \uC694\uC57D \uBC15\uC2A4 \u2014 \uC81C\uBAA9\uD45C \uC544\uB798 #DFE6F7 \uC74C\uC601 \uC0C1\uC790(\uC11C\uC6B8 \uC2E4\uACB0\uC7AC \uAD00\uD589). \uB9C8\uD06C\uB2E4\uC6B4 \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(> \u2026)\uC73C\uB85C\uB3C4 \uC9C0\uC815 \uAC00\uB2A5"),
|
|
1126
|
+
doc_info: z4.object(Object.fromEntries(DOC_INFO_KEYS.map((k) => [k, z4.string().optional()]))).optional().describe("\uBCF4\uACE0\uC11C \uD45C\uC9C0 \uBB38\uC11C\uC815\uBCF4\uD45C \u2014 docNum=\uBB38\uC11C\uBC88\uD638/date=\uACB0\uC7AC\uC77C\uC790/disclosure=\uACF5\uAC1C\uC5EC\uBD80/policyNo=\uBC29\uCE68\uBC88\uD638 (cover=true\uC640 \uD568\uAED8)"),
|
|
1127
|
+
dept: z4.string().optional().describe("\uD45C\uC9C0 \uBD80\uC11C\uBA85 \u2014 \uAE30\uAD00\uBA85 \uC544\uB798 '(\uC2A4\uB9C8\uD2B8\uB3C4\uC2DC\uACFC)' (cover\uC640 \uD568\uAED8)"),
|
|
1128
|
+
cover_label: z4.string().optional().describe("\uD45C\uC9C0 \uC6B0\uC0C1\uB2E8 \uCDE8\uAE09 \uD45C\uC2DC \u2014 '\uB300\uC678\uC8FC\uC758'\xB7'\uBE44\uACF5\uAC1C' \uBE68\uAC04 \uD14C\uB450\uB9AC \uBC15\uC2A4 (\uC5C5\uBB34\uBCF4\uACE0 \uD504\uB9AC\uC14B \uC2E4\uCE21, cover\uC640 \uD568\uAED8)"),
|
|
1129
|
+
fonts: z4.object(Object.fromEntries(FONT_ROLE_KEYS.map((k) => [k, z4.string().optional()]))).optional().describe("\uC694\uC18C\uBCC4 \uAE00\uAF34 \uC624\uBC84\uB77C\uC774\uB4DC(\uACF5\uBB38\uC11C \uBAA8\uB4DC) \u2014 body=\uBCF8\uBB38(\u25CB\xB7-)/heading=\uC81C\uBAA9 \uACC4\uC5F4(\u25A1\xB7\uC7A5\uD5E4\uB354\xB7\uD45C\uC9C0\xB7\uBAA9\uCC28)/ref=\u203B \uCC38\uACE0/table=\uD45C \uC140. \uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\uB294 \uB124 \uC5ED\uD560 \uC804\uBD80, \uADF8 \uC678 \uD504\uB9AC\uC14B\uC740 body\uB9CC \uC801\uC6A9"),
|
|
1130
|
+
sizes: z4.object(Object.fromEntries(SIZE_KEYS.map((k) => [k, z4.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional()]))).optional().describe("\uAC1C\uC870\uC2DD \uC694\uC18C\uBCC4 \uAE00\uC790 \uD06C\uAE30(pt) \uC624\uBC84\uB77C\uC774\uB4DC \u2014 dae=\u25A1/cham=\u203B/chapter=\uC7A5\uD5E4\uB354/coverTitle\xB7coverSub=\uD45C\uC9C0/tocLabel\xB7tocRoman\xB7tocItem=\uBAA9\uCC28/table=\uD45C \uC140/bodyTitle=\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4. \uBBF8\uC9C0\uC815 \uC694\uC18C\uB294 body_pt \uBE44\uB840 \uAE30\uBCF8\uAC12"),
|
|
1131
|
+
levels: z4.record(z4.string().regex(/^[0-7]$/), z4.object(Object.fromEntries(LEVEL_STYLE_KEYS.map((k) => [k, k === "pt" ? z4.number().min(SIZE_PT_RANGE.min).max(SIZE_PT_RANGE.max).optional() : k === "bold" ? z4.boolean().optional() : z4.string().optional()])))).optional().describe('\uD56D\uBAA9\uBD80\uD638 \uB2E8\uACC4\uBCC4 \uC704\uACC4 \uD0C0\uC774\uD3EC(\uACF5\uBB38\uC11C \uBAA8\uB4DC, v4.12.3) \u2014 {"0":{font:"HY\uACAC\uACE0\uB515",pt:17,bold:true},"1":{font:"\uD55C\uCEF4\uB3CB\uC6C0",bold:true}} \uAF34(depth 0~7). \uC2E4\uCE21: \uC804\uC790\uACB0\uC7AC \uAE30\uC548\uBB38 \u25A1/\u3147/- \uACC4\uC5F4\uC740 \u25A1=HY\uACAC\uACE0\uB515 +2~3pt \uAD75\uAC8C\xB7\u3147=\uD55C\uCEF4\uB3CB\uC6C0 \uAD75\uAC8C\xB7-=\uD734\uBA3C\uBA85\uC870 \uBCF8\uBB38. \uBC95\uC815 8\uB2E8\uACC4(1. \uAC00.)\uB294 \uBCF8\uBB38 \uB3D9\uC77C\uC774 \uAD00\uD589\uC774\uB77C \uAE30\uBCF8 \uBBF8\uC801\uC6A9'),
|
|
1132
|
+
bullet2: z4.enum(BULLET2_CHARS).optional().describe("2\uB2E8\uACC4 \uD56D\uBAA9\uBD80\uD638 \u2014 '\u3147'(\uC774\uC751, \uC804\uC790\uACB0\uC7AC \uAE30\uC548\uBB38\xB7\uACF5\uACE0\uBB38 \uC2E4\uCE21 \uC9C0\uBC30) / '\u25CB'(\uC6D0, \uBCF4\uACE0\uC11C \uC591\uC2DD). \uBBF8\uC9C0\uC815 \uC2DC \uD1B5\uC9C0\xB7\uBCF4\uB3C4\uC790\uB8CC \u3147, \uADF8 \uC678 \u25CB"),
|
|
1133
|
+
suppress_single: z4.boolean().optional().describe("\uB2E8\uC77C \uD615\uC81C \uD56D\uBAA9 \uBD80\uD638 \uC0DD\uB7B5(\uD3B8\uB78C \uADDC\uC815, \uBC95\uC815 \uBC88\uD638 standard \uC804\uC6A9 \u2014 \uBD88\uB9BF \uCCB4\uACC4\uC778 \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C\xB7\uAC1C\uC870\uC2DD\xB7\uBCF4\uB3C4\uC790\uB8CC\uC5D4 \uBB34\uD6A8). \uAE30\uBCF8 false \u2014 \uD558\uB098\uBFD0\uC778 \uD56D\uBAA9\uC5D0\uB3C4 \uBD80\uD638(1. \uAC00.)\uB97C \uBD80\uC5EC (\uBD80\uD638 \uC5C6\uB294 \uACC4\uB2E8 \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC2E4\uBB34 \uB208\uC5D0 \uC5B4\uC0C9)"),
|
|
1134
|
+
doc_head: z4.object(Object.fromEntries(DOC_HEAD_KEYS.map((k) => [k, z4.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uB450\uBB38\uD45C(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD\xB7\uC11C\uC6B8 \uC2E4\uACB0\uC7AC 6\uD589 \uD45C) \u2014 org=\uD589\uC815\uAE30\uAD00\uBA85(\uAD74\uB9BC 20pt bold \uC790\uAC04\uB744\uC6C0)/slogan=\uC6D0\uD6C8(\uC0C1\uB2E8 10pt)/to=\uC218\uC2E0('\uB0B4\uBD80\uACB0\uC7AC'\uBA74 \uBC1C\uC2E0\uBA85\uC758 \uC0DD\uB7B5)/via=\uACBD\uC720/title=\uC81C\uBAA9(\uBBF8\uC9C0\uC815 \uC2DC \uCCAB h1). \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1135
|
+
doc_foot: z4.object(Object.fromEntries(DOC_FOOT_KEYS.map((k) => [k, z4.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uACB0\uBB38\uD45C \u2014 sender=\uBC1C\uC2E0\uBA85\uC758(18pt bold \uC911\uC559)/drafter\xB7reviewer\xB7approver='\uC9C1\uC704 \uC131\uBA85' \uACB0\uC7AC\uC120/cooperator=\uD611\uC870\uC790/recipients=\uC218\uC2E0\uC790 \uBAA9\uB85D/docNum=\uC2DC\uD589 '\uACFC-\uBC88\uD638 (\uB0A0\uC9DC)'/receive=\uC811\uC218/zip\xB7address\xB7site/phone\xB7fax\xB7email/disclosure=\uACF5\uAC1C\uAD6C\uBD84. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1136
|
+
report_info: z4.string().optional().describe("\uBCF4\uACE0\uC11C: \uC81C\uBAA9\uD45C \uC544\uB798 \uB2F4\uB2F9\uC790 \uD589 '(2026. 9. 6., \uC2A4\uB9C8\uD2B8\uB3C4\uC2DC\uACFC \uD64D\uAE38\uB3D9, \u260E450-1234)' / \uAE30\uC548\uBB38: \uC6B0\uC0C1\uB2E8 12pt \uBCF4\uACE0\uC815\uBCF4 \uD589"),
|
|
1137
|
+
notice_head: z4.object(Object.fromEntries(NOTICE_HEAD_KEYS.map((k) => [k, z4.string().optional()]))).optional().describe("\uACF5\uACE0\uBB38 \uB450\uBB38\xB7\uACB0\uBB38 \u2014 no=\uACF5\uACE0\uBC88\uD638(\uBCF8\uBB38 \uC704 bold)/date=\uB0A0\uC9DC(\uBCF8\uBB38 \uC544\uB798 \uC6B0\uCE21)/sender=\uBC1C\uC2E0\uBA85\uC758(\uC6B0\uCE21 bold). \uD1B5\uC9C0 \uD504\uB9AC\uC14B \uC804\uC6A9"),
|
|
1138
|
+
press: z4.object({
|
|
1139
|
+
release: z4.string().optional(),
|
|
1140
|
+
distribute: z4.string().optional(),
|
|
1141
|
+
sub: z4.array(z4.string()).optional(),
|
|
1142
|
+
contact: z4.object(Object.fromEntries(PRESS_CONTACT_KEYS.map((k) => [k, z4.string().optional()]))).optional()
|
|
1143
|
+
}).optional().describe("\uBCF4\uB3C4\uC790\uB8CC \uC635\uC158 \u2014 release=\uBCF4\uB3C4\uC2DC\uC810/distribute=\uBC30\uD3EC\uC77C(\uBA38\uB9AC\uBC15\uC2A4)/sub=\uBD80\uC81C \uBC30\uC5F4('- \u2026 -')/contact=\uB2F4\uB2F9 \uBD80\uC11C\xB7\uB2F4\uB2F9\uC790\xB7\uC5F0\uB77D\uCC98 \uD45C"),
|
|
1144
|
+
paper: z4.enum(["A4", "A3", "B4", "B5", "Letter"]).optional().describe("\uC6A9\uC9C0 \uD06C\uAE30 (v4.5.0). \uAE30\uBCF8 A4"),
|
|
1145
|
+
landscape: z4.boolean().optional().describe("\uC6A9\uC9C0 \uAC00\uB85C \uBC29\uD5A5 (v4.5.0). \uAE30\uBCF8 \uC138\uB85C"),
|
|
1146
|
+
columns: z4.number().int().min(1).max(8).optional().describe("\uB2E4\uB2E8 \uAC1C\uC218 (v4.5.0). \uAE30\uBCF8 1\uB2E8"),
|
|
1147
|
+
header: z4.string().optional().describe("\uBA38\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8 \u2014 \uBAA8\uB4E0 \uCABD \uC0C1\uB2E8, \uC778\uB77C\uC778 \uB9C8\uD06C\uB2E4\uC6B4 \uD5C8\uC6A9 (v4.5.0)"),
|
|
1148
|
+
footer: z4.string().optional().describe("\uAF2C\uB9AC\uB9D0 \uD14D\uC2A4\uD2B8 \u2014 \uBAA8\uB4E0 \uCABD \uD558\uB2E8 (v4.5.0)"),
|
|
1149
|
+
image_dir: z4.string().optional().describe("\uB9C8\uD06C\uB2E4\uC6B4 \uC774\uBBF8\uC9C0 \uCC38\uC870()\uB97C \uC774 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uC77D\uC5B4 \uC2E4\uB370\uC774\uD130 \uC784\uBCA0\uB4DC (v4.5.0, PNG/JPEG/GIF/BMP). \uBBF8\uC9C0\uC815 \uC2DC \uCC38\uC870\uB9CC placeholder\uB85C \uBCF4\uC874")
|
|
1150
|
+
},
|
|
1151
|
+
async ({ markdown, output_path, profile_path, preset, font, body_pt, line_spacing, org, date, toc, cover, approval, page_numbers, end_mark, body_title_box, h2_marker, band_color, band_text_color, summary, doc_info, 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 }) => {
|
|
1152
|
+
try {
|
|
1153
|
+
let gongmun;
|
|
1154
|
+
if (preset) {
|
|
1155
|
+
gongmun = buildGongmunOptions({
|
|
1156
|
+
preset: PRESET_ALIAS[preset],
|
|
1157
|
+
font,
|
|
1158
|
+
bodyPt: body_pt,
|
|
1159
|
+
lineSpacing: line_spacing,
|
|
1160
|
+
org,
|
|
1161
|
+
date,
|
|
1162
|
+
cover,
|
|
1163
|
+
toc,
|
|
1164
|
+
approval,
|
|
1165
|
+
pageNumbers: page_numbers,
|
|
1166
|
+
endMark: end_mark,
|
|
1167
|
+
bodyTitleBox: body_title_box,
|
|
1168
|
+
h2Marker: h2_marker,
|
|
1169
|
+
bandColor: band_color,
|
|
1170
|
+
bandTextColor: band_text_color,
|
|
1171
|
+
fonts,
|
|
1172
|
+
sizes,
|
|
1173
|
+
levels,
|
|
1174
|
+
bullet2,
|
|
1175
|
+
suppressSingle: suppress_single,
|
|
1176
|
+
docHead: doc_head,
|
|
1177
|
+
docFoot: doc_foot,
|
|
1178
|
+
reportInfo: report_info,
|
|
1179
|
+
noticeHead: notice_head,
|
|
1180
|
+
press,
|
|
1181
|
+
summary,
|
|
1182
|
+
docInfo: doc_info,
|
|
1183
|
+
dept,
|
|
1184
|
+
coverLabel: cover_label
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
let profile;
|
|
1188
|
+
if (profile_path) {
|
|
1189
|
+
const { parseFormatProfileJson } = await import("./profile-io-LBM263K7.js");
|
|
1190
|
+
profile = parseFormatProfileJson(await readFile3(safePath(profile_path, PROFILE_EXTENSIONS), "utf-8"));
|
|
1191
|
+
}
|
|
1192
|
+
const out = safeOutputPath(output_path, /* @__PURE__ */ new Set([".hwpx"]));
|
|
1193
|
+
const page = paper || landscape || columns || header || footer ? {
|
|
1194
|
+
...paper ? { size: paper } : {},
|
|
1195
|
+
...landscape ? { orientation: "landscape" } : {},
|
|
1196
|
+
...columns ? { columns } : {},
|
|
1197
|
+
...header ? { header } : {},
|
|
1198
|
+
...footer ? { footer } : {}
|
|
1199
|
+
} : void 0;
|
|
1200
|
+
let images;
|
|
1201
|
+
if (image_dir) {
|
|
1202
|
+
const dir = await realpath3(resolve2(image_dir));
|
|
1203
|
+
assertWithinRoot(dir);
|
|
1204
|
+
for (const m of markdown.matchAll(/!\[[^\]]*\]\(([^)\s]+)\)/g)) {
|
|
1205
|
+
const url = m[1];
|
|
1206
|
+
if (!/^[A-Za-z0-9._-]+\.[A-Za-z0-9]+$/.test(url) || url.includes("..")) continue;
|
|
1207
|
+
try {
|
|
1208
|
+
images ??= {};
|
|
1209
|
+
images[url] = new Uint8Array(await readFile3(join2(dir, url)));
|
|
1210
|
+
} catch {
|
|
1211
|
+
}
|
|
1181
1212
|
}
|
|
1182
1213
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
const warnText = fontWarns.length ? `
|
|
1214
|
+
const genWarnings = [];
|
|
1215
|
+
const buf = await markdownToHwpx(markdown, gongmun || profile || page || images ? {
|
|
1216
|
+
...gongmun ? { gongmun } : {},
|
|
1217
|
+
...profile ? { profile } : {},
|
|
1218
|
+
...page ? { page } : {},
|
|
1219
|
+
...images ? { images } : {},
|
|
1220
|
+
warnings: genWarnings
|
|
1221
|
+
} : void 0);
|
|
1222
|
+
await mkdir3(dirname4(out), { recursive: true });
|
|
1223
|
+
await writeFile3(out, Buffer.from(buf));
|
|
1224
|
+
const mode = gongmun ? `\uACF5\uBB38\uC11C:${gongmun.preset}` : "\uBC94\uC6A9";
|
|
1225
|
+
const tableCount = (markdown.match(/^\s*\|.*\|\s*$/gm) || []).length > 0 ? `, \uD45C \uD3EC\uD568` : "";
|
|
1226
|
+
const fontWarns = gongmun?.fonts ? unknownFontWarnings(gongmun.fonts) : [];
|
|
1227
|
+
if (gongmun) fontWarns.push(...incompatibleGongmunWarnings(gongmun));
|
|
1228
|
+
if (gongmun) fontWarns.push(...gongmunLintWarnings(markdown, 5));
|
|
1229
|
+
if (gongmun && usesGaejosikMunche(gongmun.preset)) fontWarns.push(...muncheLintWarnings(markdown, 5));
|
|
1230
|
+
fontWarns.push(...genWarnings);
|
|
1231
|
+
const warnText = fontWarns.length ? `
|
|
1202
1232
|
\u26A0 ${fontWarns.join("\n\u26A0 ")}` : "";
|
|
1203
|
-
|
|
1204
|
-
|
|
1233
|
+
return {
|
|
1234
|
+
content: [{ type: "text", text: `\u2713 HWPX \uC0DD\uC131 (${mode}${tableCount}) \u2192 ${out}
|
|
1205
1235
|
\uD06C\uAE30: ${(buf.byteLength / 1024).toFixed(1)}KB${warnText}` }]
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1236
|
+
};
|
|
1237
|
+
} catch (err) {
|
|
1238
|
+
return {
|
|
1239
|
+
content: [{ type: "text", text: `\uC624\uB958: ${describeError(err)}` }],
|
|
1240
|
+
isError: true
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1212
1243
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
// src/mcp.ts
|
|
1248
|
+
var server = new McpServer({
|
|
1249
|
+
name: "kordoc",
|
|
1250
|
+
version: VERSION
|
|
1251
|
+
});
|
|
1252
|
+
registerParseTools(server);
|
|
1253
|
+
registerFormTools(server);
|
|
1254
|
+
registerRenderTools(server);
|
|
1255
|
+
registerGenerateTools(server);
|
|
1215
1256
|
var serverStarted = false;
|
|
1216
1257
|
async function startMcpServer() {
|
|
1217
1258
|
if (serverStarted) return;
|
|
@@ -1228,7 +1269,7 @@ async function startMcpServer() {
|
|
|
1228
1269
|
var autoStart = true;
|
|
1229
1270
|
try {
|
|
1230
1271
|
const entry = process.argv[1];
|
|
1231
|
-
if (entry && pathToFileURL(
|
|
1272
|
+
if (entry && pathToFileURL(realpathSync2(entry)).href !== import.meta.url) autoStart = false;
|
|
1232
1273
|
} catch {
|
|
1233
1274
|
}
|
|
1234
1275
|
if (autoStart) startMcpServer().catch((err) => {
|