kordoc 4.0.3 → 4.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +8 -0
  2. package/dist/{-QSF64HNK.js → -QVHGOOCR.js} +9 -7
  3. package/dist/chunk-5RPYBC2Q.js +88 -0
  4. package/dist/chunk-5RPYBC2Q.js.map +1 -0
  5. package/dist/{chunk-6JSZBSOD.js → chunk-6BABRVOJ.js} +2 -2
  6. package/dist/{chunk-PNQDQ3SM.js → chunk-6PED5OOG.js} +34 -4
  7. package/dist/chunk-6PED5OOG.js.map +1 -0
  8. package/dist/{chunk-OVESZY5R.cjs → chunk-6R5FY47W.cjs} +38 -8
  9. package/dist/chunk-6R5FY47W.cjs.map +1 -0
  10. package/dist/{chunk-RO2GVZ3I.js → chunk-6WDPB4SN.js} +3 -3
  11. package/dist/{chunk-TQYX5E32.js → chunk-FKK4K53F.js} +34 -4
  12. package/dist/chunk-FKK4K53F.js.map +1 -0
  13. package/dist/{chunk-MQLKSRIK.js → chunk-OMERK4AW.js} +76 -25
  14. package/dist/chunk-OMERK4AW.js.map +1 -0
  15. package/dist/{chunk-AUJICYJG.js → chunk-QK2G34WE.js} +4 -3
  16. package/dist/chunk-QK2G34WE.js.map +1 -0
  17. package/dist/{chunk-K2SETHJ6.js → chunk-Z6Q3YG22.js} +1632 -765
  18. package/dist/chunk-Z6Q3YG22.js.map +1 -0
  19. package/dist/chunk-ZGMMLYAL.js +92 -0
  20. package/dist/chunk-ZGMMLYAL.js.map +1 -0
  21. package/dist/cli.js +119 -72
  22. package/dist/cli.js.map +1 -1
  23. package/dist/index.cjs +21162 -20243
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +53 -1
  26. package/dist/index.d.ts +53 -1
  27. package/dist/index.js +20987 -20068
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp.js +106 -83
  30. package/dist/mcp.js.map +1 -1
  31. package/dist/{parser-FMONFTAN.cjs → parser-2V5SPTU7.cjs} +106 -17
  32. package/dist/parser-2V5SPTU7.cjs.map +1 -0
  33. package/dist/{parser-AODAQQLQ.js → parser-3MAYZUJX.js} +95 -6
  34. package/dist/parser-3MAYZUJX.js.map +1 -0
  35. package/dist/{parser-J7YREDNS.js → parser-YSHZC5FQ.js} +94 -5
  36. package/dist/parser-YSHZC5FQ.js.map +1 -0
  37. package/dist/profile-io-3EECPDHG.js +11 -0
  38. package/dist/render-MJSQ4TG2.js +10 -0
  39. package/dist/seal-R3POFNOU.js +10 -0
  40. package/dist/seal-R3POFNOU.js.map +1 -0
  41. package/dist/{watch-P65Z24AL.js → watch-7MHSCKEQ.js} +7 -7
  42. package/package.json +1 -1
  43. package/dist/chunk-AUJICYJG.js.map +0 -1
  44. package/dist/chunk-K2SETHJ6.js.map +0 -1
  45. package/dist/chunk-MQLKSRIK.js.map +0 -1
  46. package/dist/chunk-OVESZY5R.cjs.map +0 -1
  47. package/dist/chunk-PNQDQ3SM.js.map +0 -1
  48. package/dist/chunk-TQYX5E32.js.map +0 -1
  49. package/dist/parser-AODAQQLQ.js.map +0 -1
  50. package/dist/parser-FMONFTAN.cjs.map +0 -1
  51. package/dist/parser-J7YREDNS.js.map +0 -1
  52. package/dist/render-JPP7YTV3.js +0 -10
  53. package/dist/seal-MDE4DXZQ.js +0 -10
  54. /package/dist/{-QSF64HNK.js.map → -QVHGOOCR.js.map} +0 -0
  55. /package/dist/{chunk-6JSZBSOD.js.map → chunk-6BABRVOJ.js.map} +0 -0
  56. /package/dist/{chunk-RO2GVZ3I.js.map → chunk-6WDPB4SN.js.map} +0 -0
  57. /package/dist/{render-JPP7YTV3.js.map → profile-io-3EECPDHG.js.map} +0 -0
  58. /package/dist/{seal-MDE4DXZQ.js.map → render-MJSQ4TG2.js.map} +0 -0
  59. /package/dist/{watch-P65Z24AL.js.map → watch-7MHSCKEQ.js.map} +0 -0
package/dist/mcp.js CHANGED
@@ -1,5 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ APPROVAL_MAX,
4
+ BODY_FONTS,
5
+ BODY_PT_RANGE,
6
+ BULLET2_CHARS,
7
+ DOC_FOOT_KEYS,
8
+ DOC_HEAD_KEYS,
9
+ FONT_ROLE_KEYS,
10
+ H2_MARKERS,
11
+ LINE_SPACING_RANGE,
12
+ NOTICE_HEAD_KEYS,
13
+ PRESS_CONTACT_KEYS,
14
+ SIZE_KEYS,
15
+ SIZE_PT_RANGE,
16
+ buildGongmunOptions
17
+ } from "./chunk-5RPYBC2Q.js";
18
+ import {
19
+ PRESET_ALIAS,
3
20
  compare,
4
21
  extractFormFields,
5
22
  extractHwp5MetadataOnly,
@@ -8,29 +25,30 @@ import {
8
25
  fillHwpx,
9
26
  fillWithUniqueGuard,
10
27
  gongmunLintWarnings,
28
+ incompatibleGongmunWarnings,
11
29
  markdownToHwpx,
12
30
  parse,
13
31
  patchHwp,
14
32
  patchHwpx,
15
33
  unknownFontWarnings
16
- } from "./chunk-K2SETHJ6.js";
34
+ } from "./chunk-Z6Q3YG22.js";
17
35
  import {
18
36
  blocksToMarkdown
19
- } from "./chunk-PNQDQ3SM.js";
37
+ } from "./chunk-6PED5OOG.js";
20
38
  import {
21
39
  detectFormat,
22
40
  detectZipFormat
23
41
  } from "./chunk-MEPHGCPQ.js";
24
42
  import "./chunk-MOL7MDBG.js";
25
- import "./chunk-RO2GVZ3I.js";
26
- import "./chunk-MQLKSRIK.js";
27
- import "./chunk-AUJICYJG.js";
43
+ import "./chunk-6WDPB4SN.js";
44
+ import "./chunk-OMERK4AW.js";
45
+ import "./chunk-QK2G34WE.js";
28
46
  import {
29
47
  KordocError,
30
48
  VERSION,
31
49
  sanitizeError,
32
50
  toArrayBuffer
33
- } from "./chunk-6JSZBSOD.js";
51
+ } from "./chunk-6BABRVOJ.js";
34
52
 
35
53
  // src/mcp.ts
36
54
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -150,14 +168,18 @@ ${markdown}`);
150
168
  );
151
169
  server.tool(
152
170
  "detect_format",
153
- "\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, pdf, unknown).",
171
+ "\uD30C\uC77C\uC758 \uD3EC\uB9F7\uC744 \uB9E4\uC9C1 \uBC14\uC774\uD2B8\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4 (hwpx, hwp, pdf, xlsx, docx, unknown).",
154
172
  {
155
173
  file_path: z.string().min(1).describe("\uAC10\uC9C0\uD560 \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C")
156
174
  },
157
175
  async ({ file_path }) => {
158
176
  try {
159
177
  const resolved = safePath(file_path);
160
- const format = detectFormatFromHeader(resolved);
178
+ let format = detectFormatFromHeader(resolved);
179
+ if (format === "hwpx") {
180
+ const { buffer } = readValidatedFile(file_path, MAX_METADATA_FILE_SIZE);
181
+ format = await detectZipFormat(buffer);
182
+ }
161
183
  return {
162
184
  content: [{ type: "text", text: `${file_path}: ${format}` }]
163
185
  };
@@ -202,7 +224,7 @@ server.tool(
202
224
  break;
203
225
  case "pdf":
204
226
  try {
205
- const { extractPdfMetadataOnly } = await import("./parser-AODAQQLQ.js");
227
+ const { extractPdfMetadataOnly } = await import("./parser-3MAYZUJX.js");
206
228
  metadata = await extractPdfMetadataOnly(buffer);
207
229
  } catch {
208
230
  metadata = void 0;
@@ -554,7 +576,7 @@ server.tool(
554
576
  }
555
577
  const image = new Uint8Array(readFileSync(imgResolved));
556
578
  const ext = extname(image_path).slice(1).toLowerCase() || "png";
557
- const { placeSealHwpx } = await import("./seal-MDE4DXZQ.js");
579
+ const { placeSealHwpx } = await import("./seal-R3POFNOU.js");
558
580
  const result = await placeSealHwpx(buffer, [{
559
581
  anchor,
560
582
  occurrence,
@@ -639,110 +661,111 @@ server.tool(
639
661
  }
640
662
  }
641
663
  );
664
+ server.tool(
665
+ "extract_profile",
666
+ '\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.',
667
+ {
668
+ hwpx_path: z.string().min(1).describe("\uC11C\uC2DD\uC744 \uCD94\uCD9C\uD560 \uCC38\uC870 HWPX \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C"),
669
+ output_path: z.string().min(1).describe("\uD504\uB85C\uD544 JSON \uCD9C\uB825 \uC808\uB300 \uACBD\uB85C (.json \uAD8C\uC7A5)")
670
+ },
671
+ async ({ hwpx_path, output_path }) => {
672
+ try {
673
+ const { buffer } = readValidatedFile(hwpx_path);
674
+ const { hwpxToProfile } = await import("./-QVHGOOCR.js");
675
+ const profile = await hwpxToProfile(buffer);
676
+ const out = resolve(output_path);
677
+ mkdirSync(dirname(out), { recursive: true });
678
+ writeFileSync(out, JSON.stringify(profile, null, 2));
679
+ return {
680
+ content: [{ type: "text", text: `\uC11C\uC2DD \uD504\uB85C\uD544 \uCD94\uCD9C \uC644\uB8CC: \uD45C ${profile.tables.length}\uAC1C \u2192 ${out}
681
+ (generate_document\uC758 profile_path\uB85C \uC0AC\uC6A9)` }]
682
+ };
683
+ } catch (err) {
684
+ return {
685
+ content: [{ type: "text", text: `\uC624\uB958: ${sanitizeError(err)}` }],
686
+ isError: true
687
+ };
688
+ }
689
+ }
690
+ );
642
691
  server.tool(
643
692
  "generate_document",
644
693
  `\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', \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: #(h1)=\uBB38\uC11C \uC81C\uBAA9(\uD45C\uC9C0), ##(h2)=\uC7A5(\u2160 \u2161 \u2162 \uC790\uB3D9), \uB9AC\uC2A4\uD2B8 \uAE4A\uC774=\u25A1 \u25CB - \u318D \uBD80\uD638, \u203B\uC2DC\uC791 \uBB38\uB2E8=\uCC38\uACE0 \uC2A4\uD0C0\uC77C, <right>\uD14D\uC2A4\uD2B8</right>=\uC6B0\uCE21\uC815\uB82C \uCD9C\uCC98\uD589. (\uC6D0\uBCF8 \uC11C\uC2DD \uBCF4\uC874 \uC81C\uC790\uB9AC \uC218\uC815\uC740 patch_document, \uC11C\uC2DD \uBE48\uCE78 \uCC44\uC6B0\uAE30\uB294 fill_form)`,
645
694
  {
646
695
  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 |')"),
647
696
  output_path: z.string().min(1).describe("\uCD9C\uB825 HWPX \uD30C\uC77C\uC758 \uC808\uB300 \uACBD\uB85C (.hwpx \uAD8C\uC7A5)"),
648
- preset: z.enum(["\uAE30\uC548\uBB38", "\uBCF4\uACE0\uC11C", "\uACC4\uD68D\uC11C", "\uD1B5\uC9C0", "\uD68C\uC758\uB85D", "\uAC1C\uC870\uC2DD", "\uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C", "\uC815\uBD80\uBCF4\uACE0\uC11C", "\uC815\uBD80\uD45C\uC900\uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C", "\uBCF4\uB3C4\uC790\uB8CC", "official", "report", "plan", "notice", "minutes", "gaejosik", "press"]).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), '\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"),
649
- font: z.enum(["myeongjo", "gothic"]).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"),
650
- body_pt: z.number().int().min(6).max(40).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"),
697
+ 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"),
698
+ // 집합·범위는 gongmun-surface SSOT에서 파생 (CLI와 드리프트 불가 v4.0.4 영역1-1)
699
+ 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), '\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"),
700
+ 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"),
701
+ 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"),
702
+ 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)"),
651
703
  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"),
652
704
  date: z.string().optional().describe("\uD45C\uC9C0 \uB0A0\uC9DC ('YYYY. M. D.' \uD45C\uAE30 \uAD8C\uC7A5). \uBBF8\uC9C0\uC815 \uC2DC \uC624\uB298 \uB0A0\uC9DC"),
653
705
  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"),
654
706
  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)"),
655
- approval: z.array(z.string()).max(6).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"),
707
+ 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"),
656
708
  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"),
657
709
  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"),
658
710
  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"),
659
- h2_marker: z.enum(["box", "number", "none"]).optional().describe("h2 \uC139\uC158 \uC81C\uBAA9 \uB9D0\uBA38\uB9AC(\uBE44\uAC1C\uC870\uC2DD): box='\u25A1 \uC81C\uBAA9'(\uC2E4\uCE21 \uBCF4\uACE0\uC11C \uAD00\uD589), number='1. \uC81C\uBAA9'(\uACF5\uACE0\uBB38 \uAD00\uD589), none=\uB9D0\uBA38\uB9AC \uC5C6\uC74C. \uBBF8\uC9C0\uC815 \uC2DC \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C box, \uADF8 \uC678 none"),
660
- fonts: z.object({
661
- body: z.string().optional(),
662
- heading: z.string().optional(),
663
- ref: z.string().optional(),
664
- table: z.string().optional()
665
- }).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"),
666
- sizes: z.object({
667
- dae: z.number().min(6).max(60).optional(),
668
- cham: z.number().min(6).max(60).optional(),
669
- chapter: z.number().min(6).max(60).optional(),
670
- coverTitle: z.number().min(6).max(60).optional(),
671
- coverSub: z.number().min(6).max(60).optional(),
672
- tocLabel: z.number().min(6).max(60).optional(),
673
- tocRoman: z.number().min(6).max(60).optional(),
674
- tocItem: z.number().min(6).max(60).optional(),
675
- table: z.number().min(6).max(60).optional()
676
- }).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. \uBBF8\uC9C0\uC815 \uC694\uC18C\uB294 body_pt \uBE44\uB840 \uAE30\uBCF8\uAC12"),
677
- bullet2: z.enum(["\u3147", "\u25CB"]).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"),
711
+ h2_marker: z.enum(H2_MARKERS).optional().describe("h2 \uC139\uC158 \uC81C\uBAA9 \uB9D0\uBA38\uB9AC(\uBE44\uAC1C\uC870\uC2DD): box='\u25A1 \uC81C\uBAA9'(\uC2E4\uCE21 \uBCF4\uACE0\uC11C \uAD00\uD589), number='1. \uC81C\uBAA9'(\uACF5\uACE0\uBB38 \uAD00\uD589), none=\uB9D0\uBA38\uB9AC \uC5C6\uC74C. \uBBF8\uC9C0\uC815 \uC2DC \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C box, \uADF8 \uC678 none"),
712
+ 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"),
713
+ 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"),
714
+ 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"),
678
715
  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)"),
679
- doc_head: z.object({
680
- org: z.string().optional(),
681
- to: z.string().optional(),
682
- via: z.string().optional(),
683
- title: z.string().optional()
684
- }).optional().describe("\uAE30\uC548\uBB38 \uB450\uBB38(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD) \u2014 org=\uD589\uC815\uAE30\uAD00\uBA85(18pt bold \uC911\uC559)/to=\uC218\uC2E0/via=\uACBD\uC720/title=\uC81C\uBAA9. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
685
- doc_foot: z.object({
686
- sender: z.string().optional(),
687
- drafter: z.string().optional(),
688
- reviewer: z.string().optional(),
689
- approver: z.string().optional(),
690
- cooperator: z.string().optional(),
691
- docNum: z.string().optional(),
692
- receive: z.string().optional(),
693
- address: z.string().optional(),
694
- site: z.string().optional(),
695
- phone: z.string().optional(),
696
- fax: z.string().optional(),
697
- email: z.string().optional(),
698
- disclosure: z.string().optional()
699
- }).optional().describe("\uAE30\uC548\uBB38 \uACB0\uBB38 \u2014 sender=\uBC1C\uC2E0\uBA85\uC758(22pt \uC911\uC559)/drafter\xB7reviewer\xB7approver=\uAE30\uC548\xB7\uAC80\uD1A0\xB7\uACB0\uC7AC/docNum=\uC2DC\uD589/receive=\uC811\uC218/disclosure=\uACF5\uAC1C\uAD6C\uBD84 \uB4F1. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
716
+ doc_head: z.object(Object.fromEntries(DOC_HEAD_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uB450\uBB38(\uBCC4\uC9C0 \uC81C1\uD638\uC11C\uC2DD) \u2014 org=\uD589\uC815\uAE30\uAD00\uBA85(18pt bold \uC911\uC559)/to=\uC218\uC2E0/via=\uACBD\uC720/title=\uC81C\uBAA9. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
717
+ doc_foot: z.object(Object.fromEntries(DOC_FOOT_KEYS.map((k) => [k, z.string().optional()]))).optional().describe("\uAE30\uC548\uBB38 \uACB0\uBB38 \u2014 sender=\uBC1C\uC2E0\uBA85\uC758(22pt \uC911\uC559)/drafter\xB7reviewer\xB7approver=\uAE30\uC548\xB7\uAC80\uD1A0\xB7\uACB0\uC7AC/docNum=\uC2DC\uD589/receive=\uC811\uC218/disclosure=\uACF5\uAC1C\uAD6C\uBD84 \uB4F1. \uAE30\uC548\uBB38 \uD504\uB9AC\uC14B \uC804\uC6A9"),
700
718
  report_info: z.string().optional().describe("\uC5C5\uBB34\uBCF4\uACE0 \uC6B0\uC0C1\uB2E8 \uBCF4\uACE0\uC815\uBCF4 \uD589 \u2014 \uC608: '(2026. 7. 11., \uACFC\uC7A5 \uD64D\uAE38\uB3D9, \u260E02-120)' (\uC2E4\uCE21: 12pt \uC6B0\uCE21\uC815\uB82C)"),
701
- notice_head: z.object({
702
- no: z.string().optional(),
703
- date: z.string().optional(),
704
- sender: z.string().optional()
705
- }).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"),
719
+ 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"),
706
720
  press: z.object({
707
721
  release: z.string().optional(),
708
722
  distribute: z.string().optional(),
709
723
  sub: z.array(z.string()).optional(),
710
- contact: z.object({ dept: z.string().optional(), manager: z.string().optional(), phone: z.string().optional() }).optional()
724
+ contact: z.object(Object.fromEntries(PRESS_CONTACT_KEYS.map((k) => [k, z.string().optional()]))).optional()
711
725
  }).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")
712
726
  },
713
- async ({ markdown, output_path, preset, font, body_pt, org, date, toc, cover, approval, page_numbers, end_mark, body_title_box, h2_marker, fonts, sizes, bullet2, suppress_single, doc_head, doc_foot, report_info, notice_head, press }) => {
727
+ 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, fonts, sizes, bullet2, suppress_single, doc_head, doc_foot, report_info, notice_head, press }) => {
714
728
  try {
715
729
  let gongmun;
716
730
  if (preset) {
717
- gongmun = { preset };
718
- if (font) gongmun.bodyFont = font;
719
- if (body_pt) gongmun.bodyPt = body_pt;
720
- if (cover === false) gongmun.cover = false;
721
- else if (org || date) gongmun.cover = { ...org ? { org } : {}, ...date ? { date } : {} };
722
- else if (cover === true) gongmun.cover = true;
723
- if (toc !== void 0) gongmun.toc = toc;
724
- if (approval && approval.length > 0) gongmun.approval = approval;
725
- if (page_numbers !== void 0) gongmun.pageNumbers = page_numbers;
726
- if (end_mark !== void 0) gongmun.endMark = end_mark;
727
- if (body_title_box !== void 0) gongmun.bodyTitleBox = body_title_box;
728
- if (h2_marker) gongmun.h2Marker = h2_marker;
729
- if (fonts) gongmun.fonts = fonts;
730
- if (sizes) gongmun.sizes = sizes;
731
- if (bullet2) gongmun.bullet2 = bullet2;
732
- if (suppress_single !== void 0) gongmun.suppressSingle = suppress_single;
733
- if (doc_head) gongmun.docHead = doc_head;
734
- if (doc_foot) gongmun.docFoot = doc_foot;
735
- if (report_info) gongmun.reportInfo = report_info;
736
- if (notice_head) gongmun.noticeHead = notice_head;
737
- if (press) gongmun.press = press;
731
+ gongmun = buildGongmunOptions({
732
+ preset: PRESET_ALIAS[preset],
733
+ font,
734
+ bodyPt: body_pt,
735
+ lineSpacing: line_spacing,
736
+ org,
737
+ date,
738
+ cover,
739
+ toc,
740
+ approval,
741
+ pageNumbers: page_numbers,
742
+ endMark: end_mark,
743
+ bodyTitleBox: body_title_box,
744
+ h2Marker: h2_marker,
745
+ fonts,
746
+ sizes,
747
+ bullet2,
748
+ suppressSingle: suppress_single,
749
+ docHead: doc_head,
750
+ docFoot: doc_foot,
751
+ reportInfo: report_info,
752
+ noticeHead: notice_head,
753
+ press
754
+ });
755
+ }
756
+ let profile;
757
+ if (profile_path) {
758
+ const { parseFormatProfileJson } = await import("./profile-io-3EECPDHG.js");
759
+ profile = parseFormatProfileJson(readFileSync(resolve(profile_path), "utf-8"));
738
760
  }
739
- const buf = await markdownToHwpx(markdown, gongmun ? { gongmun } : void 0);
761
+ const buf = await markdownToHwpx(markdown, gongmun || profile ? { ...gongmun ? { gongmun } : {}, ...profile ? { profile } : {} } : void 0);
740
762
  const out = resolve(output_path);
741
763
  mkdirSync(dirname(out), { recursive: true });
742
764
  writeFileSync(out, Buffer.from(buf));
743
765
  const mode = gongmun ? `\uACF5\uBB38\uC11C:${gongmun.preset}` : "\uBC94\uC6A9";
744
766
  const tableCount = (markdown.match(/^\s*\|.*\|\s*$/gm) || []).length > 0 ? `, \uD45C \uD3EC\uD568` : "";
745
767
  const fontWarns = gongmun?.fonts ? unknownFontWarnings(gongmun.fonts) : [];
768
+ if (gongmun) fontWarns.push(...incompatibleGongmunWarnings(gongmun));
746
769
  if (gongmun) fontWarns.push(...gongmunLintWarnings(markdown, 5));
747
770
  const warnText = fontWarns.length ? `
748
771
  \u26A0 ${fontWarns.join("\n\u26A0 ")}` : "";