@kodocagent/cli 0.4.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1644 -1234
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9739,9 +9739,9 @@ var require_load = __commonJS({
|
|
|
9739
9739
|
var require_lib3 = __commonJS({
|
|
9740
9740
|
"../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/index.js"(exports, module) {
|
|
9741
9741
|
"use strict";
|
|
9742
|
-
function
|
|
9743
|
-
if (!(this instanceof
|
|
9744
|
-
return new
|
|
9742
|
+
function JSZip7() {
|
|
9743
|
+
if (!(this instanceof JSZip7)) {
|
|
9744
|
+
return new JSZip7();
|
|
9745
9745
|
}
|
|
9746
9746
|
if (arguments.length) {
|
|
9747
9747
|
throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
|
|
@@ -9750,7 +9750,7 @@ var require_lib3 = __commonJS({
|
|
|
9750
9750
|
this.comment = null;
|
|
9751
9751
|
this.root = "";
|
|
9752
9752
|
this.clone = function() {
|
|
9753
|
-
var newObj = new
|
|
9753
|
+
var newObj = new JSZip7();
|
|
9754
9754
|
for (var i in this) {
|
|
9755
9755
|
if (typeof this[i] !== "function") {
|
|
9756
9756
|
newObj[i] = this[i];
|
|
@@ -9759,16 +9759,16 @@ var require_lib3 = __commonJS({
|
|
|
9759
9759
|
return newObj;
|
|
9760
9760
|
};
|
|
9761
9761
|
}
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
return new
|
|
9762
|
+
JSZip7.prototype = require_object();
|
|
9763
|
+
JSZip7.prototype.loadAsync = require_load();
|
|
9764
|
+
JSZip7.support = require_support();
|
|
9765
|
+
JSZip7.defaults = require_defaults();
|
|
9766
|
+
JSZip7.version = "3.10.1";
|
|
9767
|
+
JSZip7.loadAsync = function(content, options) {
|
|
9768
|
+
return new JSZip7().loadAsync(content, options);
|
|
9769
9769
|
};
|
|
9770
|
-
|
|
9771
|
-
module.exports =
|
|
9770
|
+
JSZip7.external = require_external();
|
|
9771
|
+
module.exports = JSZip7;
|
|
9772
9772
|
}
|
|
9773
9773
|
});
|
|
9774
9774
|
|
|
@@ -9894,6 +9894,15 @@ function detectPii(text3) {
|
|
|
9894
9894
|
function summarizePii(findings) {
|
|
9895
9895
|
return findings.map((f) => `${f.type} ${f.count}\uAC74`).join(", ");
|
|
9896
9896
|
}
|
|
9897
|
+
function redactText(text3) {
|
|
9898
|
+
if (!text3) return { text: text3 ?? "", findings: [] };
|
|
9899
|
+
let result = text3;
|
|
9900
|
+
const findings = detectPii(text3);
|
|
9901
|
+
for (const { re, mask } of PATTERNS) {
|
|
9902
|
+
result = result.replace(new RegExp(re.source, re.flags), (m) => mask(m));
|
|
9903
|
+
}
|
|
9904
|
+
return { text: result, findings };
|
|
9905
|
+
}
|
|
9897
9906
|
|
|
9898
9907
|
// ../core/dist/index.js
|
|
9899
9908
|
import { stepCountIs, streamText } from "ai";
|
|
@@ -9935,7 +9944,7 @@ var DOCUMENT_RULES_SECTION = `## \uBB38\uC11C \uADDC\uCE59
|
|
|
9935
9944
|
1. \uBB38\uC11C\uB97C \uC218\uC815\uD558\uAE30 \uC804\uC5D0 \uBC18\uB4DC\uC2DC \`read_document\` \uD234\uB85C \uB0B4\uC6A9\uC744 \uBA3C\uC800 \uC77D\uC73C\uC138\uC694.
|
|
9936
9945
|
2. \uBAA8\uB4E0 \uD30C\uC77C \uC800\uC7A5\uC740 \`propose_*\` \uD234\uC744 \uD1B5\uD55C \uC2A4\uD14C\uC774\uC9D5\uACFC \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC744 \uAC70\uCCD0\uC57C \uD569\uB2C8\uB2E4.
|
|
9937
9946
|
3. \uC2B9\uC778\uC744 \uBC1B\uAE30 \uC804\uC5D0\uB294 \uC808\uB300 "\uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4", "\uC644\uB8CC\uD588\uC2B5\uB2C8\uB2E4"\uB77C\uACE0 \uB9D0\uD558\uC9C0 \uB9C8\uC138\uC694.
|
|
9938
|
-
4. \`.hwp
|
|
9947
|
+
4. \`propose_edit\`\uB85C \`.hwp\`/\`.hwpx\`\uB97C \uD3B8\uC9D1\uD558\uBA74 \uC6D0\uBCF8 \uD615\uC2DD \uADF8\uB300\uB85C \uBB34\uC190\uC2E4 \uC800\uC7A5\uB429\uB2C8\uB2E4(.hwp\uB294 .hwp\uB85C \uC720\uC9C0). \uB2E8, \uD45C\xB7\uC140\xB7\uCC3E\uC544\uBC14\uAFB8\uAE30 \uB4F1 \uC77C\uBD80 \uAD6C\uC870 \uD3B8\uC9D1 \uD234\uC740 \`.hwpx\` \uAE30\uBC18\uC774\uBBC0\uB85C \`.hwp\` \uC785\uB825\uC774 \`.hwpx\`\uB85C \uC800\uC7A5\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD615\uC2DD \uBCC0\uD658\uC774 \uC548\uB0B4\uB418\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBBF8\uB9AC \uC54C\uB9AC\uC138\uC694.
|
|
9939
9948
|
5. \uACBD\uB85C\uB294 \uD604\uC7AC \uC791\uC5C5 \uB514\uB809\uD130\uB9AC\uB97C \uAE30\uC900\uC73C\uB85C \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
|
|
9940
9949
|
6. \uC0AC\uC6A9\uC790\uAC00 \uC218\uC815\uC548\uC744 \uAC70\uC808\uD558\uBA74 \uAC19\uC740 \uC81C\uC548\uC744 \uC790\uB3D9\uC73C\uB85C \uBC18\uBCF5\uD558\uC9C0 \uB9D0\uACE0, \uC0AC\uC6A9\uC790\uC758 \uB2E4\uC74C \uC9C0\uC2DC\uB97C \uAE30\uB2E4\uB9AC\uC138\uC694.
|
|
9941
9950
|
7. \uD070 \uBB38\uC11C\uB294 \uBA3C\uC800 \`outline\`\uC73C\uB85C \uAD6C\uC870\uB97C \uD30C\uC545\uD558\uACE0, \`search\`\uB098 \`pages\`\uB85C \uD544\uC694\uD55C \uBD80\uBD84\uB9CC \uC77D\uC5B4 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uC544\uB07C\uC138\uC694.
|
|
@@ -9948,7 +9957,7 @@ var EDIT_SAFETY_SECTION = `## \uD3B8\uC9D1 \uC548\uC804 \uADDC\uCE59
|
|
|
9948
9957
|
4. \uC804\uBB38 \uC6A9\uC5B4\uB294 \uC784\uC758\uB85C \uB2E4\uB978 \uD45C\uD604\uC73C\uB85C \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uBB38\uC11C \uC804\uCCB4\uC5D0\uC11C \uC77C\uAD00\uB418\uAC8C \uC720\uC9C0\uD569\uB2C8\uB2E4.
|
|
9949
9958
|
5. \uACC4\uC57D\uC11C\xB7\uC57D\uAD00\xB7\uACF5\uC2DC\xB7\uB17C\uBB38 \uB4F1 \uBC95\uC801\xB7\uACF5\uC2DD \uBB38\uC11C\uB294 \uB2E8\uC5B4 \uD558\uB098\uAC00 \uC758\uBBF8\uB97C \uBC14\uAFC0 \uC218 \uC788\uC73C\uBBC0\uB85C, \uD45C\uD604\uC744 \uC790\uB3D9\uC73C\uB85C \uB2E4\uB4EC\uC9C0 \uB9D0\uACE0 \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uBCC0\uACBD\uB9CC \uC218\uD589\uD569\uB2C8\uB2E4.
|
|
9950
9959
|
6. \uC758\uBBF8\uAC00 \uBC14\uB014 \uC218 \uC788\uB294 \uC218\uC815\uC740 \uC2E4\uD589 \uC804\uC5D0 \uADF8 \uC0AC\uC2E4\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uACE0, \uC218\uC815 \uC81C\uC548\uC758 \uC694\uC57D(summary)\uC5D0\uB294 \uBB34\uC5C7\uC744\xB7\uC65C \uBC14\uAFB8\uB294\uC9C0 \uD568\uAED8 \uC801\uC2B5\uB2C8\uB2E4.
|
|
9951
|
-
7. \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\xB7\uC804\uD654\uBC88\uD638\xB7\uC774\uBA54\uC77C\xB7\uACC4\uC88C\xB7\uCE74\uB4DC\uBC88\uD638 \uB4F1)
|
|
9960
|
+
7. \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\xB7\uC804\uD654\uBC88\uD638\xB7\uC774\uBA54\uC77C\xB7\uACC4\uC88C\xB7\uCE74\uB4DC\uBC88\uD638 \uB4F1) \uCC98\uB9AC: \uC0AC\uC6A9\uC790\uAC00 **\uD655\uC778\xB7\uC810\uAC80\uB9CC** \uC6D0\uD558\uBA74 \`scan_pii\`(\uC77D\uAE30 \uC804\uC6A9)\uB85C \uBCF4\uC5EC\uC8FC\uACE0, **\uAC00\uB9AC\uAE30\xB7\uB9C8\uC2A4\uD0B9\xB7\uBE44\uC2DD\uBCC4\xB7\uAC1C\uC778\uC815\uBCF4 \uC0AD\uC81C**\uB97C \uC6D0\uD558\uBA74 \`scan_pii\`\uC5D0\uC11C \uBA48\uCD94\uC9C0 \uB9D0\uACE0 \`propose_redact_pii\`\uB85C \uBC14\uB85C \uC218\uC815\uC548\uC744 \uC81C\uC548\uD558\uC138\uC694(\uC774 \uB3C4\uAD6C\uB3C4 \uC2B9\uC778\uC744 \uAC70\uCE58\uBBC0\uB85C \uC548\uC804\uD569\uB2C8\uB2E4).`;
|
|
9952
9961
|
var LAW_RULES_SECTION = `## \uBC95\uB839 \uADDC\uCE59
|
|
9953
9962
|
|
|
9954
9963
|
1. \uBC95\uB839 \uC778\uC6A9 \uD615\uC2DD: \u300C\uBC95\uB839\uBA85\u300D \uC81CN\uC870 \uC81CN\uD56D \uC81CN\uD638
|
|
@@ -10919,23 +10928,27 @@ import { basename as basename3, extname as extname2, join as join32 } from "path
|
|
|
10919
10928
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
10920
10929
|
var import_jszip2 = __toESM(require_lib3(), 1);
|
|
10921
10930
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
10931
|
+
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
10922
10932
|
import { z as z3 } from "zod";
|
|
10923
10933
|
import { readFile as readFile32 } from "fs/promises";
|
|
10924
|
-
import { blocksToMarkdown, compare } from "
|
|
10934
|
+
import { blocksToMarkdown, compare } from "kordoc";
|
|
10925
10935
|
import { z as z22 } from "zod";
|
|
10936
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
10937
|
+
import { extname as extname4 } from "path";
|
|
10938
|
+
import { z as z4 } from "zod";
|
|
10926
10939
|
import { readFile as readFile4 } from "fs/promises";
|
|
10927
10940
|
import { extname as extname3 } from "path";
|
|
10928
10941
|
import { z as z32 } from "zod";
|
|
10929
|
-
import {
|
|
10930
|
-
import { extname as extname4, join as join4, relative as relative2 } from "path";
|
|
10931
|
-
import { z as z4 } from "zod";
|
|
10932
|
-
import { readFile as readFile5 } from "fs/promises";
|
|
10942
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
10933
10943
|
import { extname as extname5 } from "path";
|
|
10934
10944
|
import { z as z5 } from "zod";
|
|
10935
|
-
import {
|
|
10936
|
-
import { extname as extname6 } from "path";
|
|
10937
|
-
import { compare as compare2, markdownToHwpx, parse } from "@clazic/kordoc";
|
|
10945
|
+
import { readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
10946
|
+
import { extname as extname6, join as join4, relative as relative2 } from "path";
|
|
10938
10947
|
import { z as z6 } from "zod";
|
|
10948
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
10949
|
+
import { extname as extname7 } from "path";
|
|
10950
|
+
import { compare as compare2, parse, patchHwp, patchHwpx } from "kordoc";
|
|
10951
|
+
import { z as z7 } from "zod";
|
|
10939
10952
|
import {
|
|
10940
10953
|
Document,
|
|
10941
10954
|
HeadingLevel,
|
|
@@ -10947,41 +10960,45 @@ import {
|
|
|
10947
10960
|
TextRun,
|
|
10948
10961
|
WidthType
|
|
10949
10962
|
} from "docx";
|
|
10950
|
-
import { readFile as readFile7 } from "fs/promises";
|
|
10951
|
-
import { extname as extname7 } from "path";
|
|
10952
|
-
import { parse as parse2 } from "@clazic/kordoc";
|
|
10953
|
-
import { z as z7 } from "zod";
|
|
10954
10963
|
import { readFile as readFile8 } from "fs/promises";
|
|
10955
10964
|
import { extname as extname8 } from "path";
|
|
10956
|
-
import {
|
|
10957
|
-
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
10965
|
+
import { parse as parse2 } from "kordoc";
|
|
10958
10966
|
import { z as z8 } from "zod";
|
|
10959
10967
|
import { readFile as readFile9 } from "fs/promises";
|
|
10960
10968
|
import { extname as extname9 } from "path";
|
|
10961
|
-
import
|
|
10969
|
+
import { extractFormFields, parse as parse3, patchHwpx as patchHwpx2 } from "kordoc";
|
|
10962
10970
|
import { z as z9 } from "zod";
|
|
10963
10971
|
import { readFile as readFile10 } from "fs/promises";
|
|
10964
|
-
import { extname as extname10 } from "path";
|
|
10965
|
-
|
|
10972
|
+
import { basename as basename4, extname as extname10 } from "path";
|
|
10973
|
+
var import_jszip5 = __toESM(require_lib3(), 1);
|
|
10974
|
+
var import_jszip6 = __toESM(require_lib3(), 1);
|
|
10966
10975
|
import { z as z10 } from "zod";
|
|
10967
|
-
import { readFile as readFile11
|
|
10976
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
10968
10977
|
import { extname as extname11 } from "path";
|
|
10969
|
-
import
|
|
10978
|
+
import ExcelJS from "exceljs";
|
|
10970
10979
|
import { z as z11 } from "zod";
|
|
10971
|
-
import { readFile as fsReadFile, stat as stat5 } from "fs/promises";
|
|
10972
|
-
import { z as z12 } from "zod";
|
|
10973
10980
|
import { readFile as readFile12 } from "fs/promises";
|
|
10974
10981
|
import { extname as extname12 } from "path";
|
|
10975
|
-
import { parse as
|
|
10976
|
-
import { z as
|
|
10977
|
-
import { stat as
|
|
10982
|
+
import { parse as parse4 } from "kordoc";
|
|
10983
|
+
import { z as z12 } from "zod";
|
|
10984
|
+
import { readFile as readFile13, stat as stat4 } from "fs/promises";
|
|
10978
10985
|
import { extname as extname13 } from "path";
|
|
10979
|
-
import {
|
|
10986
|
+
import { parse as parse5 } from "kordoc";
|
|
10987
|
+
import { z as z13 } from "zod";
|
|
10988
|
+
import { readFile as fsReadFile, stat as stat5 } from "fs/promises";
|
|
10980
10989
|
import { z as z14 } from "zod";
|
|
10981
|
-
import {
|
|
10990
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
10982
10991
|
import { extname as extname14 } from "path";
|
|
10983
|
-
import
|
|
10992
|
+
import { parse as parse6 } from "kordoc";
|
|
10984
10993
|
import { z as z15 } from "zod";
|
|
10994
|
+
import { stat as stat6 } from "fs/promises";
|
|
10995
|
+
import { extname as extname15 } from "path";
|
|
10996
|
+
import { markdownToHwpx } from "kordoc";
|
|
10997
|
+
import { z as z16 } from "zod";
|
|
10998
|
+
import { stat as stat7 } from "fs/promises";
|
|
10999
|
+
import { extname as extname16 } from "path";
|
|
11000
|
+
import ExcelJS2 from "exceljs";
|
|
11001
|
+
import { z as z17 } from "zod";
|
|
10985
11002
|
async function resolveSafePath(cwd, p) {
|
|
10986
11003
|
const normalizedCwd = normalize(cwd).normalize("NFC");
|
|
10987
11004
|
const normalizedP = p.normalize("NFC");
|
|
@@ -11481,458 +11498,357 @@ var compareDocumentsTool = {
|
|
|
11481
11498
|
return output;
|
|
11482
11499
|
}
|
|
11483
11500
|
};
|
|
11484
|
-
|
|
11485
|
-
|
|
11501
|
+
var cellEditItemSchema = z32.object({
|
|
11502
|
+
tableIndex: z32.number().int().nonnegative().optional().describe(
|
|
11503
|
+
"\uC88C\uD45C \uBAA8\uB4DC: 0-based \uD45C \uC778\uB371\uC2A4(read_document\uC758 kordoc \uBE14\uB85D \uC21C\uC11C, \uC911\uCCA9\uD45C \uC81C\uC678). \uB808\uC774\uBE14 \uBAA8\uB4DC\uC5D0\uC120 \uD0D0\uC0C9 \uBC94\uC704 \uC81C\uD55C\uC6A9(\uC120\uD0DD)."
|
|
11504
|
+
),
|
|
11505
|
+
row: z32.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 rowAddr (0-based)"),
|
|
11506
|
+
col: z32.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 colAddr (0-based)"),
|
|
11507
|
+
label: z32.string().optional().describe(
|
|
11508
|
+
"\uB808\uC774\uBE14 \uBAA8\uB4DC: \uAE30\uC900 \uC140 \uD14D\uC2A4\uD2B8(\uD2B8\uB9BC \uBE44\uAD50). \uC774 \uC140\uC758 direction \uBC29\uD5A5 \uC778\uC811 \uC140\uC5D0 newText\uB97C \uAE30\uB85D. \uC88C\uD45C \uBAA8\uB4DC\uBA74 \uC0DD\uB7B5."
|
|
11509
|
+
),
|
|
11510
|
+
direction: z32.enum(["right", "below"]).optional().describe("\uB808\uC774\uBE14 \uBAA8\uB4DC \uBC29\uD5A5. \uAE30\uBCF8 right(\uC624\uB978\uCABD \uC140), below(\uC544\uB798 \uC140). \uBCD1\uD569 span \uACE0\uB824."),
|
|
11511
|
+
newText: z32.string().describe("\uC140\uC5D0 \uC4F8 \uC0C8 \uD14D\uC2A4\uD2B8"),
|
|
11512
|
+
expectedText: z32.string().optional().describe(
|
|
11513
|
+
"\uD604\uC7AC \uC140 \uD14D\uC2A4\uD2B8(\uC548\uC804 \uAC80\uC99D\uC6A9). \uBD88\uC77C\uCE58 \uC2DC \uC218\uC815\uD558\uC9C0 \uC54A\uC74C. \uC798\uBABB\uB41C \uC140 \uC218\uC815 \uBC29\uC9C0\uB97C \uC704\uD574 \uAD8C\uC7A5."
|
|
11514
|
+
)
|
|
11515
|
+
}).describe(
|
|
11516
|
+
"\uD3B8\uC9D1 \uD56D\uBAA9. \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label[+direction]) \uC911 \uD558\uB098\uB97C \uC0AC\uC6A9\uD558\uC138\uC694. \uB458 \uB2E4 \uC9C0\uC815\uD558\uAC70\uB098 \uB458 \uB2E4 \uC0DD\uB7B5\uD558\uBA74 \uC624\uB958\uC785\uB2C8\uB2E4."
|
|
11517
|
+
);
|
|
11518
|
+
var proposeCellEditSchema = z32.object({
|
|
11519
|
+
path: z32.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
11520
|
+
edits: z32.array(cellEditItemSchema).min(1).describe(
|
|
11521
|
+
"\uD3B8\uC9D1 \uBAA9\uB85D. \uAC01 \uD56D\uBAA9\uC740 \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label+direction) \uC911 \uD558\uB098"
|
|
11522
|
+
),
|
|
11523
|
+
summary: z32.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
11524
|
+
});
|
|
11525
|
+
function tokenizeHwpxXml(xml) {
|
|
11526
|
+
const tokens = [];
|
|
11527
|
+
const re = /<hp:tbl[\s>]|<\/hp:tbl>|<hp:tc[\s>]|<\/hp:tc>|<hp:t\/>|<hp:t>|<hp:cellAddr[^/>]*|<hp:cellSpan[^/>]*/g;
|
|
11528
|
+
let startPos = 0;
|
|
11529
|
+
let m = re.exec(xml);
|
|
11530
|
+
while (m !== null) {
|
|
11531
|
+
const raw = m[0];
|
|
11532
|
+
const pos = m.index;
|
|
11533
|
+
if (raw.startsWith("<hp:tbl")) {
|
|
11534
|
+
tokens.push({ kind: "tbl_open", pos, end: pos + raw.length });
|
|
11535
|
+
} else if (raw === "</hp:tbl>") {
|
|
11536
|
+
tokens.push({ kind: "tbl_close", pos, end: pos + raw.length });
|
|
11537
|
+
} else if (raw.startsWith("<hp:tc")) {
|
|
11538
|
+
tokens.push({ kind: "tc_open", pos, end: pos + raw.length });
|
|
11539
|
+
} else if (raw === "</hp:tc>") {
|
|
11540
|
+
tokens.push({ kind: "tc_close", pos, end: pos + raw.length });
|
|
11541
|
+
} else if (raw === "<hp:t/>") {
|
|
11542
|
+
tokens.push({ kind: "t_empty", pos, end: pos + raw.length });
|
|
11543
|
+
} else if (raw === "<hp:t>") {
|
|
11544
|
+
tokens.push({ kind: "t_open", pos, end: pos + raw.length });
|
|
11545
|
+
} else if (raw.startsWith("<hp:cellAddr")) {
|
|
11546
|
+
const colM = raw.match(/colAddr="(\d+)"/);
|
|
11547
|
+
const rowM = raw.match(/rowAddr="(\d+)"/);
|
|
11548
|
+
if (colM && rowM) {
|
|
11549
|
+
const selfClose = xml.indexOf("/>", pos);
|
|
11550
|
+
const end = selfClose >= 0 ? selfClose + 2 : pos + raw.length;
|
|
11551
|
+
tokens.push({
|
|
11552
|
+
kind: "cell_addr",
|
|
11553
|
+
pos,
|
|
11554
|
+
end,
|
|
11555
|
+
colAddr: Number(colM[1]),
|
|
11556
|
+
rowAddr: Number(rowM[1])
|
|
11557
|
+
});
|
|
11558
|
+
}
|
|
11559
|
+
} else if (raw.startsWith("<hp:cellSpan")) {
|
|
11560
|
+
const colM = raw.match(/colSpan="(\d+)"/);
|
|
11561
|
+
const rowM = raw.match(/rowSpan="(\d+)"/);
|
|
11562
|
+
const selfClose = xml.indexOf("/>", pos);
|
|
11563
|
+
const end = selfClose >= 0 ? selfClose + 2 : pos + raw.length;
|
|
11564
|
+
tokens.push({
|
|
11565
|
+
kind: "cell_span",
|
|
11566
|
+
pos,
|
|
11567
|
+
end,
|
|
11568
|
+
colSpan: colM ? Number(colM[1]) : 1,
|
|
11569
|
+
rowSpan: rowM ? Number(rowM[1]) : 1
|
|
11570
|
+
});
|
|
11571
|
+
}
|
|
11572
|
+
startPos = re.lastIndex;
|
|
11573
|
+
m = re.exec(xml);
|
|
11574
|
+
}
|
|
11575
|
+
void startPos;
|
|
11576
|
+
return tokens;
|
|
11486
11577
|
}
|
|
11487
|
-
function
|
|
11488
|
-
return text3.replace(
|
|
11578
|
+
function escapeXml(text3) {
|
|
11579
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
11489
11580
|
}
|
|
11490
|
-
function
|
|
11491
|
-
const
|
|
11492
|
-
const
|
|
11493
|
-
|
|
11581
|
+
function collectDirectTcRanges(tokens, tblStart, tblEnd) {
|
|
11582
|
+
const tblTokens = tokens.filter((t) => t.pos > tblStart && t.pos < tblEnd);
|
|
11583
|
+
const tcRanges = [];
|
|
11584
|
+
const tcStack = [];
|
|
11585
|
+
let innerDepth = 0;
|
|
11586
|
+
for (const tok of tblTokens) {
|
|
11587
|
+
if (tok.kind === "tbl_open") {
|
|
11588
|
+
innerDepth++;
|
|
11589
|
+
} else if (tok.kind === "tbl_close") {
|
|
11590
|
+
innerDepth--;
|
|
11591
|
+
} else if (tok.kind === "tc_open") {
|
|
11592
|
+
tcStack.push({ pos: tok.pos, depth: innerDepth });
|
|
11593
|
+
} else if (tok.kind === "tc_close") {
|
|
11594
|
+
const entry = tcStack.pop();
|
|
11595
|
+
if (entry !== void 0) {
|
|
11596
|
+
tcRanges.push({ start: entry.pos, end: tok.end, depth: entry.depth });
|
|
11597
|
+
}
|
|
11598
|
+
}
|
|
11599
|
+
}
|
|
11600
|
+
return tcRanges.filter((tc) => tc.depth === 0);
|
|
11494
11601
|
}
|
|
11495
|
-
function
|
|
11496
|
-
const
|
|
11497
|
-
let
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
for (let m = re.exec(xml); m !== null; m = re.exec(xml)) {
|
|
11509
|
-
hits.push({ pos: m.index, xmlTag: spec.xmlTag, type: spec.type });
|
|
11602
|
+
function readOwnTextFromTc(xml, tokens, tcStart, tcEnd) {
|
|
11603
|
+
const tcTokens = tokens.filter((t) => t.pos >= tcStart && t.pos < tcEnd);
|
|
11604
|
+
let innerDepth = 0;
|
|
11605
|
+
let text3 = "";
|
|
11606
|
+
for (const t of tcTokens) {
|
|
11607
|
+
if (t.kind === "tbl_open") innerDepth++;
|
|
11608
|
+
else if (t.kind === "tbl_close") innerDepth--;
|
|
11609
|
+
else if (t.kind === "t_empty" && innerDepth === 0) {
|
|
11610
|
+
} else if (t.kind === "t_open" && innerDepth === 0) {
|
|
11611
|
+
const closePos = xml.indexOf("</hp:t>", t.end);
|
|
11612
|
+
if (closePos >= 0) {
|
|
11613
|
+
text3 += xml.substring(t.end, closePos);
|
|
11614
|
+
}
|
|
11510
11615
|
}
|
|
11511
11616
|
}
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
const name = getAttr(openTag, "name");
|
|
11524
|
-
let currentValue;
|
|
11525
|
-
let comboItems;
|
|
11526
|
-
switch (type) {
|
|
11527
|
-
case "button":
|
|
11528
|
-
currentValue = getAttr(openTag, "caption");
|
|
11529
|
-
break;
|
|
11530
|
-
case "checkBox":
|
|
11531
|
-
case "radioButton":
|
|
11532
|
-
currentValue = getAttr(openTag, "value") === "CHECKED";
|
|
11533
|
-
break;
|
|
11534
|
-
case "comboBox": {
|
|
11535
|
-
currentValue = getAttr(openTag, "selectedValue");
|
|
11536
|
-
const listItemRe = /<hp:listItem\b[^>]*/g;
|
|
11537
|
-
const items = [];
|
|
11538
|
-
for (let lm = listItemRe.exec(elementXml); lm !== null; lm = listItemRe.exec(elementXml)) {
|
|
11539
|
-
const itemValue = getAttr(lm[0] ?? "", "value");
|
|
11540
|
-
items.push(itemValue);
|
|
11617
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
11618
|
+
}
|
|
11619
|
+
function findTopLevelTableRange(tokens, tableIndex) {
|
|
11620
|
+
let topLevelCount = 0;
|
|
11621
|
+
let depth = 0;
|
|
11622
|
+
let targetStart = -1;
|
|
11623
|
+
for (const tok of tokens) {
|
|
11624
|
+
if (tok.kind === "tbl_open") {
|
|
11625
|
+
if (depth === 0) {
|
|
11626
|
+
if (topLevelCount === tableIndex) {
|
|
11627
|
+
targetStart = tok.pos;
|
|
11541
11628
|
}
|
|
11542
|
-
|
|
11543
|
-
break;
|
|
11629
|
+
topLevelCount++;
|
|
11544
11630
|
}
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
currentValue = "";
|
|
11551
|
-
} else {
|
|
11552
|
-
const tOpenIdx = elementXml.search(textOpen);
|
|
11553
|
-
if (tOpenIdx >= 0) {
|
|
11554
|
-
const afterOpen = elementXml.indexOf(">", tOpenIdx) + 1;
|
|
11555
|
-
const closePos = elementXml.indexOf(textClose, afterOpen);
|
|
11556
|
-
currentValue = closePos >= 0 ? decodeXml(elementXml.slice(afterOpen, closePos)) : "";
|
|
11557
|
-
} else {
|
|
11558
|
-
currentValue = "";
|
|
11559
|
-
}
|
|
11560
|
-
}
|
|
11561
|
-
break;
|
|
11631
|
+
depth++;
|
|
11632
|
+
} else if (tok.kind === "tbl_close") {
|
|
11633
|
+
depth--;
|
|
11634
|
+
if (depth === 0 && topLevelCount === tableIndex + 1 && targetStart >= 0) {
|
|
11635
|
+
return { start: targetStart, end: tok.end };
|
|
11562
11636
|
}
|
|
11563
11637
|
}
|
|
11564
|
-
results.push({
|
|
11565
|
-
index: idx++,
|
|
11566
|
-
name,
|
|
11567
|
-
type,
|
|
11568
|
-
currentValue,
|
|
11569
|
-
comboItems,
|
|
11570
|
-
sectionFile,
|
|
11571
|
-
posInSection: pos
|
|
11572
|
-
});
|
|
11573
11638
|
}
|
|
11574
|
-
return
|
|
11639
|
+
return null;
|
|
11575
11640
|
}
|
|
11576
|
-
function
|
|
11577
|
-
const
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
|
|
11585
|
-
if (openTagEnd < 0) {
|
|
11586
|
-
results[ei] = {
|
|
11587
|
-
success: false,
|
|
11588
|
-
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}" \uC5EC\uB294 \uD0DC\uADF8 \uB05D\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
11589
|
-
};
|
|
11590
|
-
continue;
|
|
11641
|
+
function readCellAddrSpan(tokens, tcStart, tcEnd) {
|
|
11642
|
+
const tcTokens = tokens.filter((t) => t.pos >= tcStart && t.pos < tcEnd);
|
|
11643
|
+
let addr = null;
|
|
11644
|
+
let span = { colSpan: 1, rowSpan: 1 };
|
|
11645
|
+
for (const t of tcTokens) {
|
|
11646
|
+
if (t.kind === "cell_addr" && t.colAddr !== void 0 && t.rowAddr !== void 0) {
|
|
11647
|
+
addr = { colAddr: t.colAddr, rowAddr: t.rowAddr };
|
|
11648
|
+
} else if (t.kind === "cell_span" && t.colSpan !== void 0 && t.rowSpan !== void 0) {
|
|
11649
|
+
span = { colSpan: t.colSpan, rowSpan: t.rowSpan };
|
|
11591
11650
|
}
|
|
11592
|
-
|
|
11593
|
-
|
|
11594
|
-
|
|
11595
|
-
|
|
11651
|
+
}
|
|
11652
|
+
if (!addr) return null;
|
|
11653
|
+
return { ...addr, ...span };
|
|
11654
|
+
}
|
|
11655
|
+
function applyCellEditsToSectionXml(xml, edits) {
|
|
11656
|
+
const tokens = tokenizeHwpxXml(xml);
|
|
11657
|
+
const results = edits.map(() => ({ success: false }));
|
|
11658
|
+
let totalTopLevelTbls = 0;
|
|
11659
|
+
{
|
|
11660
|
+
let d = 0;
|
|
11661
|
+
for (const tok of tokens) {
|
|
11662
|
+
if (tok.kind === "tbl_open") {
|
|
11663
|
+
if (d === 0) totalTopLevelTbls++;
|
|
11664
|
+
d++;
|
|
11665
|
+
} else if (tok.kind === "tbl_close") {
|
|
11666
|
+
d--;
|
|
11667
|
+
}
|
|
11668
|
+
}
|
|
11669
|
+
}
|
|
11670
|
+
const replacements = [];
|
|
11671
|
+
for (let ei = 0; ei < edits.length; ei++) {
|
|
11672
|
+
const edit = edits[ei];
|
|
11673
|
+
const tblRange = findTopLevelTableRange(tokens, edit.tableIndex);
|
|
11674
|
+
if (!tblRange) {
|
|
11596
11675
|
results[ei] = {
|
|
11597
11676
|
success: false,
|
|
11598
|
-
error: `\
|
|
11677
|
+
error: `\uD45C ${edit.tableIndex}\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774 \uC139\uC158\uC5D0 \uCD1D ${totalTopLevelTbls}\uAC1C\uC758 \uCD5C\uC0C1\uC704 \uD45C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.`
|
|
11599
11678
|
};
|
|
11600
11679
|
continue;
|
|
11601
11680
|
}
|
|
11602
|
-
const
|
|
11603
|
-
const
|
|
11604
|
-
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
const items = target.comboItems ?? [];
|
|
11625
|
-
if (!items.includes(set.selected)) {
|
|
11626
|
-
const validList = items.map((v) => `"${v}"`).join(", ");
|
|
11627
|
-
results[ei] = {
|
|
11628
|
-
success: false,
|
|
11629
|
-
error: `comboBox "${target.name}"\uC758 selected \uAC12 "${set.selected}"\uC774 \uC720\uD6A8\uD55C \uD56D\uBAA9\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC720\uD6A8\uD55C \uD56D\uBAA9: ${validList || "(\uC5C6\uC74C)"}`
|
|
11630
|
-
};
|
|
11631
|
-
continue;
|
|
11681
|
+
const directTcs = collectDirectTcRanges(tokens, tblRange.start, tblRange.end);
|
|
11682
|
+
const tblTokens = tokens.filter((t) => t.pos >= tblRange.start && t.pos < tblRange.end);
|
|
11683
|
+
let found = false;
|
|
11684
|
+
for (const tc of directTcs) {
|
|
11685
|
+
const tcTokens = tblTokens.filter((t) => t.pos >= tc.start && t.pos < tc.end);
|
|
11686
|
+
const hasAddr = tcTokens.some(
|
|
11687
|
+
(t) => t.kind === "cell_addr" && t.colAddr === edit.col && t.rowAddr === edit.row
|
|
11688
|
+
);
|
|
11689
|
+
if (!hasAddr) continue;
|
|
11690
|
+
let innerDepth = 0;
|
|
11691
|
+
const ownTRuns = [];
|
|
11692
|
+
for (const t of tokens.filter((x) => x.pos >= tc.start && x.pos < tc.end)) {
|
|
11693
|
+
if (t.kind === "tbl_open") innerDepth++;
|
|
11694
|
+
else if (t.kind === "tbl_close") innerDepth--;
|
|
11695
|
+
else if (t.kind === "t_empty" && innerDepth === 0) {
|
|
11696
|
+
ownTRuns.push({ isEmpty: true, tagPos: t.pos, tagEnd: t.end });
|
|
11697
|
+
} else if (t.kind === "t_open" && innerDepth === 0) {
|
|
11698
|
+
const closePos = xml.indexOf("</hp:t>", t.end);
|
|
11699
|
+
if (closePos >= 0) {
|
|
11700
|
+
ownTRuns.push({ isEmpty: false, openEnd: t.end, closePos });
|
|
11701
|
+
}
|
|
11702
|
+
}
|
|
11632
11703
|
}
|
|
11633
|
-
|
|
11634
|
-
|
|
11635
|
-
if (set.caption !== void 0) {
|
|
11636
|
-
const patch = replaceAttrInOpenTag(xml, pos, openTagEnd, "caption", escapeXml(set.caption));
|
|
11637
|
-
if (!patch) {
|
|
11704
|
+
const currentText = ownTRuns.map((r) => r.isEmpty ? "" : xml.substring(r.openEnd, r.closePos)).join("").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
11705
|
+
if (edit.expectedText !== void 0 && edit.expectedText !== currentText) {
|
|
11638
11706
|
results[ei] = {
|
|
11639
11707
|
success: false,
|
|
11640
|
-
|
|
11708
|
+
oldText: currentText,
|
|
11709
|
+
error: `\uC140 (\uD45C ${edit.tableIndex}, \uD589 ${edit.row}, \uC5F4 ${edit.col})\uC758 \uD604\uC7AC \uD14D\uC2A4\uD2B8\uAC00 \uC608\uC0C1\uAC12\uACFC \uB2E4\uB985\uB2C8\uB2E4. \uC608\uC0C1: "${edit.expectedText}", \uC2E4\uC81C: "${currentText}". \uC218\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
|
|
11641
11710
|
};
|
|
11642
|
-
|
|
11711
|
+
found = true;
|
|
11712
|
+
break;
|
|
11643
11713
|
}
|
|
11644
|
-
|
|
11645
|
-
patchCreated = true;
|
|
11646
|
-
} else if (set.checked !== void 0) {
|
|
11647
|
-
const newValue = set.checked ? "CHECKED" : "UNCHECKED";
|
|
11648
|
-
const patch = replaceAttrInOpenTag(xml, pos, openTagEnd, "value", newValue);
|
|
11649
|
-
if (!patch) {
|
|
11714
|
+
if (ownTRuns.length === 0) {
|
|
11650
11715
|
results[ei] = {
|
|
11651
11716
|
success: false,
|
|
11652
|
-
|
|
11717
|
+
oldText: currentText,
|
|
11718
|
+
error: `\uC140 (\uD45C ${edit.tableIndex}, \uD589 ${edit.row}, \uC5F4 ${edit.col})\uC5D0 \uD14D\uC2A4\uD2B8 \uB7F0\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. <hp:t> \uB610\uB294 <hp:t/> \uB7F0\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC140 \uAD6C\uC870\uB97C \uD655\uC778\uD558\uC138\uC694.`
|
|
11653
11719
|
};
|
|
11654
|
-
|
|
11720
|
+
found = true;
|
|
11721
|
+
break;
|
|
11655
11722
|
}
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
|
|
11659
|
-
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
|
|
11665
|
-
|
|
11666
|
-
|
|
11667
|
-
results[ei] = {
|
|
11668
|
-
success: false,
|
|
11669
|
-
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 selectedValue \uC18D\uC131\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
11670
|
-
};
|
|
11671
|
-
continue;
|
|
11723
|
+
const escapedNew = escapeXml(edit.newText);
|
|
11724
|
+
const patches = [];
|
|
11725
|
+
const firstRun = ownTRuns[0];
|
|
11726
|
+
if (firstRun.isEmpty) {
|
|
11727
|
+
patches.push({
|
|
11728
|
+
from: firstRun.tagPos,
|
|
11729
|
+
to: firstRun.tagEnd,
|
|
11730
|
+
text: `<hp:t>${escapedNew}</hp:t>`
|
|
11731
|
+
});
|
|
11732
|
+
} else {
|
|
11733
|
+
patches.push({ from: firstRun.openEnd, to: firstRun.closePos, text: escapedNew });
|
|
11672
11734
|
}
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
|
|
11678
|
-
if (!textPatch) {
|
|
11679
|
-
results[ei] = {
|
|
11680
|
-
success: false,
|
|
11681
|
-
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 <hp:text> \uC694\uC18C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
11682
|
-
};
|
|
11683
|
-
continue;
|
|
11735
|
+
for (let ri = 1; ri < ownTRuns.length; ri++) {
|
|
11736
|
+
const run = ownTRuns[ri];
|
|
11737
|
+
if (!run.isEmpty) {
|
|
11738
|
+
patches.push({ from: run.openEnd, to: run.closePos, text: "" });
|
|
11739
|
+
}
|
|
11684
11740
|
}
|
|
11685
|
-
|
|
11686
|
-
|
|
11741
|
+
replacements.push({ editIdx: ei, patches });
|
|
11742
|
+
results[ei] = { success: true, oldText: currentText };
|
|
11743
|
+
found = true;
|
|
11744
|
+
break;
|
|
11687
11745
|
}
|
|
11688
|
-
if (!
|
|
11689
|
-
results[ei] = {
|
|
11690
|
-
|
|
11746
|
+
if (!found) {
|
|
11747
|
+
results[ei] = {
|
|
11748
|
+
success: false,
|
|
11749
|
+
error: `\uD45C ${edit.tableIndex}\uC5D0\uC11C \uC140 (\uD589 ${edit.row}, \uC5F4 ${edit.col})\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. cellAddr colAddr="${edit.col}" rowAddr="${edit.row}"\uC5D0 \uD574\uB2F9\uD558\uB294 \uC140\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
11750
|
+
};
|
|
11691
11751
|
}
|
|
11692
|
-
results[ei] = { success: true, oldValue: currentRaw };
|
|
11693
11752
|
}
|
|
11694
11753
|
if (results.some((r) => !r.success)) {
|
|
11695
11754
|
return { newXml: xml, results };
|
|
11696
11755
|
}
|
|
11697
|
-
const
|
|
11756
|
+
const allPatches = replacements.flatMap((r) => r.patches).sort((a, b) => b.from - a.from);
|
|
11698
11757
|
let result = xml;
|
|
11699
|
-
for (const patch of
|
|
11700
|
-
result = result.
|
|
11758
|
+
for (const patch of allPatches) {
|
|
11759
|
+
result = result.substring(0, patch.from) + patch.text + result.substring(patch.to);
|
|
11701
11760
|
}
|
|
11702
11761
|
return { newXml: result, results };
|
|
11703
11762
|
}
|
|
11704
|
-
function
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
button: "caption",
|
|
11723
|
-
checkBox: "checked",
|
|
11724
|
-
radioButton: "checked",
|
|
11725
|
-
comboBox: "selected",
|
|
11726
|
-
edit: "text"
|
|
11727
|
-
};
|
|
11728
|
-
if (key !== allowed[type]) {
|
|
11729
|
-
const typeKo = {
|
|
11730
|
-
button: "PushButton",
|
|
11731
|
-
checkBox: "CheckBox",
|
|
11732
|
-
radioButton: "RadioButton",
|
|
11733
|
-
comboBox: "ComboBox",
|
|
11734
|
-
edit: "Edit"
|
|
11735
|
-
};
|
|
11736
|
-
return `\uD0C0\uC785 \uBD88\uC77C\uCE58: ${typeKo[type]} \uC591\uC2DD \uAC1C\uCCB4\uC5D0\uB294 "${allowed[type]}" \uD544\uB4DC\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5\uD558\uC9C0\uB9CC "${key}"\uC774(\uAC00) \uC9C0\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`;
|
|
11737
|
-
}
|
|
11738
|
-
return null;
|
|
11739
|
-
}
|
|
11740
|
-
function readCurrentValue(xml, pos, openTagEnd, _afterOpen, elementEnd, type) {
|
|
11741
|
-
const openTag = xml.slice(pos, openTagEnd + 1);
|
|
11742
|
-
switch (type) {
|
|
11743
|
-
case "button":
|
|
11744
|
-
return decodeXml(getAttr(openTag, "caption"));
|
|
11745
|
-
case "checkBox":
|
|
11746
|
-
case "radioButton":
|
|
11747
|
-
return getAttr(openTag, "value") === "CHECKED";
|
|
11748
|
-
case "comboBox":
|
|
11749
|
-
return decodeXml(getAttr(openTag, "selectedValue"));
|
|
11750
|
-
case "edit": {
|
|
11751
|
-
const elementContent = xml.slice(pos, elementEnd);
|
|
11752
|
-
if (/<hp:text\s*\/>/.test(elementContent)) return "";
|
|
11753
|
-
const tOpenIdx = elementContent.search(/<hp:text>/);
|
|
11754
|
-
if (tOpenIdx >= 0) {
|
|
11755
|
-
const afterOpen = elementContent.indexOf(">", tOpenIdx) + 1;
|
|
11756
|
-
const closePos = elementContent.indexOf("</hp:text>", afterOpen);
|
|
11757
|
-
return closePos >= 0 ? decodeXml(elementContent.slice(afterOpen, closePos)) : "";
|
|
11763
|
+
async function applyEditsToHwpx(hwpxBuffer, edits) {
|
|
11764
|
+
const zip = await import_jszip2.default.loadAsync(hwpxBuffer);
|
|
11765
|
+
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
11766
|
+
const sectionXmls = [];
|
|
11767
|
+
const sectionTblCounts = [];
|
|
11768
|
+
for (const sf of sectionFiles) {
|
|
11769
|
+
const entry = zip.file(sf);
|
|
11770
|
+
const xml = entry ? await entry.async("string") : "";
|
|
11771
|
+
sectionXmls.push(xml);
|
|
11772
|
+
const tokens = tokenizeHwpxXml(xml);
|
|
11773
|
+
let count = 0;
|
|
11774
|
+
let depth = 0;
|
|
11775
|
+
for (const tok of tokens) {
|
|
11776
|
+
if (tok.kind === "tbl_open") {
|
|
11777
|
+
if (depth === 0) count++;
|
|
11778
|
+
depth++;
|
|
11779
|
+
} else if (tok.kind === "tbl_close") {
|
|
11780
|
+
depth--;
|
|
11758
11781
|
}
|
|
11759
|
-
return "";
|
|
11760
11782
|
}
|
|
11783
|
+
sectionTblCounts.push(count);
|
|
11761
11784
|
}
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
let
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
from: tagStart + relFrom,
|
|
11785
|
-
to: tagStart + relTo,
|
|
11786
|
-
text: newValue
|
|
11787
|
-
};
|
|
11788
|
-
}
|
|
11789
|
-
function replaceEditText(_xml, pos, elementContent, newText) {
|
|
11790
|
-
const escaped = escapeXml(newText);
|
|
11791
|
-
const selfCloseRe = /<hp:text\s*\/>/;
|
|
11792
|
-
const scm = selfCloseRe.exec(elementContent);
|
|
11793
|
-
if (scm) {
|
|
11794
|
-
return {
|
|
11795
|
-
from: pos + scm.index,
|
|
11796
|
-
to: pos + scm.index + scm[0].length,
|
|
11797
|
-
text: `<hp:text>${escaped}</hp:text>`
|
|
11798
|
-
};
|
|
11799
|
-
}
|
|
11800
|
-
const openRe = /<hp:text>/;
|
|
11801
|
-
const om = openRe.exec(elementContent);
|
|
11802
|
-
if (om) {
|
|
11803
|
-
const afterOpen = om.index + om[0].length;
|
|
11804
|
-
const closePos = elementContent.indexOf("</hp:text>", afterOpen);
|
|
11805
|
-
if (closePos < 0) return null;
|
|
11806
|
-
return {
|
|
11807
|
-
from: pos + afterOpen,
|
|
11808
|
-
to: pos + closePos,
|
|
11809
|
-
text: escaped
|
|
11810
|
-
};
|
|
11811
|
-
}
|
|
11812
|
-
return null;
|
|
11813
|
-
}
|
|
11814
|
-
async function listFormObjectsFromZip(zip) {
|
|
11815
|
-
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
11816
|
-
const sectionXmls = [];
|
|
11817
|
-
const objects = [];
|
|
11818
|
-
let globalIndex = 0;
|
|
11819
|
-
for (const sf of sectionFiles) {
|
|
11820
|
-
const entry = zip.file(sf);
|
|
11821
|
-
const xml = entry ? await entry.async("string") : "";
|
|
11822
|
-
sectionXmls.push(xml);
|
|
11823
|
-
const parsed = parseFormObjects(xml, sf, globalIndex);
|
|
11824
|
-
objects.push(...parsed);
|
|
11825
|
-
globalIndex += parsed.length;
|
|
11785
|
+
const sectionEdits = sectionFiles.map(() => []);
|
|
11786
|
+
let offset = 0;
|
|
11787
|
+
for (let si = 0; si < sectionFiles.length; si++) {
|
|
11788
|
+
const count = sectionTblCounts[si] ?? 0;
|
|
11789
|
+
for (let ei = 0; ei < edits.length; ei++) {
|
|
11790
|
+
const edit = edits[ei];
|
|
11791
|
+
if (edit.tableIndex >= offset && edit.tableIndex < offset + count) {
|
|
11792
|
+
const secEdits = sectionEdits[si];
|
|
11793
|
+
if (secEdits) {
|
|
11794
|
+
secEdits.push({
|
|
11795
|
+
tableIndex: edit.tableIndex - offset,
|
|
11796
|
+
// 섹션 내 상대 인덱스
|
|
11797
|
+
row: edit.row,
|
|
11798
|
+
col: edit.col,
|
|
11799
|
+
newText: edit.newText,
|
|
11800
|
+
expectedText: edit.expectedText,
|
|
11801
|
+
originalEditIdx: ei
|
|
11802
|
+
});
|
|
11803
|
+
}
|
|
11804
|
+
}
|
|
11805
|
+
}
|
|
11806
|
+
offset += count;
|
|
11826
11807
|
}
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11808
|
+
const totalTables = sectionTblCounts.reduce((a, b) => a + b, 0);
|
|
11809
|
+
const allResults = edits.map((edit, ei) => ({
|
|
11810
|
+
success: false,
|
|
11811
|
+
error: `\uD45C ${edit?.tableIndex ?? ei}\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C\uC5D0 \uCD1D ${totalTables}\uAC1C\uC758 \uCD5C\uC0C1\uC704 \uD45C\uAC00 \uC788\uC2B5\uB2C8\uB2E4.`
|
|
11812
|
+
}));
|
|
11813
|
+
const newSectionXmls = [...sectionXmls];
|
|
11814
|
+
for (let si = 0; si < sectionFiles.length; si++) {
|
|
11815
|
+
const sEdits = sectionEdits[si] ?? [];
|
|
11816
|
+
if (sEdits.length === 0) continue;
|
|
11817
|
+
const srcXml = sectionXmls[si] ?? "";
|
|
11818
|
+
const { newXml, results } = applyCellEditsToSectionXml(srcXml, sEdits);
|
|
11819
|
+
newSectionXmls[si] = newXml;
|
|
11820
|
+
for (let i = 0; i < sEdits.length; i++) {
|
|
11821
|
+
const sEdit = sEdits[i];
|
|
11822
|
+
const res = results[i];
|
|
11823
|
+
if (sEdit && res) {
|
|
11824
|
+
allResults[sEdit.originalEditIdx] = res;
|
|
11825
|
+
}
|
|
11826
|
+
}
|
|
11832
11827
|
}
|
|
11833
|
-
if (
|
|
11834
|
-
return
|
|
11828
|
+
if (allResults.some((r) => !r.success)) {
|
|
11829
|
+
return { buffer: hwpxBuffer, results: allResults };
|
|
11835
11830
|
}
|
|
11836
|
-
|
|
11837
|
-
|
|
11831
|
+
const out = new import_jszip2.default();
|
|
11832
|
+
const mimetypeEntry = zip.file("mimetype");
|
|
11833
|
+
if (mimetypeEntry) {
|
|
11834
|
+
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
11838
11835
|
}
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
checked: z32.boolean().optional().describe("CheckBox/RadioButton \uCCB4\uD06C \uC0C1\uD0DC (true=CHECKED)"),
|
|
11847
|
-
selected: z32.string().optional().describe("ComboBox \uC120\uD0DD \uAC12 (listItem \uC911 \uD558\uB098\uC5EC\uC57C \uD568)"),
|
|
11848
|
-
text: z32.string().optional().describe("Edit \uD14D\uC2A4\uD2B8 \uB0B4\uC6A9")
|
|
11849
|
-
}).refine(
|
|
11850
|
-
(v) => {
|
|
11851
|
-
const keys = ["caption", "checked", "selected", "text"].filter(
|
|
11852
|
-
(k) => v[k] !== void 0
|
|
11853
|
-
);
|
|
11854
|
-
return keys.length === 1;
|
|
11855
|
-
},
|
|
11856
|
-
{ message: "set \uD544\uB4DC\uB294 caption/checked/selected/text \uC911 \uC815\uD655\uD788 \uD558\uB098\uB9CC \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4." }
|
|
11857
|
-
);
|
|
11858
|
-
var formEditExpectedSchema = z32.object({
|
|
11859
|
-
caption: z32.string().optional(),
|
|
11860
|
-
checked: z32.boolean().optional(),
|
|
11861
|
-
selected: z32.string().optional(),
|
|
11862
|
-
text: z32.string().optional()
|
|
11863
|
-
}).optional();
|
|
11864
|
-
var formEditItemSchema = z32.object({
|
|
11865
|
-
name: z32.string().describe("\uC591\uC2DD \uAC1C\uCCB4\uC758 name \uC18D\uC131 \uAC12"),
|
|
11866
|
-
index: z32.number().int().nonnegative().optional().describe("\uB3D9\uC77C name\uC774 \uC5EC\uB7FF\uC778 \uACBD\uC6B0 \uBB38\uC11C \uC804\uCCB4 0-based \uC778\uB371\uC2A4\uB85C \uAD6C\uBD84"),
|
|
11867
|
-
set: formEditSetSchema.describe("\uBCC0\uACBD\uD560 \uAC12 (caption/checked/selected/text \uC911 \uD558\uB098)"),
|
|
11868
|
-
expected: formEditExpectedSchema.describe(
|
|
11869
|
-
"\uD604\uC7AC \uAC12 \uC0AC\uC804 \uAC80\uC99D (\uC548\uC804 \uC635\uC158). \uC2E4\uC81C \uAC12\uC774 \uB2E4\uB974\uBA74 \uC774 \uD3B8\uC9D1\uC744 \uCDE8\uC18C\uD558\uACE0 \uC624\uB958 \uBC18\uD658."
|
|
11870
|
-
)
|
|
11871
|
-
});
|
|
11872
|
-
var proposeFormObjectSchema = z32.object({
|
|
11873
|
-
path: z32.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C"),
|
|
11874
|
-
edits: z32.array(formEditItemSchema).min(1).describe("\uC591\uC2DD \uAC1C\uCCB4 \uD3B8\uC9D1 \uBAA9\uB85D"),
|
|
11875
|
-
summary: z32.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
11876
|
-
});
|
|
11877
|
-
var listFormObjectsTool = {
|
|
11878
|
-
name: "list_form_objects",
|
|
11879
|
-
description: "HWPX \uBB38\uC11C\uC758 \uC591\uC2DD \uAC1C\uCCB4(form object) \uBAA9\uB85D\uC744 \uC5F4\uAC70\uD569\uB2C8\uB2E4. PushButton, CheckBox, RadioButton, ComboBox, Edit \uB2E4\uC12F \uAC00\uC9C0 \uD0C0\uC785\uC744 \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uAC01 \uC591\uC2DD \uAC1C\uCCB4\uC758 \uC774\uB984(name), \uD0C0\uC785, \uD604\uC7AC \uAC12, ComboBox\uC758 \uACBD\uC6B0 \uC120\uD0DD \uAC00\uB2A5\uD55C \uD56D\uBAA9 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. propose_form_object\uB85C \uAC12\uC744 \uC218\uC815\uD558\uAE30 \uC804\uC5D0 \uC774 \uD234\uB85C \uBA3C\uC800 \uD604\uC7AC \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. .hwpx \uD30C\uC77C \uC804\uC6A9\uC785\uB2C8\uB2E4.",
|
|
11880
|
-
inputSchema: listFormObjectsSchema,
|
|
11881
|
-
requiresApproval: false,
|
|
11882
|
-
execute: async ({
|
|
11883
|
-
input,
|
|
11884
|
-
ctx
|
|
11885
|
-
}) => {
|
|
11886
|
-
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
11887
|
-
const ext = extname3(safePath).toLowerCase();
|
|
11888
|
-
let buffer;
|
|
11889
|
-
try {
|
|
11890
|
-
buffer = await readFile4(safePath);
|
|
11891
|
-
} catch {
|
|
11892
|
-
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
11893
|
-
}
|
|
11894
|
-
const validationError = validateHwpxBuffer(ext, new Uint8Array(buffer.buffer));
|
|
11895
|
-
if (validationError) return validationError;
|
|
11896
|
-
let zip;
|
|
11897
|
-
try {
|
|
11898
|
-
zip = await import_jszip.default.loadAsync(new Uint8Array(buffer.buffer));
|
|
11899
|
-
} catch {
|
|
11900
|
-
return "\uC624\uB958: .hwpx(ZIP) \uD30C\uC77C\uC744 \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
11901
|
-
}
|
|
11902
|
-
const { objects } = await listFormObjectsFromZip(zip);
|
|
11903
|
-
if (objects.length === 0) {
|
|
11904
|
-
return "\uC774 \uBB38\uC11C\uC5D0\uB294 \uC591\uC2DD \uAC1C\uCCB4(form object)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
11905
|
-
}
|
|
11906
|
-
const lines = [`\uCD1D ${objects.length}\uAC1C\uC758 \uC591\uC2DD \uAC1C\uCCB4\uAC00 \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
11907
|
-
`];
|
|
11908
|
-
const typeKo = {
|
|
11909
|
-
button: "PushButton",
|
|
11910
|
-
checkBox: "CheckBox",
|
|
11911
|
-
radioButton: "RadioButton",
|
|
11912
|
-
comboBox: "ComboBox",
|
|
11913
|
-
edit: "Edit"
|
|
11914
|
-
};
|
|
11915
|
-
for (const obj of objects) {
|
|
11916
|
-
let valueStr;
|
|
11917
|
-
if (typeof obj.currentValue === "boolean") {
|
|
11918
|
-
valueStr = obj.currentValue ? "\uCCB4\uD06C\uB428 (CHECKED)" : "\uCCB4\uD06C \uD574\uC81C\uB428 (UNCHECKED)";
|
|
11919
|
-
} else {
|
|
11920
|
-
valueStr = `"${obj.currentValue}"`;
|
|
11921
|
-
}
|
|
11922
|
-
let line = `[${obj.index}] name="${obj.name}" | \uD0C0\uC785: ${typeKo[obj.type]} | \uD604\uC7AC \uAC12: ${valueStr}`;
|
|
11923
|
-
if (obj.type === "comboBox" && obj.comboItems) {
|
|
11924
|
-
const itemList = obj.comboItems.map((v) => `"${v}"`).join(", ");
|
|
11925
|
-
line += ` | \uD56D\uBAA9: [${itemList}]`;
|
|
11926
|
-
}
|
|
11927
|
-
lines.push(line);
|
|
11836
|
+
for (const [name, entry] of Object.entries(zip.files)) {
|
|
11837
|
+
if (name === "mimetype" || entry.dir) continue;
|
|
11838
|
+
const sectionIdx = sectionFiles.indexOf(name);
|
|
11839
|
+
if (sectionIdx >= 0) {
|
|
11840
|
+
out.file(name, newSectionXmls[sectionIdx] ?? "");
|
|
11841
|
+
} else {
|
|
11842
|
+
out.file(name, await entry.async("uint8array"));
|
|
11928
11843
|
}
|
|
11929
|
-
return lines.join("\n");
|
|
11930
11844
|
}
|
|
11931
|
-
};
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11845
|
+
const buf = await out.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
11846
|
+
return { buffer: new Uint8Array(buf), results: allResults };
|
|
11847
|
+
}
|
|
11848
|
+
var proposeCellEditTool = {
|
|
11849
|
+
name: "propose_cell_edit",
|
|
11850
|
+
description: "HWPX \uBB38\uC11C\uC758 \uD45C \uC140 \uB0B4\uC6A9\uC744 XML \uC9C1\uC811 \uD328\uCE58 \uBC29\uC2DD\uC73C\uB85C \uC218\uC815\uD569\uB2C8\uB2E4. \uBCD1\uD569 \uC140(cellSpan/rowSpan)\uC774 \uC788\uB294 \uD45C\uC5D0\uC11C\uB3C4 \uBCD1\uD569 \uAD6C\uC870\uB97C \uC644\uC804\uD788 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uBE48 \uC140(<hp:t/> self-closing \uB7F0)\uB3C4 \uCC44\uC6B8 \uC218 \uC788\uC5B4 \uC591\uC2DD(form) \uD3B8\uC9D1\uC5D0 \uC801\uD569\uD569\uB2C8\uB2E4. \uC140 \uC8FC\uC18C \uC9C0\uC815 \uBC29\uBC95: (1) \uC88C\uD45C \uBAA8\uB4DC \u2014 tableIndex + row + col \uC9C1\uC811 \uC9C0\uC815. (2) \uB808\uC774\uBE14 \uBAA8\uB4DC \u2014 label(\uC778\uC811 \uB808\uC774\uBE14 \uC140 \uD14D\uC2A4\uD2B8) + direction(right/below, \uAE30\uBCF8 right) + \uC120\uD0DD\uC801 tableIndex\uB85C \uB808\uC774\uBE14 \uC606/\uC544\uB798 \uC140\uC744 \uC790\uB3D9\uC73C\uB85C \uCC3E\uC544 \uD3B8\uC9D1. \uBCD1\uD569 \uB808\uC774\uBE14 \uC140\uB3C4 colSpan/rowSpan\uC744 \uBC18\uC601\uD558\uC5EC \uB300\uC0C1 \uC140\uC744 \uACC4\uC0B0\uD569\uB2C8\uB2E4. propose_edit/propose_form_fill\uC740 \uB9C8\uD06C\uB2E4\uC6B4 \uB77C\uC6B4\uB4DC\uD2B8\uB9BD\uC73C\uB85C \uBCD1\uD569 \uC140\uC744 \uC18C\uC2E4\uC2DC\uD0A4\uBBC0\uB85C, \uBCD1\uD569 \uC140\uC774 \uC788\uB294 \uD45C\uB97C \uC218\uC815\uD560 \uB54C\uB294 \uC774 \uD234\uC744 \uC0AC\uC6A9\uD558\uC138\uC694. .hwpx \uD30C\uC77C \uC804\uC6A9\uC785\uB2C8\uB2E4. .hwp\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC73C\uBA70 Hancom\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5 \uD6C4 \uC0AC\uC6A9\uD558\uC138\uC694. \uC218\uC815 \uC804\uC5D0 \uBC18\uB4DC\uC2DC read_document\uB85C \uC6D0\uBCF8\uC744 \uC77D\uACE0, expectedText\uB97C \uC9C0\uC815\uD558\uC5EC \uC548\uC804\uD558\uAC8C \uC218\uC815\uD558\uC138\uC694. \uBCC0\uACBD \uC0AC\uD56D\uC740 diff \uBBF8\uB9AC\uBCF4\uAE30\uC640 \uD568\uAED8 \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC744 \uBC1B\uC740 \uD6C4\uC5D0\uB9CC \uC800\uC7A5\uB429\uB2C8\uB2E4.",
|
|
11851
|
+
inputSchema: proposeCellEditSchema,
|
|
11936
11852
|
requiresApproval: true,
|
|
11937
11853
|
propose: async ({
|
|
11938
11854
|
input,
|
|
@@ -11940,145 +11856,196 @@ var proposeFormObjectTool = {
|
|
|
11940
11856
|
}) => {
|
|
11941
11857
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
11942
11858
|
const ext = extname3(safePath).toLowerCase();
|
|
11859
|
+
if (ext === ".hwp") {
|
|
11860
|
+
return "\uC624\uB958: propose_cell_edit\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uB610\uB294 propose_edit\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC788\uC73C\uB098, \uBCD1\uD569 \uC140\uC774 \uC18C\uC2E4\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
11861
|
+
}
|
|
11862
|
+
if (ext !== ".hwpx") {
|
|
11863
|
+
return `\uC624\uB958: propose_cell_edit\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}. \uD45C \uC140 \uC9C1\uC811 \uD3B8\uC9D1\uC740 .hwpx \uD3EC\uB9F7\uC5D0\uC11C\uB9CC \uAC00\uB2A5\uD569\uB2C8\uB2E4.`;
|
|
11864
|
+
}
|
|
11943
11865
|
let originalBuffer;
|
|
11944
11866
|
try {
|
|
11945
11867
|
originalBuffer = await readFile4(safePath);
|
|
11946
11868
|
} catch {
|
|
11947
|
-
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}
|
|
11869
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uAC70\uB098 read_document\uB85C \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`;
|
|
11948
11870
|
}
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
if (validationError) return validationError;
|
|
11952
|
-
let zip;
|
|
11953
|
-
try {
|
|
11954
|
-
zip = await import_jszip.default.loadAsync(bufArray);
|
|
11955
|
-
} catch {
|
|
11956
|
-
return "\uC624\uB958: .hwpx(ZIP) \uD30C\uC77C\uC744 \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
11871
|
+
if (originalBuffer[0] !== 80 || originalBuffer[1] !== 75) {
|
|
11872
|
+
return "\uC624\uB958: \uD30C\uC77C\uC774 \uC720\uD6A8\uD55C .hwpx(ZIP) \uD3EC\uB9F7\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uAD6C\uD615 .hwp(OLE \uBC14\uC774\uB108\uB9AC) \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
11957
11873
|
}
|
|
11958
|
-
const
|
|
11959
|
-
const
|
|
11960
|
-
const
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
const
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11974
|
-
const indices = candidates.map((c) => c.index).join(", ");
|
|
11975
|
-
resolveErrors.push(
|
|
11976
|
-
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}"\uC778 \uC591\uC2DD \uAC1C\uCCB4\uAC00 ${candidates.length}\uAC1C \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (\uBB38\uC11C \uC778\uB371\uC2A4: ${indices}). index \uD544\uB4DC\uB85C \uB300\uC0C1\uC744 \uC9C0\uC815\uD558\uC138\uC694.`
|
|
11977
|
-
);
|
|
11978
|
-
continue;
|
|
11979
|
-
}
|
|
11980
|
-
const byIndex = candidates.find((c) => c.index === edit.index);
|
|
11981
|
-
if (!byIndex) {
|
|
11982
|
-
resolveErrors.push(
|
|
11983
|
-
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}", index=${edit.index}\uC778 \uC591\uC2DD \uAC1C\uCCB4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
11984
|
-
);
|
|
11985
|
-
continue;
|
|
11874
|
+
const zipForLabel = await import_jszip2.default.loadAsync(new Uint8Array(originalBuffer.buffer));
|
|
11875
|
+
const sectionFilesForLabel = Object.keys(zipForLabel.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
11876
|
+
const sectionInfos = [];
|
|
11877
|
+
let globalTblOffset = 0;
|
|
11878
|
+
for (const sf of sectionFilesForLabel) {
|
|
11879
|
+
const entry = zipForLabel.file(sf);
|
|
11880
|
+
const xml = entry ? await entry.async("string") : "";
|
|
11881
|
+
const tokens = tokenizeHwpxXml(xml);
|
|
11882
|
+
let count = 0;
|
|
11883
|
+
let d = 0;
|
|
11884
|
+
for (const tok of tokens) {
|
|
11885
|
+
if (tok.kind === "tbl_open") {
|
|
11886
|
+
if (d === 0) count++;
|
|
11887
|
+
d++;
|
|
11888
|
+
} else if (tok.kind === "tbl_close") {
|
|
11889
|
+
d--;
|
|
11986
11890
|
}
|
|
11987
|
-
|
|
11891
|
+
}
|
|
11892
|
+
sectionInfos.push({ xml, tblCount: count, globalOffset: globalTblOffset });
|
|
11893
|
+
globalTblOffset += count;
|
|
11894
|
+
}
|
|
11895
|
+
function resolveLabelAcrossSections(label, direction, scopedTableIndex) {
|
|
11896
|
+
const trimmedLabel = label.trim();
|
|
11897
|
+
const allMatches = [];
|
|
11898
|
+
for (const si of sectionInfos) {
|
|
11899
|
+
const tokens = tokenizeHwpxXml(si.xml);
|
|
11900
|
+
let localStart = 0;
|
|
11901
|
+
let localEnd = si.tblCount - 1;
|
|
11902
|
+
if (scopedTableIndex !== void 0) {
|
|
11903
|
+
const localIdx2 = scopedTableIndex - si.globalOffset;
|
|
11904
|
+
if (localIdx2 < 0 || localIdx2 >= si.tblCount) continue;
|
|
11905
|
+
localStart = localIdx2;
|
|
11906
|
+
localEnd = localIdx2;
|
|
11907
|
+
}
|
|
11908
|
+
for (let li = localStart; li <= localEnd; li++) {
|
|
11909
|
+
const tblRange = findTopLevelTableRange(tokens, li);
|
|
11910
|
+
if (!tblRange) continue;
|
|
11911
|
+
const directTcs = collectDirectTcRanges(tokens, tblRange.start, tblRange.end);
|
|
11912
|
+
for (const tc of directTcs) {
|
|
11913
|
+
const cellText = readOwnTextFromTc(si.xml, tokens, tc.start, tc.end).trim();
|
|
11914
|
+
if (cellText === trimmedLabel) {
|
|
11915
|
+
const addrSpan2 = readCellAddrSpan(tokens, tc.start, tc.end);
|
|
11916
|
+
if (addrSpan2) {
|
|
11917
|
+
allMatches.push({
|
|
11918
|
+
globalTableIndex: si.globalOffset + li,
|
|
11919
|
+
addrSpan: addrSpan2,
|
|
11920
|
+
sectionXml: si.xml,
|
|
11921
|
+
sectionOffset: si.globalOffset
|
|
11922
|
+
});
|
|
11923
|
+
}
|
|
11924
|
+
}
|
|
11925
|
+
}
|
|
11926
|
+
}
|
|
11927
|
+
}
|
|
11928
|
+
if (allMatches.length === 0) {
|
|
11929
|
+
const scope = scopedTableIndex !== void 0 ? `\uD45C ${scopedTableIndex}` : "\uBB38\uC11C \uB0B4 \uBAA8\uB4E0 \uD45C";
|
|
11930
|
+
return {
|
|
11931
|
+
error: `\uB808\uC774\uBE14 "${label}"\uC744(\uB97C) ${scope}\uC5D0\uC11C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. read_document\uB85C \uD45C \uB0B4\uC6A9\uC744 \uD655\uC778\uD558\uC138\uC694.`
|
|
11932
|
+
};
|
|
11933
|
+
}
|
|
11934
|
+
if (allMatches.length > 1) {
|
|
11935
|
+
const locs = allMatches.map(
|
|
11936
|
+
(m) => `\uD45C ${m.globalTableIndex} (\uD589 ${m.addrSpan.rowAddr}, \uC5F4 ${m.addrSpan.colAddr})`
|
|
11937
|
+
).join(", ");
|
|
11938
|
+
return {
|
|
11939
|
+
error: `\uB808\uC774\uBE14 "${label}"\uC774(\uAC00) \uC5EC\uB7EC \uC140\uC5D0\uC11C \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${locs}. tableIndex\uB85C \uD0D0\uC0C9 \uBC94\uC704\uB97C \uC881\uD788\uAC70\uB098 \uC88C\uD45C(row/col)\uB97C \uC9C1\uC811 \uC9C0\uC815\uD558\uC138\uC694.`
|
|
11940
|
+
};
|
|
11941
|
+
}
|
|
11942
|
+
const match = allMatches[0];
|
|
11943
|
+
const { addrSpan, globalTableIndex, sectionXml, sectionOffset } = match;
|
|
11944
|
+
let targetRow;
|
|
11945
|
+
let targetCol;
|
|
11946
|
+
if (direction === "right") {
|
|
11947
|
+
targetRow = addrSpan.rowAddr;
|
|
11948
|
+
targetCol = addrSpan.colAddr + addrSpan.colSpan;
|
|
11988
11949
|
} else {
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11950
|
+
targetRow = addrSpan.rowAddr + addrSpan.rowSpan;
|
|
11951
|
+
targetCol = addrSpan.colAddr;
|
|
11952
|
+
}
|
|
11953
|
+
const localIdx = globalTableIndex - sectionOffset;
|
|
11954
|
+
const tokens2 = tokenizeHwpxXml(sectionXml);
|
|
11955
|
+
const tblRange2 = findTopLevelTableRange(tokens2, localIdx);
|
|
11956
|
+
if (!tblRange2) {
|
|
11957
|
+
return { error: `\uD45C ${globalTableIndex}\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uB0B4\uBD80 \uC624\uB958).` };
|
|
11958
|
+
}
|
|
11959
|
+
const directTcs2 = collectDirectTcRanges(tokens2, tblRange2.start, tblRange2.end);
|
|
11960
|
+
const tblTokens2 = tokens2.filter((t) => t.pos >= tblRange2.start && t.pos < tblRange2.end);
|
|
11961
|
+
let targetExists = false;
|
|
11962
|
+
for (const tc of directTcs2) {
|
|
11963
|
+
const tcTokens = tblTokens2.filter((t) => t.pos >= tc.start && t.pos < tc.end);
|
|
11964
|
+
if (tcTokens.some(
|
|
11965
|
+
(t) => t.kind === "cell_addr" && t.colAddr === targetCol && t.rowAddr === targetRow
|
|
11966
|
+
)) {
|
|
11967
|
+
targetExists = true;
|
|
11968
|
+
break;
|
|
11995
11969
|
}
|
|
11996
11970
|
}
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
|
|
12002
|
-
}
|
|
11971
|
+
if (!targetExists) {
|
|
11972
|
+
const dirLabel = direction === "right" ? "\uC624\uB978\uCABD" : "\uC544\uB798";
|
|
11973
|
+
return {
|
|
11974
|
+
error: `\uB808\uC774\uBE14 "${label}" (\uD45C ${globalTableIndex}, \uD589 ${addrSpan.rowAddr}, \uC5F4 ${addrSpan.colAddr})\uC758 ${dirLabel} \uC140 (\uD589 ${targetRow}, \uC5F4 ${targetCol})\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. direction \uB610\uB294 \uC88C\uD45C\uB97C \uD655\uC778\uD558\uC138\uC694.`
|
|
11975
|
+
};
|
|
11976
|
+
}
|
|
11977
|
+
return { tableIndex: globalTableIndex, row: targetRow, col: targetCol };
|
|
11978
|
+
}
|
|
11979
|
+
const resolvedEdits = [];
|
|
11980
|
+
const resolveErrors = [];
|
|
11981
|
+
for (let i = 0; i < input.edits.length; i++) {
|
|
11982
|
+
const e = input.edits[i];
|
|
11983
|
+
if (!e) continue;
|
|
11984
|
+
if (e.label !== void 0 && (e.row !== void 0 || e.col !== void 0)) {
|
|
11985
|
+
resolveErrors.push(
|
|
11986
|
+
`\uD3B8\uC9D1 #${i + 1}: label\uACFC row/col\uC744 \uB3D9\uC2DC\uC5D0 \uC9C0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label) \uC911 \uD558\uB098\uB9CC \uC0AC\uC6A9\uD558\uC138\uC694.`
|
|
11987
|
+
);
|
|
11988
|
+
} else if (e.label !== void 0) {
|
|
11989
|
+
const direction = e.direction ?? "right";
|
|
11990
|
+
const resolved = resolveLabelAcrossSections(e.label, direction, e.tableIndex);
|
|
11991
|
+
if ("error" in resolved) {
|
|
11992
|
+
resolveErrors.push(`\uD3B8\uC9D1 #${i + 1} (\uB808\uC774\uBE14 "${e.label}"): ${resolved.error}`);
|
|
11993
|
+
} else {
|
|
11994
|
+
resolvedEdits.push({
|
|
11995
|
+
tableIndex: resolved.tableIndex,
|
|
11996
|
+
row: resolved.row,
|
|
11997
|
+
col: resolved.col,
|
|
11998
|
+
newText: e.newText,
|
|
11999
|
+
expectedText: e.expectedText,
|
|
12000
|
+
label: e.label
|
|
12001
|
+
});
|
|
12002
|
+
}
|
|
12003
|
+
} else if (e.tableIndex !== void 0 && e.row !== void 0 && e.col !== void 0) {
|
|
12004
|
+
resolvedEdits.push({
|
|
12005
|
+
tableIndex: e.tableIndex,
|
|
12006
|
+
row: e.row,
|
|
12007
|
+
col: e.col,
|
|
12008
|
+
newText: e.newText,
|
|
12009
|
+
expectedText: e.expectedText
|
|
12010
|
+
});
|
|
12011
|
+
} else {
|
|
12012
|
+
resolveErrors.push(
|
|
12013
|
+
`\uD3B8\uC9D1 #${i + 1}: \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label) \uC911 \uD558\uB098\uB97C \uC644\uC804\uD788 \uC9C0\uC815\uD558\uC138\uC694. read_document\uB85C \uD45C \uB0B4\uC6A9\uC744 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`
|
|
12014
|
+
);
|
|
12015
|
+
}
|
|
12003
12016
|
}
|
|
12004
12017
|
if (resolveErrors.length > 0) {
|
|
12005
|
-
return `\uC624\uB958: \uB2E4\uC74C \
|
|
12018
|
+
return `\uC624\uB958: \uB2E4\uC74C \uB808\uC774\uBE14\uC744 \uD574\uC11D\uD560 \uC218 \uC5C6\uC5B4 \uD30C\uC77C\uC744 \uC218\uC815\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
12006
12019
|
${resolveErrors.join("\n")}`;
|
|
12007
12020
|
}
|
|
12008
|
-
const
|
|
12009
|
-
|
|
12010
|
-
|
|
12011
|
-
|
|
12012
|
-
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12021
|
+
const editRequests = resolvedEdits.map((e) => ({
|
|
12022
|
+
tableIndex: e.tableIndex,
|
|
12023
|
+
row: e.row,
|
|
12024
|
+
col: e.col,
|
|
12025
|
+
newText: e.newText,
|
|
12026
|
+
expectedText: e.expectedText
|
|
12027
|
+
}));
|
|
12028
|
+
const { buffer: newBuffer, results } = await applyEditsToHwpx(
|
|
12029
|
+
new Uint8Array(originalBuffer.buffer),
|
|
12030
|
+
editRequests
|
|
12031
|
+
);
|
|
12032
|
+
const failedResults = results.map((r, i) => ({ r, i })).filter(({ r }) => !r.success);
|
|
12033
|
+
if (failedResults.length > 0) {
|
|
12034
|
+
const messages = failedResults.map(({ r, i }) => {
|
|
12035
|
+
const e = resolvedEdits[i];
|
|
12036
|
+
const label = e?.label ? `\uB808\uC774\uBE14 "${e.label}" \u2192 ` : "";
|
|
12037
|
+
return `\uD3B8\uC9D1 #${i + 1} (${label}\uD45C ${e?.tableIndex ?? "?"}, \uD589 ${e?.row ?? "?"}, \uC5F4 ${e?.col ?? "?"}): ${r.error}`;
|
|
12017
12038
|
});
|
|
12018
|
-
}
|
|
12019
|
-
const sectionResults = [];
|
|
12020
|
-
const newSectionXmls = [...sectionXmls];
|
|
12021
|
-
for (const [si, edits] of sectionEditMap) {
|
|
12022
|
-
const xml = sectionXmls[si] ?? "";
|
|
12023
|
-
const { newXml, results } = applyFormObjectEdits(xml, edits);
|
|
12024
|
-
newSectionXmls[si] = newXml;
|
|
12025
|
-
sectionResults.push({ si, results, edits });
|
|
12026
|
-
}
|
|
12027
|
-
const failMessages = [];
|
|
12028
|
-
const successMap = /* @__PURE__ */ new Map();
|
|
12029
|
-
for (const sr of sectionResults) {
|
|
12030
|
-
for (let i = 0; i < sr.edits.length; i++) {
|
|
12031
|
-
const editReq = sr.edits[i];
|
|
12032
|
-
const result = sr.results[i];
|
|
12033
|
-
const resolved = resolvedEdits.find((r) => r.target === editReq.target);
|
|
12034
|
-
if (resolved) {
|
|
12035
|
-
successMap.set(resolved.editIdx, result);
|
|
12036
|
-
if (!result.success) {
|
|
12037
|
-
failMessages.push(
|
|
12038
|
-
`\uD3B8\uC9D1 #${resolved.editIdx + 1} (name="${editReq.target.name}"): ${result.error}`
|
|
12039
|
-
);
|
|
12040
|
-
}
|
|
12041
|
-
}
|
|
12042
|
-
}
|
|
12043
|
-
}
|
|
12044
|
-
if (failMessages.length > 0) {
|
|
12045
12039
|
return `\uC624\uB958: \uB2E4\uC74C \uD3B8\uC9D1\uC744 \uC801\uC6A9\uD560 \uC218 \uC5C6\uC5B4 \uD30C\uC77C\uC744 \uC218\uC815\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
12046
|
-
${
|
|
12047
|
-
}
|
|
12048
|
-
const out = new import_jszip.default();
|
|
12049
|
-
const mimetypeEntry = zip.file("mimetype");
|
|
12050
|
-
if (mimetypeEntry) {
|
|
12051
|
-
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
12052
|
-
}
|
|
12053
|
-
for (const [name, entry] of Object.entries(zip.files)) {
|
|
12054
|
-
if (name === "mimetype" || entry.dir) continue;
|
|
12055
|
-
const si = sectionFiles.indexOf(name);
|
|
12056
|
-
if (si >= 0) {
|
|
12057
|
-
out.file(name, newSectionXmls[si] ?? "");
|
|
12058
|
-
} else {
|
|
12059
|
-
out.file(name, await entry.async("uint8array"));
|
|
12060
|
-
}
|
|
12040
|
+
${messages.join("\n")}`;
|
|
12061
12041
|
}
|
|
12062
|
-
const
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
edit: "Edit"
|
|
12070
|
-
};
|
|
12071
|
-
const diffLines = ["| \uC591\uC2DD \uAC1C\uCCB4 | \uC774\uC804 | \uC774\uD6C4 |", "| --- | --- | --- |"];
|
|
12072
|
-
for (const re of resolvedEdits) {
|
|
12073
|
-
const result = successMap.get(re.editIdx);
|
|
12074
|
-
const oldVal = result?.oldValue ?? "";
|
|
12075
|
-
const oldStr = typeof oldVal === "boolean" ? oldVal ? "CHECKED" : "UNCHECKED" : String(oldVal);
|
|
12076
|
-
let newStr;
|
|
12077
|
-
if (re.set.caption !== void 0) newStr = re.set.caption;
|
|
12078
|
-
else if (re.set.checked !== void 0) newStr = re.set.checked ? "CHECKED" : "UNCHECKED";
|
|
12079
|
-
else if (re.set.selected !== void 0) newStr = re.set.selected;
|
|
12080
|
-
else newStr = re.set.text ?? "";
|
|
12081
|
-
diffLines.push(`| ${re.target.name}(${typeKo[re.target.type]}) | ${oldStr} | ${newStr} |`);
|
|
12042
|
+
const diffLines = ["| \uD45C\xB7\uC140 | \uC774\uC804 | \uC774\uD6C4 |", "| --- | --- | --- |"];
|
|
12043
|
+
for (let i = 0; i < resolvedEdits.length; i++) {
|
|
12044
|
+
const e = resolvedEdits[i];
|
|
12045
|
+
if (!e) continue;
|
|
12046
|
+
const oldText = results[i]?.oldText ?? "";
|
|
12047
|
+
const addr = e.label ? `\uB808\uC774\uBE14 "${e.label}" \u2192 #${e.tableIndex} (${e.row},${e.col})` : `#${e.tableIndex} (${e.row},${e.col})`;
|
|
12048
|
+
diffLines.push(`| ${addr} | ${oldText} | ${e.newText} |`);
|
|
12082
12049
|
}
|
|
12083
12050
|
const diff = diffLines.join("\n");
|
|
12084
12051
|
const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
|
|
@@ -12087,7 +12054,7 @@ ${failMessages.join("\n")}`;
|
|
|
12087
12054
|
return {
|
|
12088
12055
|
proposal: {
|
|
12089
12056
|
id: proposalId,
|
|
12090
|
-
kind: "
|
|
12057
|
+
kind: "cell-edit",
|
|
12091
12058
|
targetPath: outputPath,
|
|
12092
12059
|
stagedPath,
|
|
12093
12060
|
summary: input.summary,
|
|
@@ -12104,443 +12071,644 @@ ${failMessages.join("\n")}`;
|
|
|
12104
12071
|
};
|
|
12105
12072
|
}
|
|
12106
12073
|
};
|
|
12107
|
-
var
|
|
12108
|
-
".
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
".docx",
|
|
12112
|
-
".doc",
|
|
12113
|
-
".xlsx",
|
|
12114
|
-
".xls",
|
|
12115
|
-
".pdf",
|
|
12116
|
-
".pptx",
|
|
12117
|
-
".ppt",
|
|
12118
|
-
".md",
|
|
12119
|
-
".txt"
|
|
12120
|
-
]);
|
|
12121
|
-
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
12122
|
-
"node_modules",
|
|
12123
|
-
".git",
|
|
12124
|
-
".DS_Store",
|
|
12125
|
-
"__pycache__",
|
|
12126
|
-
"dist",
|
|
12127
|
-
"build",
|
|
12128
|
-
".next"
|
|
12129
|
-
]);
|
|
12130
|
-
var MAX_DEPTH = 4;
|
|
12131
|
-
var MAX_FILES = 500;
|
|
12132
|
-
var listFilesSchema = z4.object({
|
|
12133
|
-
dir: z4.string().optional().describe("\uBAA9\uB85D\uC744 \uC870\uD68C\uD560 \uB514\uB809\uD130\uB9AC (\uBBF8\uC9C0\uC815 \uC2DC cwd \uC804\uCCB4)")
|
|
12074
|
+
var findInDocumentSchema = z4.object({
|
|
12075
|
+
path: z4.string().describe("\uAC80\uC0C9\uD560 .hwpx \uBB38\uC11C \uACBD\uB85C"),
|
|
12076
|
+
query: z4.string().min(1).describe("\uCC3E\uC744 \uD14D\uC2A4\uD2B8"),
|
|
12077
|
+
caseSensitive: z4.boolean().optional().describe("\uB300\uC18C\uBB38\uC790 \uAD6C\uBD84 (\uAE30\uBCF8 false)")
|
|
12134
12078
|
});
|
|
12135
|
-
|
|
12136
|
-
|
|
12137
|
-
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12079
|
+
function unescapeXml(text3) {
|
|
12080
|
+
return text3.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
12081
|
+
}
|
|
12082
|
+
function windowText(text3, query, caseSensitive, maxLen = 60) {
|
|
12083
|
+
const compare3 = caseSensitive ? text3 : text3.toLowerCase();
|
|
12084
|
+
const compareQuery = caseSensitive ? query : query.toLowerCase();
|
|
12085
|
+
const idx = compare3.indexOf(compareQuery);
|
|
12086
|
+
if (idx < 0) return text3.slice(0, maxLen);
|
|
12087
|
+
const half = Math.floor((maxLen - query.length) / 2);
|
|
12088
|
+
const start = Math.max(0, idx - half);
|
|
12089
|
+
const end = Math.min(text3.length, idx + query.length + half);
|
|
12090
|
+
const prefix = start > 0 ? "\u2026" : "";
|
|
12091
|
+
const suffix = end < text3.length ? "\u2026" : "";
|
|
12092
|
+
return prefix + text3.slice(start, end) + suffix;
|
|
12093
|
+
}
|
|
12094
|
+
function findInSectionXmls(xmls, query, caseSensitive) {
|
|
12095
|
+
const hits = [];
|
|
12096
|
+
let globalOffset = 0;
|
|
12097
|
+
for (let si = 0; si < xmls.length; si++) {
|
|
12098
|
+
const xml = xmls[si] ?? "";
|
|
12099
|
+
const tokens = tokenizeHwpxXml(xml);
|
|
12100
|
+
let localCount = 0;
|
|
12101
|
+
{
|
|
12102
|
+
let depth = 0;
|
|
12103
|
+
for (const tok of tokens) {
|
|
12104
|
+
if (tok.kind === "tbl_open") {
|
|
12105
|
+
if (depth === 0) localCount++;
|
|
12106
|
+
depth++;
|
|
12107
|
+
} else if (tok.kind === "tbl_close") {
|
|
12108
|
+
depth--;
|
|
12109
|
+
}
|
|
12110
|
+
}
|
|
12111
|
+
}
|
|
12112
|
+
for (let ti = 0; ti < localCount; ti++) {
|
|
12113
|
+
const range = findTopLevelTableRange(tokens, ti);
|
|
12114
|
+
if (!range) continue;
|
|
12115
|
+
const cells = collectDirectTcRanges(tokens, range.start, range.end);
|
|
12116
|
+
const tblTokens = tokens.filter((t) => t.pos >= range.start && t.pos < range.end);
|
|
12117
|
+
for (const cell of cells) {
|
|
12118
|
+
const cellText = readOwnTextFromTc(xml, tokens, cell.start, cell.end);
|
|
12119
|
+
const compare3 = caseSensitive ? cellText : cellText.toLowerCase();
|
|
12120
|
+
const compareQuery = caseSensitive ? query : query.toLowerCase();
|
|
12121
|
+
if (!compare3.includes(compareQuery)) continue;
|
|
12122
|
+
const cellTokens = tblTokens.filter((t) => t.pos >= cell.start && t.pos < cell.end);
|
|
12123
|
+
const addrTok = cellTokens.find((t) => t.kind === "cell_addr");
|
|
12124
|
+
if (addrTok === void 0) continue;
|
|
12125
|
+
const row = addrTok.rowAddr ?? 0;
|
|
12126
|
+
const col = addrTok.colAddr ?? 0;
|
|
12127
|
+
const truncated = cellText.length > 60 ? `${cellText.slice(0, 57)}\u2026` : cellText;
|
|
12128
|
+
hits.push({
|
|
12129
|
+
kind: "\uD45C",
|
|
12130
|
+
tableIndex: globalOffset + ti,
|
|
12131
|
+
row,
|
|
12132
|
+
col,
|
|
12133
|
+
text: truncated
|
|
12134
|
+
});
|
|
12135
|
+
}
|
|
12153
12136
|
}
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12137
|
+
{
|
|
12138
|
+
const bodySegments = [];
|
|
12139
|
+
let tblDepth = 0;
|
|
12140
|
+
let segStart = 0;
|
|
12141
|
+
for (const tok of tokens) {
|
|
12142
|
+
if (tok.kind === "tbl_open") {
|
|
12143
|
+
if (tblDepth === 0) {
|
|
12144
|
+
if (tok.pos > segStart) {
|
|
12145
|
+
bodySegments.push({ start: segStart, end: tok.pos });
|
|
12146
|
+
}
|
|
12147
|
+
}
|
|
12148
|
+
tblDepth++;
|
|
12149
|
+
} else if (tok.kind === "tbl_close") {
|
|
12150
|
+
tblDepth--;
|
|
12151
|
+
if (tblDepth === 0) {
|
|
12152
|
+
segStart = tok.end;
|
|
12153
|
+
}
|
|
12154
|
+
}
|
|
12155
|
+
}
|
|
12156
|
+
if (segStart < xml.length) {
|
|
12157
|
+
bodySegments.push({ start: segStart, end: xml.length });
|
|
12158
|
+
}
|
|
12159
|
+
const tRe = /<hp:t>([\s\S]*?)<\/hp:t>/g;
|
|
12160
|
+
for (const seg of bodySegments) {
|
|
12161
|
+
const slice = xml.slice(seg.start, seg.end);
|
|
12162
|
+
tRe.lastIndex = 0;
|
|
12163
|
+
let m = tRe.exec(slice);
|
|
12164
|
+
while (m !== null) {
|
|
12165
|
+
const rawText = m[1] ?? "";
|
|
12166
|
+
const decodedText = unescapeXml(rawText);
|
|
12167
|
+
const compare3 = caseSensitive ? decodedText : decodedText.toLowerCase();
|
|
12168
|
+
const compareQuery = caseSensitive ? query : query.toLowerCase();
|
|
12169
|
+
if (compare3.includes(compareQuery)) {
|
|
12170
|
+
hits.push({
|
|
12171
|
+
kind: "\uBCF8\uBB38",
|
|
12172
|
+
section: si,
|
|
12173
|
+
text: windowText(decodedText, query, caseSensitive)
|
|
12174
|
+
});
|
|
12175
|
+
}
|
|
12176
|
+
m = tRe.exec(slice);
|
|
12177
|
+
}
|
|
12178
|
+
}
|
|
12162
12179
|
}
|
|
12180
|
+
globalOffset += localCount;
|
|
12163
12181
|
}
|
|
12182
|
+
return hits;
|
|
12164
12183
|
}
|
|
12165
|
-
var
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12184
|
+
var MAX_HITS = 50;
|
|
12185
|
+
function formatHits(hits, query) {
|
|
12186
|
+
const shown = hits.slice(0, MAX_HITS);
|
|
12187
|
+
const lines = shown.map((h) => {
|
|
12188
|
+
if (h.kind === "\uD45C") {
|
|
12189
|
+
return `[\uD45C] tableIndex=${h.tableIndex}, row=${h.row}, col=${h.col} \u2014 "${h.text}" (propose_cell_edit\uC73C\uB85C \uC218\uC815 \uAC00\uB2A5)`;
|
|
12190
|
+
}
|
|
12191
|
+
return `[\uBCF8\uBB38] \uC139\uC158 ${h.section} \u2014 "\u2026${h.text}\u2026" (propose_find_replace\uB85C \uC218\uC815 \uAC00\uB2A5)`;
|
|
12192
|
+
});
|
|
12193
|
+
const notice = hits.length > MAX_HITS ? `
|
|
12194
|
+
(\uCD1D ${hits.length}\uAC1C \uB9E4\uCE6D \uC911 ${MAX_HITS}\uAC1C\uB9CC \uD45C\uC2DC\uB429\uB2C8\uB2E4.)` : "";
|
|
12195
|
+
return `"${query}" \uAC80\uC0C9 \uACB0\uACFC: ${hits.length}\uAC1C
|
|
12196
|
+
|
|
12197
|
+
${lines.join("\n")}${notice}`;
|
|
12198
|
+
}
|
|
12199
|
+
var findInDocumentTool = {
|
|
12200
|
+
name: "find_in_document",
|
|
12201
|
+
description: "\uBB38\uC11C\uC5D0\uC11C \uD2B9\uC815 \uD14D\uC2A4\uD2B8\uAC00 **\uC5B4\uB514\uC5D0 \uC788\uB294\uC9C0** \uC704\uCE58\uB97C \uCC3E\uC544 \uC90D\uB2C8\uB2E4. \uD45C \uC548\uC758 \uC140\uC774\uBA74 propose_cell_edit\uC5D0\uC11C \uBC14\uB85C \uC4F8 \uC218 \uC788\uB294 tableIndex\xB7row\xB7col \uC88C\uD45C\uB97C, \uBCF8\uBB38\uC774\uBA74 \uC8FC\uBCC0 \uB9E5\uB77D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. \uD070 \uBB38\uC11C\uC5D0\uC11C \uC804\uCCB4\uB97C \uC77D\uC9C0 \uC54A\uACE0 \uC218\uC815 \uB300\uC0C1\uC744 \uC815\uD655\uD788 \uC9C0\uC815\uD560 \uB54C \uC0AC\uC6A9\uD558\uC138\uC694. .hwpx \uC804\uC6A9.",
|
|
12202
|
+
inputSchema: findInDocumentSchema,
|
|
12169
12203
|
requiresApproval: false,
|
|
12170
12204
|
execute: async ({
|
|
12171
12205
|
input,
|
|
12172
12206
|
ctx
|
|
12173
12207
|
}) => {
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
return
|
|
12208
|
+
let safePath;
|
|
12209
|
+
try {
|
|
12210
|
+
safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
12211
|
+
} catch (err) {
|
|
12212
|
+
return `\uC624\uB958: \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. ${String(err)}`;
|
|
12179
12213
|
}
|
|
12180
|
-
const
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
const allSorted = [...docs, ...dirs, ...others];
|
|
12184
|
-
const lines = allSorted.map((e) => {
|
|
12185
|
-
const icon = e.isDir ? "\u{1F4C1}" : e.isDoc ? "\u{1F4C4}" : " ";
|
|
12186
|
-
return `${icon} ${e.path}`;
|
|
12187
|
-
});
|
|
12188
|
-
const truncateNotice = entries.length >= MAX_FILES ? `
|
|
12189
|
-
(\uCD5C\uB300 ${MAX_FILES}\uAC1C\uAE4C\uC9C0 \uD45C\uC2DC\uB429\uB2C8\uB2E4. \uB354 \uC881\uC740 \uBC94\uC704\uB97C \uC9C0\uC815\uD558\uC138\uC694.)` : "";
|
|
12190
|
-
return lines.join("\n") + truncateNotice;
|
|
12191
|
-
}
|
|
12192
|
-
};
|
|
12193
|
-
var cellEditItemSchema = z5.object({
|
|
12194
|
-
tableIndex: z5.number().int().nonnegative().optional().describe(
|
|
12195
|
-
"\uC88C\uD45C \uBAA8\uB4DC: 0-based \uD45C \uC778\uB371\uC2A4(read_document\uC758 kordoc \uBE14\uB85D \uC21C\uC11C, \uC911\uCCA9\uD45C \uC81C\uC678). \uB808\uC774\uBE14 \uBAA8\uB4DC\uC5D0\uC120 \uD0D0\uC0C9 \uBC94\uC704 \uC81C\uD55C\uC6A9(\uC120\uD0DD)."
|
|
12196
|
-
),
|
|
12197
|
-
row: z5.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 rowAddr (0-based)"),
|
|
12198
|
-
col: z5.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 colAddr (0-based)"),
|
|
12199
|
-
label: z5.string().optional().describe(
|
|
12200
|
-
"\uB808\uC774\uBE14 \uBAA8\uB4DC: \uAE30\uC900 \uC140 \uD14D\uC2A4\uD2B8(\uD2B8\uB9BC \uBE44\uAD50). \uC774 \uC140\uC758 direction \uBC29\uD5A5 \uC778\uC811 \uC140\uC5D0 newText\uB97C \uAE30\uB85D. \uC88C\uD45C \uBAA8\uB4DC\uBA74 \uC0DD\uB7B5."
|
|
12201
|
-
),
|
|
12202
|
-
direction: z5.enum(["right", "below"]).optional().describe("\uB808\uC774\uBE14 \uBAA8\uB4DC \uBC29\uD5A5. \uAE30\uBCF8 right(\uC624\uB978\uCABD \uC140), below(\uC544\uB798 \uC140). \uBCD1\uD569 span \uACE0\uB824."),
|
|
12203
|
-
newText: z5.string().describe("\uC140\uC5D0 \uC4F8 \uC0C8 \uD14D\uC2A4\uD2B8"),
|
|
12204
|
-
expectedText: z5.string().optional().describe(
|
|
12205
|
-
"\uD604\uC7AC \uC140 \uD14D\uC2A4\uD2B8(\uC548\uC804 \uAC80\uC99D\uC6A9). \uBD88\uC77C\uCE58 \uC2DC \uC218\uC815\uD558\uC9C0 \uC54A\uC74C. \uC798\uBABB\uB41C \uC140 \uC218\uC815 \uBC29\uC9C0\uB97C \uC704\uD574 \uAD8C\uC7A5."
|
|
12206
|
-
)
|
|
12207
|
-
}).describe(
|
|
12208
|
-
"\uD3B8\uC9D1 \uD56D\uBAA9. \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label[+direction]) \uC911 \uD558\uB098\uB97C \uC0AC\uC6A9\uD558\uC138\uC694. \uB458 \uB2E4 \uC9C0\uC815\uD558\uAC70\uB098 \uB458 \uB2E4 \uC0DD\uB7B5\uD558\uBA74 \uC624\uB958\uC785\uB2C8\uB2E4."
|
|
12209
|
-
);
|
|
12210
|
-
var proposeCellEditSchema = z5.object({
|
|
12211
|
-
path: z5.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
12212
|
-
edits: z5.array(cellEditItemSchema).min(1).describe(
|
|
12213
|
-
"\uD3B8\uC9D1 \uBAA9\uB85D. \uAC01 \uD56D\uBAA9\uC740 \uC88C\uD45C \uBAA8\uB4DC(tableIndex+row+col) \uB610\uB294 \uB808\uC774\uBE14 \uBAA8\uB4DC(label+direction) \uC911 \uD558\uB098"
|
|
12214
|
-
),
|
|
12215
|
-
summary: z5.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
12216
|
-
});
|
|
12217
|
-
function tokenizeHwpxXml(xml) {
|
|
12218
|
-
const tokens = [];
|
|
12219
|
-
const re = /<hp:tbl[\s>]|<\/hp:tbl>|<hp:tc[\s>]|<\/hp:tc>|<hp:t\/>|<hp:t>|<hp:cellAddr[^/>]*|<hp:cellSpan[^/>]*/g;
|
|
12220
|
-
let startPos = 0;
|
|
12221
|
-
let m = re.exec(xml);
|
|
12222
|
-
while (m !== null) {
|
|
12223
|
-
const raw = m[0];
|
|
12224
|
-
const pos = m.index;
|
|
12225
|
-
if (raw.startsWith("<hp:tbl")) {
|
|
12226
|
-
tokens.push({ kind: "tbl_open", pos, end: pos + raw.length });
|
|
12227
|
-
} else if (raw === "</hp:tbl>") {
|
|
12228
|
-
tokens.push({ kind: "tbl_close", pos, end: pos + raw.length });
|
|
12229
|
-
} else if (raw.startsWith("<hp:tc")) {
|
|
12230
|
-
tokens.push({ kind: "tc_open", pos, end: pos + raw.length });
|
|
12231
|
-
} else if (raw === "</hp:tc>") {
|
|
12232
|
-
tokens.push({ kind: "tc_close", pos, end: pos + raw.length });
|
|
12233
|
-
} else if (raw === "<hp:t/>") {
|
|
12234
|
-
tokens.push({ kind: "t_empty", pos, end: pos + raw.length });
|
|
12235
|
-
} else if (raw === "<hp:t>") {
|
|
12236
|
-
tokens.push({ kind: "t_open", pos, end: pos + raw.length });
|
|
12237
|
-
} else if (raw.startsWith("<hp:cellAddr")) {
|
|
12238
|
-
const colM = raw.match(/colAddr="(\d+)"/);
|
|
12239
|
-
const rowM = raw.match(/rowAddr="(\d+)"/);
|
|
12240
|
-
if (colM && rowM) {
|
|
12241
|
-
const selfClose = xml.indexOf("/>", pos);
|
|
12242
|
-
const end = selfClose >= 0 ? selfClose + 2 : pos + raw.length;
|
|
12243
|
-
tokens.push({
|
|
12244
|
-
kind: "cell_addr",
|
|
12245
|
-
pos,
|
|
12246
|
-
end,
|
|
12247
|
-
colAddr: Number(colM[1]),
|
|
12248
|
-
rowAddr: Number(rowM[1])
|
|
12249
|
-
});
|
|
12250
|
-
}
|
|
12251
|
-
} else if (raw.startsWith("<hp:cellSpan")) {
|
|
12252
|
-
const colM = raw.match(/colSpan="(\d+)"/);
|
|
12253
|
-
const rowM = raw.match(/rowSpan="(\d+)"/);
|
|
12254
|
-
const selfClose = xml.indexOf("/>", pos);
|
|
12255
|
-
const end = selfClose >= 0 ? selfClose + 2 : pos + raw.length;
|
|
12256
|
-
tokens.push({
|
|
12257
|
-
kind: "cell_span",
|
|
12258
|
-
pos,
|
|
12259
|
-
end,
|
|
12260
|
-
colSpan: colM ? Number(colM[1]) : 1,
|
|
12261
|
-
rowSpan: rowM ? Number(rowM[1]) : 1
|
|
12262
|
-
});
|
|
12214
|
+
const ext = extname4(safePath).toLowerCase();
|
|
12215
|
+
if (ext !== ".hwpx") {
|
|
12216
|
+
return "find_in_document\uB294 .hwpx \uC804\uC6A9\uC785\uB2C8\uB2E4. \uBCF8\uBB38 \uD14D\uC2A4\uD2B8 \uAC80\uC0C9\uC740 read_document\uC758 search \uBAA8\uB4DC\uB97C \uC0AC\uC6A9\uD558\uC138\uC694. (.hwp \uD30C\uC77C\uC740 \uD55C\uAE00\uC5D0\uC11C \uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx\uB85C \uBCC0\uD658 \uD6C4 \uC0AC\uC6A9\uD558\uC138\uC694.)";
|
|
12263
12217
|
}
|
|
12264
|
-
|
|
12265
|
-
|
|
12266
|
-
|
|
12267
|
-
|
|
12268
|
-
|
|
12269
|
-
}
|
|
12270
|
-
function escapeXml2(text3) {
|
|
12271
|
-
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
12272
|
-
}
|
|
12273
|
-
function collectDirectTcRanges(tokens, tblStart, tblEnd) {
|
|
12274
|
-
const tblTokens = tokens.filter((t) => t.pos > tblStart && t.pos < tblEnd);
|
|
12275
|
-
const tcRanges = [];
|
|
12276
|
-
const tcStack = [];
|
|
12277
|
-
let innerDepth = 0;
|
|
12278
|
-
for (const tok of tblTokens) {
|
|
12279
|
-
if (tok.kind === "tbl_open") {
|
|
12280
|
-
innerDepth++;
|
|
12281
|
-
} else if (tok.kind === "tbl_close") {
|
|
12282
|
-
innerDepth--;
|
|
12283
|
-
} else if (tok.kind === "tc_open") {
|
|
12284
|
-
tcStack.push({ pos: tok.pos, depth: innerDepth });
|
|
12285
|
-
} else if (tok.kind === "tc_close") {
|
|
12286
|
-
const entry = tcStack.pop();
|
|
12287
|
-
if (entry !== void 0) {
|
|
12288
|
-
tcRanges.push({ start: entry.pos, end: tok.end, depth: entry.depth });
|
|
12289
|
-
}
|
|
12218
|
+
let bytes;
|
|
12219
|
+
try {
|
|
12220
|
+
bytes = await readFile5(safePath);
|
|
12221
|
+
} catch {
|
|
12222
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
|
|
12290
12223
|
}
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
}
|
|
12294
|
-
function readOwnTextFromTc(xml, tokens, tcStart, tcEnd) {
|
|
12295
|
-
const tcTokens = tokens.filter((t) => t.pos >= tcStart && t.pos < tcEnd);
|
|
12296
|
-
let innerDepth = 0;
|
|
12297
|
-
let text3 = "";
|
|
12298
|
-
for (const t of tcTokens) {
|
|
12299
|
-
if (t.kind === "tbl_open") innerDepth++;
|
|
12300
|
-
else if (t.kind === "tbl_close") innerDepth--;
|
|
12301
|
-
else if (t.kind === "t_empty" && innerDepth === 0) {
|
|
12302
|
-
} else if (t.kind === "t_open" && innerDepth === 0) {
|
|
12303
|
-
const closePos = xml.indexOf("</hp:t>", t.end);
|
|
12304
|
-
if (closePos >= 0) {
|
|
12305
|
-
text3 += xml.substring(t.end, closePos);
|
|
12306
|
-
}
|
|
12224
|
+
if (bytes[0] !== 80 || bytes[1] !== 75) {
|
|
12225
|
+
return "\uC624\uB958: \uD30C\uC77C\uC774 \uC720\uD6A8\uD55C .hwpx(ZIP) \uD3EC\uB9F7\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uAD6C\uD615 .hwp(OLE \uBC14\uC774\uB108\uB9AC) \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
12307
12226
|
}
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
depth++;
|
|
12324
|
-
} else if (tok.kind === "tbl_close") {
|
|
12325
|
-
depth--;
|
|
12326
|
-
if (depth === 0 && topLevelCount === tableIndex + 1 && targetStart >= 0) {
|
|
12327
|
-
return { start: targetStart, end: tok.end };
|
|
12227
|
+
let zip;
|
|
12228
|
+
try {
|
|
12229
|
+
zip = await import_jszip.default.loadAsync(bytes);
|
|
12230
|
+
} catch (err) {
|
|
12231
|
+
return `\uC624\uB958: .hwpx ZIP\uC744 \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${String(err)}`;
|
|
12232
|
+
}
|
|
12233
|
+
const sectionNames = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
12234
|
+
const xmls = [];
|
|
12235
|
+
for (const name of sectionNames) {
|
|
12236
|
+
try {
|
|
12237
|
+
const entry = zip.file(name);
|
|
12238
|
+
const xml = entry ? await entry.async("string") : "";
|
|
12239
|
+
xmls.push(xml);
|
|
12240
|
+
} catch {
|
|
12241
|
+
xmls.push("");
|
|
12328
12242
|
}
|
|
12329
12243
|
}
|
|
12244
|
+
if (xmls.length === 0) {
|
|
12245
|
+
return `\uC624\uB958: .hwpx \uD30C\uC77C\uC5D0\uC11C \uC139\uC158 XML\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
12246
|
+
}
|
|
12247
|
+
const caseSensitive = input.caseSensitive ?? false;
|
|
12248
|
+
let hits;
|
|
12249
|
+
try {
|
|
12250
|
+
hits = findInSectionXmls(xmls, input.query, caseSensitive);
|
|
12251
|
+
} catch (err) {
|
|
12252
|
+
return `\uC624\uB958: \uBB38\uC11C \uD0D0\uC0C9 \uC911 \uC608\uC678\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4: ${String(err)}`;
|
|
12253
|
+
}
|
|
12254
|
+
if (hits.length === 0) {
|
|
12255
|
+
return `\uBB38\uC11C\uC5D0\uC11C "${input.query}"\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
12256
|
+
}
|
|
12257
|
+
return formatHits(hits, input.query);
|
|
12330
12258
|
}
|
|
12331
|
-
|
|
12259
|
+
};
|
|
12260
|
+
function escapeXml2(text3) {
|
|
12261
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
12332
12262
|
}
|
|
12333
|
-
function
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12263
|
+
function decodeXml(text3) {
|
|
12264
|
+
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
12265
|
+
}
|
|
12266
|
+
function getAttr(openTag, attr) {
|
|
12267
|
+
const re = new RegExp(`\\b${attr}="([^"]*)"`, "");
|
|
12268
|
+
const m = re.exec(openTag);
|
|
12269
|
+
return m ? decodeXml(m[1] ?? "") : "";
|
|
12270
|
+
}
|
|
12271
|
+
function parseFormObjects(xml, sectionFile, startIndex = 0) {
|
|
12272
|
+
const results = [];
|
|
12273
|
+
let idx = startIndex;
|
|
12274
|
+
const tagSpecs = [
|
|
12275
|
+
{ xmlTag: "hp:btn", type: "button" },
|
|
12276
|
+
{ xmlTag: "hp:checkBtn", type: "checkBox" },
|
|
12277
|
+
{ xmlTag: "hp:radioBtn", type: "radioButton" },
|
|
12278
|
+
{ xmlTag: "hp:comboBox", type: "comboBox" },
|
|
12279
|
+
{ xmlTag: "hp:edit", type: "edit" }
|
|
12280
|
+
];
|
|
12281
|
+
const hits = [];
|
|
12282
|
+
for (const spec of tagSpecs) {
|
|
12283
|
+
const re = new RegExp(`<${spec.xmlTag}\\b`, "g");
|
|
12284
|
+
for (let m = re.exec(xml); m !== null; m = re.exec(xml)) {
|
|
12285
|
+
hits.push({ pos: m.index, xmlTag: spec.xmlTag, type: spec.type });
|
|
12342
12286
|
}
|
|
12343
12287
|
}
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
}
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
|
|
12288
|
+
hits.sort((a, b) => a.pos - b.pos);
|
|
12289
|
+
for (const hit of hits) {
|
|
12290
|
+
const { pos, xmlTag, type } = hit;
|
|
12291
|
+
const openTagEnd = xml.indexOf(">", pos);
|
|
12292
|
+
if (openTagEnd < 0) continue;
|
|
12293
|
+
const openTag = xml.slice(pos, openTagEnd + 1);
|
|
12294
|
+
const closeTag = `</${xmlTag}>`;
|
|
12295
|
+
const closeIdx = xml.indexOf(closeTag, openTagEnd);
|
|
12296
|
+
if (closeIdx < 0) continue;
|
|
12297
|
+
const elementEnd = closeIdx + closeTag.length;
|
|
12298
|
+
const elementXml = xml.slice(pos, elementEnd);
|
|
12299
|
+
const name = getAttr(openTag, "name");
|
|
12300
|
+
let currentValue;
|
|
12301
|
+
let comboItems;
|
|
12302
|
+
switch (type) {
|
|
12303
|
+
case "button":
|
|
12304
|
+
currentValue = getAttr(openTag, "caption");
|
|
12305
|
+
break;
|
|
12306
|
+
case "checkBox":
|
|
12307
|
+
case "radioButton":
|
|
12308
|
+
currentValue = getAttr(openTag, "value") === "CHECKED";
|
|
12309
|
+
break;
|
|
12310
|
+
case "comboBox": {
|
|
12311
|
+
currentValue = getAttr(openTag, "selectedValue");
|
|
12312
|
+
const listItemRe = /<hp:listItem\b[^>]*/g;
|
|
12313
|
+
const items = [];
|
|
12314
|
+
for (let lm = listItemRe.exec(elementXml); lm !== null; lm = listItemRe.exec(elementXml)) {
|
|
12315
|
+
const itemValue = getAttr(lm[0] ?? "", "value");
|
|
12316
|
+
items.push(itemValue);
|
|
12317
|
+
}
|
|
12318
|
+
comboItems = items;
|
|
12319
|
+
break;
|
|
12320
|
+
}
|
|
12321
|
+
case "edit": {
|
|
12322
|
+
const textSelfClose = /<hp:text\s*\/>/;
|
|
12323
|
+
const textOpen = /<hp:text>/;
|
|
12324
|
+
const textClose = "</hp:text>";
|
|
12325
|
+
if (textSelfClose.test(elementXml)) {
|
|
12326
|
+
currentValue = "";
|
|
12327
|
+
} else {
|
|
12328
|
+
const tOpenIdx = elementXml.search(textOpen);
|
|
12329
|
+
if (tOpenIdx >= 0) {
|
|
12330
|
+
const afterOpen = elementXml.indexOf(">", tOpenIdx) + 1;
|
|
12331
|
+
const closePos = elementXml.indexOf(textClose, afterOpen);
|
|
12332
|
+
currentValue = closePos >= 0 ? decodeXml(elementXml.slice(afterOpen, closePos)) : "";
|
|
12333
|
+
} else {
|
|
12334
|
+
currentValue = "";
|
|
12335
|
+
}
|
|
12336
|
+
}
|
|
12337
|
+
break;
|
|
12359
12338
|
}
|
|
12360
12339
|
}
|
|
12340
|
+
results.push({
|
|
12341
|
+
index: idx++,
|
|
12342
|
+
name,
|
|
12343
|
+
type,
|
|
12344
|
+
currentValue,
|
|
12345
|
+
comboItems,
|
|
12346
|
+
sectionFile,
|
|
12347
|
+
posInSection: pos
|
|
12348
|
+
});
|
|
12361
12349
|
}
|
|
12362
|
-
|
|
12350
|
+
return results;
|
|
12351
|
+
}
|
|
12352
|
+
function applyFormObjectEdits(xml, edits) {
|
|
12353
|
+
const results = edits.map(() => ({ success: false }));
|
|
12354
|
+
const patches = [];
|
|
12363
12355
|
for (let ei = 0; ei < edits.length; ei++) {
|
|
12364
12356
|
const edit = edits[ei];
|
|
12365
|
-
const
|
|
12366
|
-
|
|
12357
|
+
const { target, set, expected } = edit;
|
|
12358
|
+
const pos = target.posInSection;
|
|
12359
|
+
const xmlTag = typeToXmlTag(target.type);
|
|
12360
|
+
const openTagEnd = xml.indexOf(">", pos);
|
|
12361
|
+
if (openTagEnd < 0) {
|
|
12367
12362
|
results[ei] = {
|
|
12368
12363
|
success: false,
|
|
12369
|
-
error: `\
|
|
12364
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}" \uC5EC\uB294 \uD0DC\uADF8 \uB05D\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12370
12365
|
};
|
|
12371
12366
|
continue;
|
|
12372
12367
|
}
|
|
12373
|
-
const
|
|
12374
|
-
const
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12368
|
+
const _openTag = xml.slice(pos, openTagEnd + 1);
|
|
12369
|
+
const closeTag = `</${xmlTag}>`;
|
|
12370
|
+
const closeIdx = xml.indexOf(closeTag, openTagEnd);
|
|
12371
|
+
if (closeIdx < 0) {
|
|
12372
|
+
results[ei] = {
|
|
12373
|
+
success: false,
|
|
12374
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}" \uB2EB\uB294 \uD0DC\uADF8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12375
|
+
};
|
|
12376
|
+
continue;
|
|
12377
|
+
}
|
|
12378
|
+
const elementEnd = closeIdx + closeTag.length;
|
|
12379
|
+
const typeError = validateSetForType(target.type, set);
|
|
12380
|
+
if (typeError) {
|
|
12381
|
+
results[ei] = { success: false, error: typeError };
|
|
12382
|
+
continue;
|
|
12383
|
+
}
|
|
12384
|
+
const currentRaw = readCurrentValue(
|
|
12385
|
+
xml,
|
|
12386
|
+
pos,
|
|
12387
|
+
openTagEnd,
|
|
12388
|
+
openTagEnd + 1,
|
|
12389
|
+
elementEnd,
|
|
12390
|
+
target.type
|
|
12391
|
+
);
|
|
12392
|
+
if (expected !== void 0) {
|
|
12393
|
+
const mismatch = checkExpected(expected, currentRaw, target);
|
|
12394
|
+
if (mismatch) {
|
|
12395
|
+
results[ei] = { success: false, error: mismatch };
|
|
12396
|
+
continue;
|
|
12395
12397
|
}
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
+
}
|
|
12399
|
+
if (target.type === "comboBox" && set.selected !== void 0) {
|
|
12400
|
+
const items = target.comboItems ?? [];
|
|
12401
|
+
if (!items.includes(set.selected)) {
|
|
12402
|
+
const validList = items.map((v) => `"${v}"`).join(", ");
|
|
12398
12403
|
results[ei] = {
|
|
12399
12404
|
success: false,
|
|
12400
|
-
|
|
12401
|
-
error: `\uC140 (\uD45C ${edit.tableIndex}, \uD589 ${edit.row}, \uC5F4 ${edit.col})\uC758 \uD604\uC7AC \uD14D\uC2A4\uD2B8\uAC00 \uC608\uC0C1\uAC12\uACFC \uB2E4\uB985\uB2C8\uB2E4. \uC608\uC0C1: "${edit.expectedText}", \uC2E4\uC81C: "${currentText}". \uC218\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`
|
|
12405
|
+
error: `comboBox "${target.name}"\uC758 selected \uAC12 "${set.selected}"\uC774 \uC720\uD6A8\uD55C \uD56D\uBAA9\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uC720\uD6A8\uD55C \uD56D\uBAA9: ${validList || "(\uC5C6\uC74C)"}`
|
|
12402
12406
|
};
|
|
12403
|
-
|
|
12404
|
-
break;
|
|
12407
|
+
continue;
|
|
12405
12408
|
}
|
|
12406
|
-
|
|
12409
|
+
}
|
|
12410
|
+
let patchCreated = false;
|
|
12411
|
+
if (set.caption !== void 0) {
|
|
12412
|
+
const patch = replaceAttrInOpenTag(xml, pos, openTagEnd, "caption", escapeXml2(set.caption));
|
|
12413
|
+
if (!patch) {
|
|
12407
12414
|
results[ei] = {
|
|
12408
12415
|
success: false,
|
|
12409
|
-
|
|
12410
|
-
error: `\uC140 (\uD45C ${edit.tableIndex}, \uD589 ${edit.row}, \uC5F4 ${edit.col})\uC5D0 \uD14D\uC2A4\uD2B8 \uB7F0\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. <hp:t> \uB610\uB294 <hp:t/> \uB7F0\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uC140 \uAD6C\uC870\uB97C \uD655\uC778\uD558\uC138\uC694.`
|
|
12416
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 caption \uC18D\uC131\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12411
12417
|
};
|
|
12412
|
-
|
|
12413
|
-
break;
|
|
12418
|
+
continue;
|
|
12414
12419
|
}
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12420
|
+
patches.push(patch);
|
|
12421
|
+
patchCreated = true;
|
|
12422
|
+
} else if (set.checked !== void 0) {
|
|
12423
|
+
const newValue = set.checked ? "CHECKED" : "UNCHECKED";
|
|
12424
|
+
const patch = replaceAttrInOpenTag(xml, pos, openTagEnd, "value", newValue);
|
|
12425
|
+
if (!patch) {
|
|
12426
|
+
results[ei] = {
|
|
12427
|
+
success: false,
|
|
12428
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 value \uC18D\uC131\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12429
|
+
};
|
|
12430
|
+
continue;
|
|
12426
12431
|
}
|
|
12427
|
-
|
|
12428
|
-
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12432
|
+
patches.push(patch);
|
|
12433
|
+
patchCreated = true;
|
|
12434
|
+
} else if (set.selected !== void 0) {
|
|
12435
|
+
const patch = replaceAttrInOpenTag(
|
|
12436
|
+
xml,
|
|
12437
|
+
pos,
|
|
12438
|
+
openTagEnd,
|
|
12439
|
+
"selectedValue",
|
|
12440
|
+
escapeXml2(set.selected)
|
|
12441
|
+
);
|
|
12442
|
+
if (!patch) {
|
|
12443
|
+
results[ei] = {
|
|
12444
|
+
success: false,
|
|
12445
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 selectedValue \uC18D\uC131\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12446
|
+
};
|
|
12447
|
+
continue;
|
|
12432
12448
|
}
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12449
|
+
patches.push(patch);
|
|
12450
|
+
patchCreated = true;
|
|
12451
|
+
} else if (set.text !== void 0) {
|
|
12452
|
+
const elementContent = xml.slice(pos, elementEnd);
|
|
12453
|
+
const textPatch = replaceEditText(xml, pos, elementContent, set.text);
|
|
12454
|
+
if (!textPatch) {
|
|
12455
|
+
results[ei] = {
|
|
12456
|
+
success: false,
|
|
12457
|
+
error: `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}"\uC758 <hp:text> \uC694\uC18C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12458
|
+
};
|
|
12459
|
+
continue;
|
|
12460
|
+
}
|
|
12461
|
+
patches.push(textPatch);
|
|
12462
|
+
patchCreated = true;
|
|
12437
12463
|
}
|
|
12438
|
-
if (!
|
|
12439
|
-
results[ei] = {
|
|
12440
|
-
|
|
12441
|
-
error: `\uD45C ${edit.tableIndex}\uC5D0\uC11C \uC140 (\uD589 ${edit.row}, \uC5F4 ${edit.col})\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. cellAddr colAddr="${edit.col}" rowAddr="${edit.row}"\uC5D0 \uD574\uB2F9\uD558\uB294 \uC140\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12442
|
-
};
|
|
12464
|
+
if (!patchCreated) {
|
|
12465
|
+
results[ei] = { success: false, error: `\uD3B8\uC9D1 #${ei + 1}: set \uD544\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.` };
|
|
12466
|
+
continue;
|
|
12443
12467
|
}
|
|
12468
|
+
results[ei] = { success: true, oldValue: currentRaw };
|
|
12444
12469
|
}
|
|
12445
12470
|
if (results.some((r) => !r.success)) {
|
|
12446
12471
|
return { newXml: xml, results };
|
|
12447
12472
|
}
|
|
12448
|
-
const
|
|
12473
|
+
const sortedPatches = [...patches].sort((a, b) => b.from - a.from);
|
|
12449
12474
|
let result = xml;
|
|
12450
|
-
for (const patch of
|
|
12451
|
-
result = result.
|
|
12475
|
+
for (const patch of sortedPatches) {
|
|
12476
|
+
result = result.slice(0, patch.from) + patch.text + result.slice(patch.to);
|
|
12452
12477
|
}
|
|
12453
12478
|
return { newXml: result, results };
|
|
12454
12479
|
}
|
|
12455
|
-
|
|
12456
|
-
|
|
12480
|
+
function typeToXmlTag(type) {
|
|
12481
|
+
switch (type) {
|
|
12482
|
+
case "button":
|
|
12483
|
+
return "hp:btn";
|
|
12484
|
+
case "checkBox":
|
|
12485
|
+
return "hp:checkBtn";
|
|
12486
|
+
case "radioButton":
|
|
12487
|
+
return "hp:radioBtn";
|
|
12488
|
+
case "comboBox":
|
|
12489
|
+
return "hp:comboBox";
|
|
12490
|
+
case "edit":
|
|
12491
|
+
return "hp:edit";
|
|
12492
|
+
}
|
|
12493
|
+
}
|
|
12494
|
+
function validateSetForType(type, set) {
|
|
12495
|
+
const key = Object.keys(set).find((k) => set[k] !== void 0);
|
|
12496
|
+
if (!key) return "set \uD544\uB4DC\uAC00 \uBE44\uC5B4\uC788\uC2B5\uB2C8\uB2E4. caption/checked/selected/text \uC911 \uD558\uB098\uB97C \uC9C0\uC815\uD558\uC138\uC694.";
|
|
12497
|
+
const allowed = {
|
|
12498
|
+
button: "caption",
|
|
12499
|
+
checkBox: "checked",
|
|
12500
|
+
radioButton: "checked",
|
|
12501
|
+
comboBox: "selected",
|
|
12502
|
+
edit: "text"
|
|
12503
|
+
};
|
|
12504
|
+
if (key !== allowed[type]) {
|
|
12505
|
+
const typeKo = {
|
|
12506
|
+
button: "PushButton",
|
|
12507
|
+
checkBox: "CheckBox",
|
|
12508
|
+
radioButton: "RadioButton",
|
|
12509
|
+
comboBox: "ComboBox",
|
|
12510
|
+
edit: "Edit"
|
|
12511
|
+
};
|
|
12512
|
+
return `\uD0C0\uC785 \uBD88\uC77C\uCE58: ${typeKo[type]} \uC591\uC2DD \uAC1C\uCCB4\uC5D0\uB294 "${allowed[type]}" \uD544\uB4DC\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5\uD558\uC9C0\uB9CC "${key}"\uC774(\uAC00) \uC9C0\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`;
|
|
12513
|
+
}
|
|
12514
|
+
return null;
|
|
12515
|
+
}
|
|
12516
|
+
function readCurrentValue(xml, pos, openTagEnd, _afterOpen, elementEnd, type) {
|
|
12517
|
+
const openTag = xml.slice(pos, openTagEnd + 1);
|
|
12518
|
+
switch (type) {
|
|
12519
|
+
case "button":
|
|
12520
|
+
return decodeXml(getAttr(openTag, "caption"));
|
|
12521
|
+
case "checkBox":
|
|
12522
|
+
case "radioButton":
|
|
12523
|
+
return getAttr(openTag, "value") === "CHECKED";
|
|
12524
|
+
case "comboBox":
|
|
12525
|
+
return decodeXml(getAttr(openTag, "selectedValue"));
|
|
12526
|
+
case "edit": {
|
|
12527
|
+
const elementContent = xml.slice(pos, elementEnd);
|
|
12528
|
+
if (/<hp:text\s*\/>/.test(elementContent)) return "";
|
|
12529
|
+
const tOpenIdx = elementContent.search(/<hp:text>/);
|
|
12530
|
+
if (tOpenIdx >= 0) {
|
|
12531
|
+
const afterOpen = elementContent.indexOf(">", tOpenIdx) + 1;
|
|
12532
|
+
const closePos = elementContent.indexOf("</hp:text>", afterOpen);
|
|
12533
|
+
return closePos >= 0 ? decodeXml(elementContent.slice(afterOpen, closePos)) : "";
|
|
12534
|
+
}
|
|
12535
|
+
return "";
|
|
12536
|
+
}
|
|
12537
|
+
}
|
|
12538
|
+
}
|
|
12539
|
+
function checkExpected(expected, currentRaw, target) {
|
|
12540
|
+
let expectedVal;
|
|
12541
|
+
if (expected.caption !== void 0) expectedVal = expected.caption;
|
|
12542
|
+
else if (expected.checked !== void 0) expectedVal = expected.checked;
|
|
12543
|
+
else if (expected.selected !== void 0) expectedVal = expected.selected;
|
|
12544
|
+
else if (expected.text !== void 0) expectedVal = expected.text;
|
|
12545
|
+
if (expectedVal === void 0) return null;
|
|
12546
|
+
const matches = typeof expectedVal === "boolean" ? currentRaw === expectedVal : String(currentRaw) === String(expectedVal);
|
|
12547
|
+
if (!matches) {
|
|
12548
|
+
return `\uC591\uC2DD \uAC1C\uCCB4 "${target.name}" \uD604\uC7AC \uAC12\uC774 \uC608\uC0C1\uAC12\uACFC \uB2E4\uB985\uB2C8\uB2E4. \uC608\uC0C1: ${JSON.stringify(expectedVal)}, \uC2E4\uC81C: ${JSON.stringify(currentRaw)}. \uC218\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`;
|
|
12549
|
+
}
|
|
12550
|
+
return null;
|
|
12551
|
+
}
|
|
12552
|
+
function replaceAttrInOpenTag(xml, tagStart, tagEnd, attr, newValue) {
|
|
12553
|
+
const tagStr = xml.slice(tagStart, tagEnd + 1);
|
|
12554
|
+
const re = new RegExp(`\\b(${attr}=")([^"]*)(")`, "");
|
|
12555
|
+
const m = re.exec(tagStr);
|
|
12556
|
+
if (!m) return null;
|
|
12557
|
+
const relFrom = m.index + (m[1]?.length ?? 0);
|
|
12558
|
+
const relTo = relFrom + (m[2]?.length ?? 0);
|
|
12559
|
+
return {
|
|
12560
|
+
from: tagStart + relFrom,
|
|
12561
|
+
to: tagStart + relTo,
|
|
12562
|
+
text: newValue
|
|
12563
|
+
};
|
|
12564
|
+
}
|
|
12565
|
+
function replaceEditText(_xml, pos, elementContent, newText) {
|
|
12566
|
+
const escaped = escapeXml2(newText);
|
|
12567
|
+
const selfCloseRe = /<hp:text\s*\/>/;
|
|
12568
|
+
const scm = selfCloseRe.exec(elementContent);
|
|
12569
|
+
if (scm) {
|
|
12570
|
+
return {
|
|
12571
|
+
from: pos + scm.index,
|
|
12572
|
+
to: pos + scm.index + scm[0].length,
|
|
12573
|
+
text: `<hp:text>${escaped}</hp:text>`
|
|
12574
|
+
};
|
|
12575
|
+
}
|
|
12576
|
+
const openRe = /<hp:text>/;
|
|
12577
|
+
const om = openRe.exec(elementContent);
|
|
12578
|
+
if (om) {
|
|
12579
|
+
const afterOpen = om.index + om[0].length;
|
|
12580
|
+
const closePos = elementContent.indexOf("</hp:text>", afterOpen);
|
|
12581
|
+
if (closePos < 0) return null;
|
|
12582
|
+
return {
|
|
12583
|
+
from: pos + afterOpen,
|
|
12584
|
+
to: pos + closePos,
|
|
12585
|
+
text: escaped
|
|
12586
|
+
};
|
|
12587
|
+
}
|
|
12588
|
+
return null;
|
|
12589
|
+
}
|
|
12590
|
+
async function listFormObjectsFromZip(zip) {
|
|
12457
12591
|
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
12458
12592
|
const sectionXmls = [];
|
|
12459
|
-
const
|
|
12593
|
+
const objects = [];
|
|
12594
|
+
let globalIndex = 0;
|
|
12460
12595
|
for (const sf of sectionFiles) {
|
|
12461
12596
|
const entry = zip.file(sf);
|
|
12462
12597
|
const xml = entry ? await entry.async("string") : "";
|
|
12463
12598
|
sectionXmls.push(xml);
|
|
12464
|
-
const
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
for (const tok of tokens) {
|
|
12468
|
-
if (tok.kind === "tbl_open") {
|
|
12469
|
-
if (depth === 0) count++;
|
|
12470
|
-
depth++;
|
|
12471
|
-
} else if (tok.kind === "tbl_close") {
|
|
12472
|
-
depth--;
|
|
12473
|
-
}
|
|
12474
|
-
}
|
|
12475
|
-
sectionTblCounts.push(count);
|
|
12476
|
-
}
|
|
12477
|
-
const sectionEdits = sectionFiles.map(() => []);
|
|
12478
|
-
let offset = 0;
|
|
12479
|
-
for (let si = 0; si < sectionFiles.length; si++) {
|
|
12480
|
-
const count = sectionTblCounts[si] ?? 0;
|
|
12481
|
-
for (let ei = 0; ei < edits.length; ei++) {
|
|
12482
|
-
const edit = edits[ei];
|
|
12483
|
-
if (edit.tableIndex >= offset && edit.tableIndex < offset + count) {
|
|
12484
|
-
const secEdits = sectionEdits[si];
|
|
12485
|
-
if (secEdits) {
|
|
12486
|
-
secEdits.push({
|
|
12487
|
-
tableIndex: edit.tableIndex - offset,
|
|
12488
|
-
// 섹션 내 상대 인덱스
|
|
12489
|
-
row: edit.row,
|
|
12490
|
-
col: edit.col,
|
|
12491
|
-
newText: edit.newText,
|
|
12492
|
-
expectedText: edit.expectedText,
|
|
12493
|
-
originalEditIdx: ei
|
|
12494
|
-
});
|
|
12495
|
-
}
|
|
12496
|
-
}
|
|
12497
|
-
}
|
|
12498
|
-
offset += count;
|
|
12599
|
+
const parsed = parseFormObjects(xml, sf, globalIndex);
|
|
12600
|
+
objects.push(...parsed);
|
|
12601
|
+
globalIndex += parsed.length;
|
|
12499
12602
|
}
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
const newSectionXmls = [...sectionXmls];
|
|
12506
|
-
for (let si = 0; si < sectionFiles.length; si++) {
|
|
12507
|
-
const sEdits = sectionEdits[si] ?? [];
|
|
12508
|
-
if (sEdits.length === 0) continue;
|
|
12509
|
-
const srcXml = sectionXmls[si] ?? "";
|
|
12510
|
-
const { newXml, results } = applyCellEditsToSectionXml(srcXml, sEdits);
|
|
12511
|
-
newSectionXmls[si] = newXml;
|
|
12512
|
-
for (let i = 0; i < sEdits.length; i++) {
|
|
12513
|
-
const sEdit = sEdits[i];
|
|
12514
|
-
const res = results[i];
|
|
12515
|
-
if (sEdit && res) {
|
|
12516
|
-
allResults[sEdit.originalEditIdx] = res;
|
|
12517
|
-
}
|
|
12518
|
-
}
|
|
12603
|
+
return { objects, sectionFiles, sectionXmls };
|
|
12604
|
+
}
|
|
12605
|
+
function validateHwpxBuffer(ext, buffer) {
|
|
12606
|
+
if (ext === ".hwp") {
|
|
12607
|
+
return "\uC624\uB958: \uC774 \uD234\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
12519
12608
|
}
|
|
12520
|
-
if (
|
|
12521
|
-
return
|
|
12609
|
+
if (ext !== ".hwpx") {
|
|
12610
|
+
return `\uC624\uB958: \uC774 \uD234\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C \uD655\uC7A5\uC790: ${ext}`;
|
|
12522
12611
|
}
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
if (mimetypeEntry) {
|
|
12526
|
-
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
12612
|
+
if (buffer[0] !== 80 || buffer[1] !== 75) {
|
|
12613
|
+
return "\uC624\uB958: \uD30C\uC77C\uC774 \uC720\uD6A8\uD55C .hwpx(ZIP) \uD3EC\uB9F7\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uAD6C\uD615 .hwp(OLE \uBC14\uC774\uB108\uB9AC) \uD3EC\uB9F7\uC785\uB2C8\uB2E4.";
|
|
12527
12614
|
}
|
|
12528
|
-
|
|
12529
|
-
|
|
12530
|
-
|
|
12531
|
-
|
|
12532
|
-
|
|
12533
|
-
|
|
12534
|
-
|
|
12615
|
+
return null;
|
|
12616
|
+
}
|
|
12617
|
+
var listFormObjectsSchema = z5.object({
|
|
12618
|
+
path: z5.string().describe("\uC77D\uC744 .hwpx \uD30C\uC77C \uACBD\uB85C")
|
|
12619
|
+
});
|
|
12620
|
+
var formEditSetSchema = z5.object({
|
|
12621
|
+
caption: z5.string().optional().describe("PushButton \uCEA1\uC158 \uD14D\uC2A4\uD2B8"),
|
|
12622
|
+
checked: z5.boolean().optional().describe("CheckBox/RadioButton \uCCB4\uD06C \uC0C1\uD0DC (true=CHECKED)"),
|
|
12623
|
+
selected: z5.string().optional().describe("ComboBox \uC120\uD0DD \uAC12 (listItem \uC911 \uD558\uB098\uC5EC\uC57C \uD568)"),
|
|
12624
|
+
text: z5.string().optional().describe("Edit \uD14D\uC2A4\uD2B8 \uB0B4\uC6A9")
|
|
12625
|
+
}).refine(
|
|
12626
|
+
(v) => {
|
|
12627
|
+
const keys = ["caption", "checked", "selected", "text"].filter(
|
|
12628
|
+
(k) => v[k] !== void 0
|
|
12629
|
+
);
|
|
12630
|
+
return keys.length === 1;
|
|
12631
|
+
},
|
|
12632
|
+
{ message: "set \uD544\uB4DC\uB294 caption/checked/selected/text \uC911 \uC815\uD655\uD788 \uD558\uB098\uB9CC \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4." }
|
|
12633
|
+
);
|
|
12634
|
+
var formEditExpectedSchema = z5.object({
|
|
12635
|
+
caption: z5.string().optional(),
|
|
12636
|
+
checked: z5.boolean().optional(),
|
|
12637
|
+
selected: z5.string().optional(),
|
|
12638
|
+
text: z5.string().optional()
|
|
12639
|
+
}).optional();
|
|
12640
|
+
var formEditItemSchema = z5.object({
|
|
12641
|
+
name: z5.string().describe("\uC591\uC2DD \uAC1C\uCCB4\uC758 name \uC18D\uC131 \uAC12"),
|
|
12642
|
+
index: z5.number().int().nonnegative().optional().describe("\uB3D9\uC77C name\uC774 \uC5EC\uB7FF\uC778 \uACBD\uC6B0 \uBB38\uC11C \uC804\uCCB4 0-based \uC778\uB371\uC2A4\uB85C \uAD6C\uBD84"),
|
|
12643
|
+
set: formEditSetSchema.describe("\uBCC0\uACBD\uD560 \uAC12 (caption/checked/selected/text \uC911 \uD558\uB098)"),
|
|
12644
|
+
expected: formEditExpectedSchema.describe(
|
|
12645
|
+
"\uD604\uC7AC \uAC12 \uC0AC\uC804 \uAC80\uC99D (\uC548\uC804 \uC635\uC158). \uC2E4\uC81C \uAC12\uC774 \uB2E4\uB974\uBA74 \uC774 \uD3B8\uC9D1\uC744 \uCDE8\uC18C\uD558\uACE0 \uC624\uB958 \uBC18\uD658."
|
|
12646
|
+
)
|
|
12647
|
+
});
|
|
12648
|
+
var proposeFormObjectSchema = z5.object({
|
|
12649
|
+
path: z5.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C"),
|
|
12650
|
+
edits: z5.array(formEditItemSchema).min(1).describe("\uC591\uC2DD \uAC1C\uCCB4 \uD3B8\uC9D1 \uBAA9\uB85D"),
|
|
12651
|
+
summary: z5.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
12652
|
+
});
|
|
12653
|
+
var listFormObjectsTool = {
|
|
12654
|
+
name: "list_form_objects",
|
|
12655
|
+
description: "HWPX \uBB38\uC11C\uC758 \uC591\uC2DD \uAC1C\uCCB4(form object) \uBAA9\uB85D\uC744 \uC5F4\uAC70\uD569\uB2C8\uB2E4. PushButton, CheckBox, RadioButton, ComboBox, Edit \uB2E4\uC12F \uAC00\uC9C0 \uD0C0\uC785\uC744 \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uAC01 \uC591\uC2DD \uAC1C\uCCB4\uC758 \uC774\uB984(name), \uD0C0\uC785, \uD604\uC7AC \uAC12, ComboBox\uC758 \uACBD\uC6B0 \uC120\uD0DD \uAC00\uB2A5\uD55C \uD56D\uBAA9 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. propose_form_object\uB85C \uAC12\uC744 \uC218\uC815\uD558\uAE30 \uC804\uC5D0 \uC774 \uD234\uB85C \uBA3C\uC800 \uD604\uC7AC \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. .hwpx \uD30C\uC77C \uC804\uC6A9\uC785\uB2C8\uB2E4.",
|
|
12656
|
+
inputSchema: listFormObjectsSchema,
|
|
12657
|
+
requiresApproval: false,
|
|
12658
|
+
execute: async ({
|
|
12659
|
+
input,
|
|
12660
|
+
ctx
|
|
12661
|
+
}) => {
|
|
12662
|
+
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
12663
|
+
const ext = extname5(safePath).toLowerCase();
|
|
12664
|
+
let buffer;
|
|
12665
|
+
try {
|
|
12666
|
+
buffer = await readFile6(safePath);
|
|
12667
|
+
} catch {
|
|
12668
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
12669
|
+
}
|
|
12670
|
+
const validationError = validateHwpxBuffer(ext, new Uint8Array(buffer.buffer));
|
|
12671
|
+
if (validationError) return validationError;
|
|
12672
|
+
let zip;
|
|
12673
|
+
try {
|
|
12674
|
+
zip = await import_jszip3.default.loadAsync(new Uint8Array(buffer.buffer));
|
|
12675
|
+
} catch {
|
|
12676
|
+
return "\uC624\uB958: .hwpx(ZIP) \uD30C\uC77C\uC744 \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
12677
|
+
}
|
|
12678
|
+
const { objects } = await listFormObjectsFromZip(zip);
|
|
12679
|
+
if (objects.length === 0) {
|
|
12680
|
+
return "\uC774 \uBB38\uC11C\uC5D0\uB294 \uC591\uC2DD \uAC1C\uCCB4(form object)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
12535
12681
|
}
|
|
12682
|
+
const lines = [`\uCD1D ${objects.length}\uAC1C\uC758 \uC591\uC2DD \uAC1C\uCCB4\uAC00 \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
12683
|
+
`];
|
|
12684
|
+
const typeKo = {
|
|
12685
|
+
button: "PushButton",
|
|
12686
|
+
checkBox: "CheckBox",
|
|
12687
|
+
radioButton: "RadioButton",
|
|
12688
|
+
comboBox: "ComboBox",
|
|
12689
|
+
edit: "Edit"
|
|
12690
|
+
};
|
|
12691
|
+
for (const obj of objects) {
|
|
12692
|
+
let valueStr;
|
|
12693
|
+
if (typeof obj.currentValue === "boolean") {
|
|
12694
|
+
valueStr = obj.currentValue ? "\uCCB4\uD06C\uB428 (CHECKED)" : "\uCCB4\uD06C \uD574\uC81C\uB428 (UNCHECKED)";
|
|
12695
|
+
} else {
|
|
12696
|
+
valueStr = `"${obj.currentValue}"`;
|
|
12697
|
+
}
|
|
12698
|
+
let line = `[${obj.index}] name="${obj.name}" | \uD0C0\uC785: ${typeKo[obj.type]} | \uD604\uC7AC \uAC12: ${valueStr}`;
|
|
12699
|
+
if (obj.type === "comboBox" && obj.comboItems) {
|
|
12700
|
+
const itemList = obj.comboItems.map((v) => `"${v}"`).join(", ");
|
|
12701
|
+
line += ` | \uD56D\uBAA9: [${itemList}]`;
|
|
12702
|
+
}
|
|
12703
|
+
lines.push(line);
|
|
12704
|
+
}
|
|
12705
|
+
return lines.join("\n");
|
|
12536
12706
|
}
|
|
12537
|
-
|
|
12538
|
-
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
|
|
12542
|
-
description: "HWPX \uBB38\uC11C\uC758 \uD45C \uC140 \uB0B4\uC6A9\uC744 XML \uC9C1\uC811 \uD328\uCE58 \uBC29\uC2DD\uC73C\uB85C \uC218\uC815\uD569\uB2C8\uB2E4. \uBCD1\uD569 \uC140(cellSpan/rowSpan)\uC774 \uC788\uB294 \uD45C\uC5D0\uC11C\uB3C4 \uBCD1\uD569 \uAD6C\uC870\uB97C \uC644\uC804\uD788 \uBCF4\uC874\uD569\uB2C8\uB2E4. \uBE48 \uC140(<hp:t/> self-closing \uB7F0)\uB3C4 \uCC44\uC6B8 \uC218 \uC788\uC5B4 \uC591\uC2DD(form) \uD3B8\uC9D1\uC5D0 \uC801\uD569\uD569\uB2C8\uB2E4. \uC140 \uC8FC\uC18C \uC9C0\uC815 \uBC29\uBC95: (1) \uC88C\uD45C \uBAA8\uB4DC \u2014 tableIndex + row + col \uC9C1\uC811 \uC9C0\uC815. (2) \uB808\uC774\uBE14 \uBAA8\uB4DC \u2014 label(\uC778\uC811 \uB808\uC774\uBE14 \uC140 \uD14D\uC2A4\uD2B8) + direction(right/below, \uAE30\uBCF8 right) + \uC120\uD0DD\uC801 tableIndex\uB85C \uB808\uC774\uBE14 \uC606/\uC544\uB798 \uC140\uC744 \uC790\uB3D9\uC73C\uB85C \uCC3E\uC544 \uD3B8\uC9D1. \uBCD1\uD569 \uB808\uC774\uBE14 \uC140\uB3C4 colSpan/rowSpan\uC744 \uBC18\uC601\uD558\uC5EC \uB300\uC0C1 \uC140\uC744 \uACC4\uC0B0\uD569\uB2C8\uB2E4. propose_edit/propose_form_fill\uC740 \uB9C8\uD06C\uB2E4\uC6B4 \uB77C\uC6B4\uB4DC\uD2B8\uB9BD\uC73C\uB85C \uBCD1\uD569 \uC140\uC744 \uC18C\uC2E4\uC2DC\uD0A4\uBBC0\uB85C, \uBCD1\uD569 \uC140\uC774 \uC788\uB294 \uD45C\uB97C \uC218\uC815\uD560 \uB54C\uB294 \uC774 \uD234\uC744 \uC0AC\uC6A9\uD558\uC138\uC694. .hwpx \uD30C\uC77C \uC804\uC6A9\uC785\uB2C8\uB2E4. .hwp\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC73C\uBA70 Hancom\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5 \uD6C4 \uC0AC\uC6A9\uD558\uC138\uC694. \uC218\uC815 \uC804\uC5D0 \uBC18\uB4DC\uC2DC read_document\uB85C \uC6D0\uBCF8\uC744 \uC77D\uACE0, expectedText\uB97C \uC9C0\uC815\uD558\uC5EC \uC548\uC804\uD558\uAC8C \uC218\uC815\uD558\uC138\uC694. \uBCC0\uACBD \uC0AC\uD56D\uC740 diff \uBBF8\uB9AC\uBCF4\uAE30\uC640 \uD568\uAED8 \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC744 \uBC1B\uC740 \uD6C4\uC5D0\uB9CC \uC800\uC7A5\uB429\uB2C8\uB2E4.",
|
|
12543
|
-
inputSchema: proposeCellEditSchema,
|
|
12707
|
+
};
|
|
12708
|
+
var proposeFormObjectTool = {
|
|
12709
|
+
name: "propose_form_object",
|
|
12710
|
+
description: "HWPX \uBB38\uC11C\uC758 \uC591\uC2DD \uAC1C\uCCB4(form object) \uAC12\uC744 XML \uC9C1\uC811 \uD328\uCE58 \uBC29\uC2DD\uC73C\uB85C \uC218\uC815\uD569\uB2C8\uB2E4. PushButton(caption), CheckBox/RadioButton(checked), ComboBox(selected), Edit(text)\uB97C \uC218\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. kordoc IR\uC5D0 \uC591\uC2DD \uAC1C\uCCB4 \uD0C0\uC785\uC774 \uC5C6\uC73C\uBBC0\uB85C section XML\uC744 \uC9C1\uC811 \uD328\uCE58\uD569\uB2C8\uB2E4. \uC218\uC815 \uC804\uC5D0 list_form_objects\uB85C \uD604\uC7AC \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694. name\uC774 \uC911\uBCF5\uB41C \uACBD\uC6B0 index\uB85C \uB300\uC0C1\uC744 \uC9C0\uC815\uD558\uC138\uC694. \uBCC0\uACBD \uC0AC\uD56D\uC740 \uC0AC\uC6A9\uC790 \uC2B9\uC778 \uD6C4\uC5D0\uB9CC \uC800\uC7A5\uB429\uB2C8\uB2E4. .hwpx \uD30C\uC77C \uC804\uC6A9\uC785\uB2C8\uB2E4.",
|
|
12711
|
+
inputSchema: proposeFormObjectSchema,
|
|
12544
12712
|
requiresApproval: true,
|
|
12545
12713
|
propose: async ({
|
|
12546
12714
|
input,
|
|
@@ -12548,196 +12716,145 @@ var proposeCellEditTool = {
|
|
|
12548
12716
|
}) => {
|
|
12549
12717
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
12550
12718
|
const ext = extname5(safePath).toLowerCase();
|
|
12551
|
-
if (ext === ".hwp") {
|
|
12552
|
-
return "\uC624\uB958: propose_cell_edit\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694. \uB610\uB294 propose_edit\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC788\uC73C\uB098, \uBCD1\uD569 \uC140\uC774 \uC18C\uC2E4\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
12553
|
-
}
|
|
12554
|
-
if (ext !== ".hwpx") {
|
|
12555
|
-
return `\uC624\uB958: propose_cell_edit\uC740 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}. \uD45C \uC140 \uC9C1\uC811 \uD3B8\uC9D1\uC740 .hwpx \uD3EC\uB9F7\uC5D0\uC11C\uB9CC \uAC00\uB2A5\uD569\uB2C8\uB2E4.`;
|
|
12556
|
-
}
|
|
12557
12719
|
let originalBuffer;
|
|
12558
12720
|
try {
|
|
12559
|
-
originalBuffer = await
|
|
12721
|
+
originalBuffer = await readFile6(safePath);
|
|
12560
12722
|
} catch {
|
|
12561
|
-
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}
|
|
12562
|
-
}
|
|
12563
|
-
if (originalBuffer[0] !== 80 || originalBuffer[1] !== 75) {
|
|
12564
|
-
return "\uC624\uB958: \uD30C\uC77C\uC774 \uC720\uD6A8\uD55C .hwpx(ZIP) \uD3EC\uB9F7\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uAD6C\uD615 .hwp(OLE \uBC14\uC774\uB108\uB9AC) \uD3EC\uB9F7\uC785\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
12565
|
-
}
|
|
12566
|
-
const zipForLabel = await import_jszip2.default.loadAsync(new Uint8Array(originalBuffer.buffer));
|
|
12567
|
-
const sectionFilesForLabel = Object.keys(zipForLabel.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
12568
|
-
const sectionInfos = [];
|
|
12569
|
-
let globalTblOffset = 0;
|
|
12570
|
-
for (const sf of sectionFilesForLabel) {
|
|
12571
|
-
const entry = zipForLabel.file(sf);
|
|
12572
|
-
const xml = entry ? await entry.async("string") : "";
|
|
12573
|
-
const tokens = tokenizeHwpxXml(xml);
|
|
12574
|
-
let count = 0;
|
|
12575
|
-
let d = 0;
|
|
12576
|
-
for (const tok of tokens) {
|
|
12577
|
-
if (tok.kind === "tbl_open") {
|
|
12578
|
-
if (d === 0) count++;
|
|
12579
|
-
d++;
|
|
12580
|
-
} else if (tok.kind === "tbl_close") {
|
|
12581
|
-
d--;
|
|
12582
|
-
}
|
|
12583
|
-
}
|
|
12584
|
-
sectionInfos.push({ xml, tblCount: count, globalOffset: globalTblOffset });
|
|
12585
|
-
globalTblOffset += count;
|
|
12723
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
12586
12724
|
}
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
const localIdx2 = scopedTableIndex - si.globalOffset;
|
|
12596
|
-
if (localIdx2 < 0 || localIdx2 >= si.tblCount) continue;
|
|
12597
|
-
localStart = localIdx2;
|
|
12598
|
-
localEnd = localIdx2;
|
|
12599
|
-
}
|
|
12600
|
-
for (let li = localStart; li <= localEnd; li++) {
|
|
12601
|
-
const tblRange = findTopLevelTableRange(tokens, li);
|
|
12602
|
-
if (!tblRange) continue;
|
|
12603
|
-
const directTcs = collectDirectTcRanges(tokens, tblRange.start, tblRange.end);
|
|
12604
|
-
for (const tc of directTcs) {
|
|
12605
|
-
const cellText = readOwnTextFromTc(si.xml, tokens, tc.start, tc.end).trim();
|
|
12606
|
-
if (cellText === trimmedLabel) {
|
|
12607
|
-
const addrSpan2 = readCellAddrSpan(tokens, tc.start, tc.end);
|
|
12608
|
-
if (addrSpan2) {
|
|
12609
|
-
allMatches.push({
|
|
12610
|
-
globalTableIndex: si.globalOffset + li,
|
|
12611
|
-
addrSpan: addrSpan2,
|
|
12612
|
-
sectionXml: si.xml,
|
|
12613
|
-
sectionOffset: si.globalOffset
|
|
12614
|
-
});
|
|
12615
|
-
}
|
|
12616
|
-
}
|
|
12617
|
-
}
|
|
12618
|
-
}
|
|
12619
|
-
}
|
|
12620
|
-
if (allMatches.length === 0) {
|
|
12621
|
-
const scope = scopedTableIndex !== void 0 ? `\uD45C ${scopedTableIndex}` : "\uBB38\uC11C \uB0B4 \uBAA8\uB4E0 \uD45C";
|
|
12622
|
-
return {
|
|
12623
|
-
error: `\uB808\uC774\uBE14 "${label}"\uC744(\uB97C) ${scope}\uC5D0\uC11C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. read_document\uB85C \uD45C \uB0B4\uC6A9\uC744 \uD655\uC778\uD558\uC138\uC694.`
|
|
12624
|
-
};
|
|
12625
|
-
}
|
|
12626
|
-
if (allMatches.length > 1) {
|
|
12627
|
-
const locs = allMatches.map(
|
|
12628
|
-
(m) => `\uD45C ${m.globalTableIndex} (\uD589 ${m.addrSpan.rowAddr}, \uC5F4 ${m.addrSpan.colAddr})`
|
|
12629
|
-
).join(", ");
|
|
12630
|
-
return {
|
|
12631
|
-
error: `\uB808\uC774\uBE14 "${label}"\uC774(\uAC00) \uC5EC\uB7EC \uC140\uC5D0\uC11C \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${locs}. tableIndex\uB85C \uD0D0\uC0C9 \uBC94\uC704\uB97C \uC881\uD788\uAC70\uB098 \uC88C\uD45C(row/col)\uB97C \uC9C1\uC811 \uC9C0\uC815\uD558\uC138\uC694.`
|
|
12632
|
-
};
|
|
12633
|
-
}
|
|
12634
|
-
const match = allMatches[0];
|
|
12635
|
-
const { addrSpan, globalTableIndex, sectionXml, sectionOffset } = match;
|
|
12636
|
-
let targetRow;
|
|
12637
|
-
let targetCol;
|
|
12638
|
-
if (direction === "right") {
|
|
12639
|
-
targetRow = addrSpan.rowAddr;
|
|
12640
|
-
targetCol = addrSpan.colAddr + addrSpan.colSpan;
|
|
12641
|
-
} else {
|
|
12642
|
-
targetRow = addrSpan.rowAddr + addrSpan.rowSpan;
|
|
12643
|
-
targetCol = addrSpan.colAddr;
|
|
12644
|
-
}
|
|
12645
|
-
const localIdx = globalTableIndex - sectionOffset;
|
|
12646
|
-
const tokens2 = tokenizeHwpxXml(sectionXml);
|
|
12647
|
-
const tblRange2 = findTopLevelTableRange(tokens2, localIdx);
|
|
12648
|
-
if (!tblRange2) {
|
|
12649
|
-
return { error: `\uD45C ${globalTableIndex}\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uB0B4\uBD80 \uC624\uB958).` };
|
|
12650
|
-
}
|
|
12651
|
-
const directTcs2 = collectDirectTcRanges(tokens2, tblRange2.start, tblRange2.end);
|
|
12652
|
-
const tblTokens2 = tokens2.filter((t) => t.pos >= tblRange2.start && t.pos < tblRange2.end);
|
|
12653
|
-
let targetExists = false;
|
|
12654
|
-
for (const tc of directTcs2) {
|
|
12655
|
-
const tcTokens = tblTokens2.filter((t) => t.pos >= tc.start && t.pos < tc.end);
|
|
12656
|
-
if (tcTokens.some(
|
|
12657
|
-
(t) => t.kind === "cell_addr" && t.colAddr === targetCol && t.rowAddr === targetRow
|
|
12658
|
-
)) {
|
|
12659
|
-
targetExists = true;
|
|
12660
|
-
break;
|
|
12661
|
-
}
|
|
12662
|
-
}
|
|
12663
|
-
if (!targetExists) {
|
|
12664
|
-
const dirLabel = direction === "right" ? "\uC624\uB978\uCABD" : "\uC544\uB798";
|
|
12665
|
-
return {
|
|
12666
|
-
error: `\uB808\uC774\uBE14 "${label}" (\uD45C ${globalTableIndex}, \uD589 ${addrSpan.rowAddr}, \uC5F4 ${addrSpan.colAddr})\uC758 ${dirLabel} \uC140 (\uD589 ${targetRow}, \uC5F4 ${targetCol})\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. direction \uB610\uB294 \uC88C\uD45C\uB97C \uD655\uC778\uD558\uC138\uC694.`
|
|
12667
|
-
};
|
|
12668
|
-
}
|
|
12669
|
-
return { tableIndex: globalTableIndex, row: targetRow, col: targetCol };
|
|
12725
|
+
const bufArray = new Uint8Array(originalBuffer.buffer);
|
|
12726
|
+
const validationError = validateHwpxBuffer(ext, bufArray);
|
|
12727
|
+
if (validationError) return validationError;
|
|
12728
|
+
let zip;
|
|
12729
|
+
try {
|
|
12730
|
+
zip = await import_jszip3.default.loadAsync(bufArray);
|
|
12731
|
+
} catch {
|
|
12732
|
+
return "\uC624\uB958: .hwpx(ZIP) \uD30C\uC77C\uC744 \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
12670
12733
|
}
|
|
12734
|
+
const { objects, sectionFiles, sectionXmls } = await listFormObjectsFromZip(zip);
|
|
12671
12735
|
const resolvedEdits = [];
|
|
12672
12736
|
const resolveErrors = [];
|
|
12673
|
-
for (let
|
|
12674
|
-
const
|
|
12675
|
-
if (!
|
|
12676
|
-
|
|
12737
|
+
for (let ei = 0; ei < input.edits.length; ei++) {
|
|
12738
|
+
const edit = input.edits[ei];
|
|
12739
|
+
if (!edit) continue;
|
|
12740
|
+
const candidates = objects.filter((o) => o.name === edit.name);
|
|
12741
|
+
if (candidates.length === 0) {
|
|
12677
12742
|
resolveErrors.push(
|
|
12678
|
-
`\uD3B8\uC9D1 #${
|
|
12743
|
+
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}"\uC778 \uC591\uC2DD \uAC1C\uCCB4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. list_form_objects\uB85C \uBB38\uC11C\uC758 \uC591\uC2DD \uAC1C\uCCB4 \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uC138\uC694.`
|
|
12679
12744
|
);
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
|
|
12687
|
-
|
|
12688
|
-
|
|
12689
|
-
|
|
12690
|
-
newText: e.newText,
|
|
12691
|
-
expectedText: e.expectedText,
|
|
12692
|
-
label: e.label
|
|
12693
|
-
});
|
|
12745
|
+
continue;
|
|
12746
|
+
}
|
|
12747
|
+
let target;
|
|
12748
|
+
if (candidates.length > 1) {
|
|
12749
|
+
if (edit.index === void 0) {
|
|
12750
|
+
const indices = candidates.map((c) => c.index).join(", ");
|
|
12751
|
+
resolveErrors.push(
|
|
12752
|
+
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}"\uC778 \uC591\uC2DD \uAC1C\uCCB4\uAC00 ${candidates.length}\uAC1C \uBC1C\uACAC\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (\uBB38\uC11C \uC778\uB371\uC2A4: ${indices}). index \uD544\uB4DC\uB85C \uB300\uC0C1\uC744 \uC9C0\uC815\uD558\uC138\uC694.`
|
|
12753
|
+
);
|
|
12754
|
+
continue;
|
|
12694
12755
|
}
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12756
|
+
const byIndex = candidates.find((c) => c.index === edit.index);
|
|
12757
|
+
if (!byIndex) {
|
|
12758
|
+
resolveErrors.push(
|
|
12759
|
+
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}", index=${edit.index}\uC778 \uC591\uC2DD \uAC1C\uCCB4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`
|
|
12760
|
+
);
|
|
12761
|
+
continue;
|
|
12762
|
+
}
|
|
12763
|
+
target = byIndex;
|
|
12703
12764
|
} else {
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12765
|
+
target = candidates[0];
|
|
12766
|
+
if (edit.index !== void 0 && edit.index !== target.index) {
|
|
12767
|
+
resolveErrors.push(
|
|
12768
|
+
`\uD3B8\uC9D1 #${ei + 1}: name="${edit.name}"\uC758 \uBB38\uC11C \uC778\uB371\uC2A4\uB294 ${target.index}\uC774\uC9C0\uB9CC index=${edit.index}\uAC00 \uC9C0\uC815\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`
|
|
12769
|
+
);
|
|
12770
|
+
continue;
|
|
12771
|
+
}
|
|
12707
12772
|
}
|
|
12773
|
+
resolvedEdits.push({
|
|
12774
|
+
target,
|
|
12775
|
+
set: edit.set,
|
|
12776
|
+
expected: edit.expected,
|
|
12777
|
+
editIdx: ei
|
|
12778
|
+
});
|
|
12708
12779
|
}
|
|
12709
12780
|
if (resolveErrors.length > 0) {
|
|
12710
|
-
return `\uC624\uB958: \uB2E4\uC74C \
|
|
12781
|
+
return `\uC624\uB958: \uB2E4\uC74C \uD3B8\uC9D1 \uB300\uC0C1\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4 \uD30C\uC77C\uC744 \uC218\uC815\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
12711
12782
|
${resolveErrors.join("\n")}`;
|
|
12712
12783
|
}
|
|
12713
|
-
const
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
editRequests
|
|
12723
|
-
);
|
|
12724
|
-
const failedResults = results.map((r, i) => ({ r, i })).filter(({ r }) => !r.success);
|
|
12725
|
-
if (failedResults.length > 0) {
|
|
12726
|
-
const messages = failedResults.map(({ r, i }) => {
|
|
12727
|
-
const e = resolvedEdits[i];
|
|
12728
|
-
const label = e?.label ? `\uB808\uC774\uBE14 "${e.label}" \u2192 ` : "";
|
|
12729
|
-
return `\uD3B8\uC9D1 #${i + 1} (${label}\uD45C ${e?.tableIndex ?? "?"}, \uD589 ${e?.row ?? "?"}, \uC5F4 ${e?.col ?? "?"}): ${r.error}`;
|
|
12784
|
+
const sectionEditMap = /* @__PURE__ */ new Map();
|
|
12785
|
+
for (const re of resolvedEdits) {
|
|
12786
|
+
const si = sectionFiles.indexOf(re.target.sectionFile);
|
|
12787
|
+
if (si < 0) continue;
|
|
12788
|
+
if (!sectionEditMap.has(si)) sectionEditMap.set(si, []);
|
|
12789
|
+
sectionEditMap.get(si).push({
|
|
12790
|
+
target: re.target,
|
|
12791
|
+
set: re.set,
|
|
12792
|
+
expected: re.expected
|
|
12730
12793
|
});
|
|
12794
|
+
}
|
|
12795
|
+
const sectionResults = [];
|
|
12796
|
+
const newSectionXmls = [...sectionXmls];
|
|
12797
|
+
for (const [si, edits] of sectionEditMap) {
|
|
12798
|
+
const xml = sectionXmls[si] ?? "";
|
|
12799
|
+
const { newXml, results } = applyFormObjectEdits(xml, edits);
|
|
12800
|
+
newSectionXmls[si] = newXml;
|
|
12801
|
+
sectionResults.push({ si, results, edits });
|
|
12802
|
+
}
|
|
12803
|
+
const failMessages = [];
|
|
12804
|
+
const successMap = /* @__PURE__ */ new Map();
|
|
12805
|
+
for (const sr of sectionResults) {
|
|
12806
|
+
for (let i = 0; i < sr.edits.length; i++) {
|
|
12807
|
+
const editReq = sr.edits[i];
|
|
12808
|
+
const result = sr.results[i];
|
|
12809
|
+
const resolved = resolvedEdits.find((r) => r.target === editReq.target);
|
|
12810
|
+
if (resolved) {
|
|
12811
|
+
successMap.set(resolved.editIdx, result);
|
|
12812
|
+
if (!result.success) {
|
|
12813
|
+
failMessages.push(
|
|
12814
|
+
`\uD3B8\uC9D1 #${resolved.editIdx + 1} (name="${editReq.target.name}"): ${result.error}`
|
|
12815
|
+
);
|
|
12816
|
+
}
|
|
12817
|
+
}
|
|
12818
|
+
}
|
|
12819
|
+
}
|
|
12820
|
+
if (failMessages.length > 0) {
|
|
12731
12821
|
return `\uC624\uB958: \uB2E4\uC74C \uD3B8\uC9D1\uC744 \uC801\uC6A9\uD560 \uC218 \uC5C6\uC5B4 \uD30C\uC77C\uC744 \uC218\uC815\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
12732
|
-
${
|
|
12822
|
+
${failMessages.join("\n")}`;
|
|
12823
|
+
}
|
|
12824
|
+
const out = new import_jszip3.default();
|
|
12825
|
+
const mimetypeEntry = zip.file("mimetype");
|
|
12826
|
+
if (mimetypeEntry) {
|
|
12827
|
+
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
12733
12828
|
}
|
|
12734
|
-
const
|
|
12735
|
-
|
|
12736
|
-
const
|
|
12737
|
-
if (
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12829
|
+
for (const [name, entry] of Object.entries(zip.files)) {
|
|
12830
|
+
if (name === "mimetype" || entry.dir) continue;
|
|
12831
|
+
const si = sectionFiles.indexOf(name);
|
|
12832
|
+
if (si >= 0) {
|
|
12833
|
+
out.file(name, newSectionXmls[si] ?? "");
|
|
12834
|
+
} else {
|
|
12835
|
+
out.file(name, await entry.async("uint8array"));
|
|
12836
|
+
}
|
|
12837
|
+
}
|
|
12838
|
+
const buf = await out.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
12839
|
+
const newBuffer = new Uint8Array(buf);
|
|
12840
|
+
const typeKo = {
|
|
12841
|
+
button: "PushButton",
|
|
12842
|
+
checkBox: "CheckBox",
|
|
12843
|
+
radioButton: "RadioButton",
|
|
12844
|
+
comboBox: "ComboBox",
|
|
12845
|
+
edit: "Edit"
|
|
12846
|
+
};
|
|
12847
|
+
const diffLines = ["| \uC591\uC2DD \uAC1C\uCCB4 | \uC774\uC804 | \uC774\uD6C4 |", "| --- | --- | --- |"];
|
|
12848
|
+
for (const re of resolvedEdits) {
|
|
12849
|
+
const result = successMap.get(re.editIdx);
|
|
12850
|
+
const oldVal = result?.oldValue ?? "";
|
|
12851
|
+
const oldStr = typeof oldVal === "boolean" ? oldVal ? "CHECKED" : "UNCHECKED" : String(oldVal);
|
|
12852
|
+
let newStr;
|
|
12853
|
+
if (re.set.caption !== void 0) newStr = re.set.caption;
|
|
12854
|
+
else if (re.set.checked !== void 0) newStr = re.set.checked ? "CHECKED" : "UNCHECKED";
|
|
12855
|
+
else if (re.set.selected !== void 0) newStr = re.set.selected;
|
|
12856
|
+
else newStr = re.set.text ?? "";
|
|
12857
|
+
diffLines.push(`| ${re.target.name}(${typeKo[re.target.type]}) | ${oldStr} | ${newStr} |`);
|
|
12741
12858
|
}
|
|
12742
12859
|
const diff = diffLines.join("\n");
|
|
12743
12860
|
const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
|
|
@@ -12746,7 +12863,7 @@ ${messages.join("\n")}`;
|
|
|
12746
12863
|
return {
|
|
12747
12864
|
proposal: {
|
|
12748
12865
|
id: proposalId,
|
|
12749
|
-
kind: "
|
|
12866
|
+
kind: "form-object",
|
|
12750
12867
|
targetPath: outputPath,
|
|
12751
12868
|
stagedPath,
|
|
12752
12869
|
summary: input.summary,
|
|
@@ -12763,6 +12880,92 @@ ${messages.join("\n")}`;
|
|
|
12763
12880
|
};
|
|
12764
12881
|
}
|
|
12765
12882
|
};
|
|
12883
|
+
var DOC_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12884
|
+
".hwp",
|
|
12885
|
+
".hwpx",
|
|
12886
|
+
".hwpml",
|
|
12887
|
+
".docx",
|
|
12888
|
+
".doc",
|
|
12889
|
+
".xlsx",
|
|
12890
|
+
".xls",
|
|
12891
|
+
".pdf",
|
|
12892
|
+
".pptx",
|
|
12893
|
+
".ppt",
|
|
12894
|
+
".md",
|
|
12895
|
+
".txt"
|
|
12896
|
+
]);
|
|
12897
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
12898
|
+
"node_modules",
|
|
12899
|
+
".git",
|
|
12900
|
+
".DS_Store",
|
|
12901
|
+
"__pycache__",
|
|
12902
|
+
"dist",
|
|
12903
|
+
"build",
|
|
12904
|
+
".next"
|
|
12905
|
+
]);
|
|
12906
|
+
var MAX_DEPTH = 4;
|
|
12907
|
+
var MAX_FILES = 500;
|
|
12908
|
+
var listFilesSchema = z6.object({
|
|
12909
|
+
dir: z6.string().optional().describe("\uBAA9\uB85D\uC744 \uC870\uD68C\uD560 \uB514\uB809\uD130\uB9AC (\uBBF8\uC9C0\uC815 \uC2DC cwd \uC804\uCCB4)")
|
|
12910
|
+
});
|
|
12911
|
+
async function collectFiles(dir, cwd, depth, entries) {
|
|
12912
|
+
if (depth > MAX_DEPTH || entries.length >= MAX_FILES) return;
|
|
12913
|
+
let items;
|
|
12914
|
+
try {
|
|
12915
|
+
items = await readdir3(dir);
|
|
12916
|
+
} catch {
|
|
12917
|
+
return;
|
|
12918
|
+
}
|
|
12919
|
+
for (const item of items) {
|
|
12920
|
+
if (entries.length >= MAX_FILES) break;
|
|
12921
|
+
if (item.startsWith(".")) continue;
|
|
12922
|
+
if (SKIP_DIRS.has(item)) continue;
|
|
12923
|
+
const fullPath = join4(dir, item);
|
|
12924
|
+
let info;
|
|
12925
|
+
try {
|
|
12926
|
+
info = await stat3(fullPath);
|
|
12927
|
+
} catch {
|
|
12928
|
+
continue;
|
|
12929
|
+
}
|
|
12930
|
+
const relPath = relative2(cwd, fullPath);
|
|
12931
|
+
const ext = extname6(item).toLowerCase();
|
|
12932
|
+
const isDoc = DOC_EXTENSIONS.has(ext);
|
|
12933
|
+
if (info.isDirectory()) {
|
|
12934
|
+
entries.push({ path: relPath + "/", isDir: true, isDoc: false });
|
|
12935
|
+
await collectFiles(fullPath, cwd, depth + 1, entries);
|
|
12936
|
+
} else if (info.isFile()) {
|
|
12937
|
+
entries.push({ path: relPath, isDir: false, isDoc });
|
|
12938
|
+
}
|
|
12939
|
+
}
|
|
12940
|
+
}
|
|
12941
|
+
var listFilesTool = {
|
|
12942
|
+
name: "list_files",
|
|
12943
|
+
description: "\uD604\uC7AC \uC791\uC5C5 \uB514\uB809\uD130\uB9AC(cwd) \uC774\uD558\uC758 \uD30C\uC77C \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. \uBB38\uC11C \uD30C\uC77C(.hwp/.hwpx/.docx/.xlsx/.pdf \uB4F1)\uC774 \uCD5C\uC0C1\uB2E8\uC5D0 \uD45C\uC2DC\uB429\uB2C8\uB2E4. \uAE4A\uC774\uB294 \uCD5C\uB300 4\uB2E8\uACC4\uAE4C\uC9C0\uC785\uB2C8\uB2E4.",
|
|
12944
|
+
inputSchema: listFilesSchema,
|
|
12945
|
+
requiresApproval: false,
|
|
12946
|
+
execute: async ({
|
|
12947
|
+
input,
|
|
12948
|
+
ctx
|
|
12949
|
+
}) => {
|
|
12950
|
+
const targetDir = input.dir ? await resolveSafePath(ctx.cwd, input.dir) : ctx.cwd;
|
|
12951
|
+
const entries = [];
|
|
12952
|
+
await collectFiles(targetDir, ctx.cwd, 0, entries);
|
|
12953
|
+
if (entries.length === 0) {
|
|
12954
|
+
return "\uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
12955
|
+
}
|
|
12956
|
+
const docs = entries.filter((e) => e.isDoc);
|
|
12957
|
+
const dirs = entries.filter((e) => e.isDir);
|
|
12958
|
+
const others = entries.filter((e) => !e.isDoc && !e.isDir);
|
|
12959
|
+
const allSorted = [...docs, ...dirs, ...others];
|
|
12960
|
+
const lines = allSorted.map((e) => {
|
|
12961
|
+
const icon = e.isDir ? "\u{1F4C1}" : e.isDoc ? "\u{1F4C4}" : " ";
|
|
12962
|
+
return `${icon} ${e.path}`;
|
|
12963
|
+
});
|
|
12964
|
+
const truncateNotice = entries.length >= MAX_FILES ? `
|
|
12965
|
+
(\uCD5C\uB300 ${MAX_FILES}\uAC1C\uAE4C\uC9C0 \uD45C\uC2DC\uB429\uB2C8\uB2E4. \uB354 \uC881\uC740 \uBC94\uC704\uB97C \uC9C0\uC815\uD558\uC138\uC694.)` : "";
|
|
12966
|
+
return lines.join("\n") + truncateNotice;
|
|
12967
|
+
}
|
|
12968
|
+
};
|
|
12766
12969
|
var HEADING_LEVELS = {
|
|
12767
12970
|
1: HeadingLevel.HEADING_1,
|
|
12768
12971
|
2: HeadingLevel.HEADING_2,
|
|
@@ -12885,10 +13088,10 @@ async function markdownToDocx(markdown) {
|
|
|
12885
13088
|
});
|
|
12886
13089
|
return Packer.toBuffer(doc);
|
|
12887
13090
|
}
|
|
12888
|
-
var proposeEditSchema =
|
|
12889
|
-
path:
|
|
12890
|
-
newMarkdown:
|
|
12891
|
-
summary:
|
|
13091
|
+
var proposeEditSchema = z7.object({
|
|
13092
|
+
path: z7.string().describe("\uC218\uC815\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
13093
|
+
newMarkdown: z7.string().describe("\uC0C8 \uBB38\uC11C \uB0B4\uC6A9 (\uB9C8\uD06C\uB2E4\uC6B4 \uD615\uC2DD). read_document\uB85C \uC6D0\uBCF8\uC744 \uBA3C\uC800 \uC77D\uC5B4\uC57C \uD568"),
|
|
13094
|
+
summary: z7.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
12892
13095
|
});
|
|
12893
13096
|
var proposeEditTool = {
|
|
12894
13097
|
name: "propose_edit",
|
|
@@ -12900,10 +13103,10 @@ var proposeEditTool = {
|
|
|
12900
13103
|
ctx
|
|
12901
13104
|
}) => {
|
|
12902
13105
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
12903
|
-
const ext =
|
|
13106
|
+
const ext = extname7(safePath).toLowerCase();
|
|
12904
13107
|
let originalBuffer;
|
|
12905
13108
|
try {
|
|
12906
|
-
originalBuffer = await
|
|
13109
|
+
originalBuffer = await readFile7(safePath);
|
|
12907
13110
|
} catch {
|
|
12908
13111
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uAC70\uB098 read_document\uB85C \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`;
|
|
12909
13112
|
}
|
|
@@ -12915,15 +13118,21 @@ var proposeEditTool = {
|
|
|
12915
13118
|
originalMarkdown = originalResult.markdown;
|
|
12916
13119
|
}
|
|
12917
13120
|
if (ext === ".hwpx" || ext === ".hwp") {
|
|
12918
|
-
const
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
13121
|
+
const origU8 = new Uint8Array(
|
|
13122
|
+
originalBuffer.buffer,
|
|
13123
|
+
originalBuffer.byteOffset,
|
|
13124
|
+
originalBuffer.byteLength
|
|
13125
|
+
);
|
|
13126
|
+
const patchResult = ext === ".hwp" ? await patchHwp(origU8, input.newMarkdown) : await patchHwpx(origU8, input.newMarkdown);
|
|
13127
|
+
if (!patchResult.success || !patchResult.data) {
|
|
13128
|
+
return `\uC624\uB958: \uD3B8\uC9D1\uC744 \uC801\uC6A9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${patchResult.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}. read_document\uB85C \uC6D0\uBCF8\uC744 \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694.`;
|
|
13129
|
+
}
|
|
13130
|
+
stagedData = patchResult.data;
|
|
13131
|
+
for (const s of patchResult.skipped) {
|
|
13132
|
+
warnings.push(
|
|
13133
|
+
`\uC77C\uBD80 \uBCC0\uACBD\uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(${s.reason ?? "\uC0AC\uC720 \uBBF8\uC0C1"}). \uD45C \uAD6C\uC870 \uBCC0\uACBD\uC740 propose_table_structure, \uC140 \uAC12\uC740 propose_cell_edit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`
|
|
13134
|
+
);
|
|
12925
13135
|
}
|
|
12926
|
-
stagedData = new Uint8Array(hwpxBuffer);
|
|
12927
13136
|
} else if (ext === ".docx") {
|
|
12928
13137
|
warnings.push("DOCX \uC7AC\uC0DD\uC131: \uBCF5\uC7A1\uD55C \uC11C\uC2DD(\uBA38\uB9AC\uAE00/\uAC01\uC8FC/\uC2A4\uD0C0\uC77C)\uC740 \uC190\uC2E4\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
12929
13138
|
const docxBuffer = await markdownToDocx(input.newMarkdown);
|
|
@@ -12933,7 +13142,8 @@ var proposeEditTool = {
|
|
|
12933
13142
|
} else {
|
|
12934
13143
|
return `\uC624\uB958: \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4: ${ext}. .hwp, .hwpx, .docx, .md, .txt\uB9CC \uC218\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.`;
|
|
12935
13144
|
}
|
|
12936
|
-
const
|
|
13145
|
+
const outputPath = ext === ".hwpx" || ext === ".hwp" ? safePath : resolveOutputPath(safePath).outputPath;
|
|
13146
|
+
const willConvertFormat = ext === ".hwpx" || ext === ".hwp" ? void 0 : resolveOutputPath(safePath).willConvertFormat;
|
|
12937
13147
|
const stagedPath = await stageFile(ctx.sessionId, safePath, stagedData);
|
|
12938
13148
|
let diff = markdownDiff(originalMarkdown, input.newMarkdown, safePath);
|
|
12939
13149
|
if (ext === ".hwpx" || ext === ".hwp") {
|
|
@@ -12974,19 +13184,19 @@ ${diff}`;
|
|
|
12974
13184
|
};
|
|
12975
13185
|
}
|
|
12976
13186
|
};
|
|
12977
|
-
var proposeFindReplaceSchema =
|
|
12978
|
-
path:
|
|
12979
|
-
find:
|
|
12980
|
-
replace:
|
|
12981
|
-
caseSensitive:
|
|
12982
|
-
all:
|
|
12983
|
-
summary:
|
|
13187
|
+
var proposeFindReplaceSchema = z8.object({
|
|
13188
|
+
path: z8.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
13189
|
+
find: z8.string().min(1).describe("\uCC3E\uC744 \uD14D\uC2A4\uD2B8"),
|
|
13190
|
+
replace: z8.string().describe("\uBC14\uAFC0 \uD14D\uC2A4\uD2B8"),
|
|
13191
|
+
caseSensitive: z8.boolean().optional().default(false).describe("\uB300\uC18C\uBB38\uC790 \uAD6C\uBD84 (\uAE30\uBCF8\uAC12: false)"),
|
|
13192
|
+
all: z8.boolean().optional().default(true).describe("\uBAA8\uB4E0 \uD56D\uBAA9\uC744 \uAD50\uCCB4\uD560\uC9C0 \uC5EC\uBD80 (\uAE30\uBCF8\uAC12: true). false\uC774\uBA74 \uCCAB \uBC88\uC9F8 \uB9E4\uCE58\uB9CC \uAD50\uCCB4"),
|
|
13193
|
+
summary: z8.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
12984
13194
|
});
|
|
12985
13195
|
var MAX_DIFF_SAMPLES = 20;
|
|
12986
13196
|
function escapeXml3(text3) {
|
|
12987
13197
|
return text3.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
12988
13198
|
}
|
|
12989
|
-
function
|
|
13199
|
+
function unescapeXml2(text3) {
|
|
12990
13200
|
return text3.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
12991
13201
|
}
|
|
12992
13202
|
function makeChangeSnippet(before, after, ctx = 24) {
|
|
@@ -13010,7 +13220,7 @@ function collectChangedSnippets(beforeXml, afterXml, maxSamples) {
|
|
|
13010
13220
|
const n = Math.min(beforeNodes.length, afterNodes.length);
|
|
13011
13221
|
for (let i = 0; i < n && out.length < maxSamples; i++) {
|
|
13012
13222
|
if (beforeNodes[i] !== afterNodes[i]) {
|
|
13013
|
-
const snip = makeChangeSnippet(
|
|
13223
|
+
const snip = makeChangeSnippet(unescapeXml2(beforeNodes[i]), unescapeXml2(afterNodes[i]));
|
|
13014
13224
|
out.push(snip);
|
|
13015
13225
|
}
|
|
13016
13226
|
}
|
|
@@ -13093,7 +13303,7 @@ function countOccurrences(str, sub) {
|
|
|
13093
13303
|
return count;
|
|
13094
13304
|
}
|
|
13095
13305
|
async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive, replaceAll) {
|
|
13096
|
-
const zip = await
|
|
13306
|
+
const zip = await import_jszip4.default.loadAsync(hwpxBuffer);
|
|
13097
13307
|
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
13098
13308
|
const sectionXmls = [];
|
|
13099
13309
|
for (const sf of sectionFiles) {
|
|
@@ -13137,7 +13347,7 @@ async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive,
|
|
|
13137
13347
|
samples.push(snip);
|
|
13138
13348
|
}
|
|
13139
13349
|
}
|
|
13140
|
-
const out = new
|
|
13350
|
+
const out = new import_jszip4.default();
|
|
13141
13351
|
const mimetypeEntry = zip.file("mimetype");
|
|
13142
13352
|
if (mimetypeEntry) {
|
|
13143
13353
|
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
@@ -13168,7 +13378,7 @@ var proposeFindReplaceTool = {
|
|
|
13168
13378
|
ctx
|
|
13169
13379
|
}) => {
|
|
13170
13380
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
13171
|
-
const ext =
|
|
13381
|
+
const ext = extname8(safePath).toLowerCase();
|
|
13172
13382
|
if (ext === ".hwp") {
|
|
13173
13383
|
return "\uC624\uB958: propose_find_replace\uB294 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 XML \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
13174
13384
|
}
|
|
@@ -13177,7 +13387,7 @@ var proposeFindReplaceTool = {
|
|
|
13177
13387
|
}
|
|
13178
13388
|
let originalBuf;
|
|
13179
13389
|
try {
|
|
13180
|
-
originalBuf = await
|
|
13390
|
+
originalBuf = await readFile8(safePath);
|
|
13181
13391
|
} catch {
|
|
13182
13392
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
|
|
13183
13393
|
}
|
|
@@ -13270,10 +13480,10 @@ var proposeFindReplaceTool = {
|
|
|
13270
13480
|
};
|
|
13271
13481
|
}
|
|
13272
13482
|
};
|
|
13273
|
-
var proposeFormFillSchema =
|
|
13274
|
-
path:
|
|
13275
|
-
fields:
|
|
13276
|
-
summary:
|
|
13483
|
+
var proposeFormFillSchema = z9.object({
|
|
13484
|
+
path: z9.string().describe("\uC591\uC2DD \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
13485
|
+
fields: z9.record(z9.string(), z9.string()).describe("\uCC44\uC6B8 \uD544\uB4DC \uB9E4\uD551: { \uB77C\uBCA8: \uAC12 }. read_document\uB85C \uBA3C\uC800 \uD544\uB4DC \uBAA9\uB85D\uC744 \uD655\uC778\uD558\uC138\uC694"),
|
|
13486
|
+
summary: z9.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
13277
13487
|
});
|
|
13278
13488
|
var proposeFormFillTool = {
|
|
13279
13489
|
name: "propose_form_fill",
|
|
@@ -13285,13 +13495,13 @@ var proposeFormFillTool = {
|
|
|
13285
13495
|
ctx
|
|
13286
13496
|
}) => {
|
|
13287
13497
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
13288
|
-
const ext =
|
|
13498
|
+
const ext = extname9(safePath).toLowerCase();
|
|
13289
13499
|
if (ext !== ".hwpx" && ext !== ".hwp") {
|
|
13290
13500
|
return `\uC624\uB958: propose_form_fill\uC740 .hwp/.hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}. .docx \uD30C\uC77C\uC740 propose_edit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`;
|
|
13291
13501
|
}
|
|
13292
13502
|
let originalBuffer;
|
|
13293
13503
|
try {
|
|
13294
|
-
originalBuffer = await
|
|
13504
|
+
originalBuffer = await readFile9(safePath);
|
|
13295
13505
|
} catch {
|
|
13296
13506
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
|
|
13297
13507
|
}
|
|
@@ -13327,15 +13537,19 @@ var proposeFormFillTool = {
|
|
|
13327
13537
|
}
|
|
13328
13538
|
}
|
|
13329
13539
|
const diff = diffLines.join("\n");
|
|
13330
|
-
const
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13540
|
+
const origU8 = new Uint8Array(
|
|
13541
|
+
originalBuffer.buffer,
|
|
13542
|
+
originalBuffer.byteOffset,
|
|
13543
|
+
originalBuffer.byteLength
|
|
13544
|
+
);
|
|
13545
|
+
const patchResult = await patchHwpx2(origU8, newMarkdown);
|
|
13546
|
+
if (!patchResult.success || !patchResult.data) {
|
|
13547
|
+
return `\uC624\uB958: \uC591\uC2DD \uCC44\uC6B0\uAE30\uB97C \uC801\uC6A9\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${patchResult.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}.`;
|
|
13548
|
+
}
|
|
13549
|
+
const stagedData = patchResult.data;
|
|
13550
|
+
for (const s of patchResult.skipped) {
|
|
13551
|
+
warnings.push(`\uC77C\uBD80 \uD56D\uBAA9\uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(${s.reason ?? "\uC0AC\uC720 \uBBF8\uC0C1"}).`);
|
|
13337
13552
|
}
|
|
13338
|
-
const stagedData = new Uint8Array(hwpxBuffer);
|
|
13339
13553
|
const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
|
|
13340
13554
|
const stagedPath = await stageFile(ctx.sessionId, safePath, stagedData);
|
|
13341
13555
|
const proposalId = crypto.randomUUID();
|
|
@@ -13359,16 +13573,216 @@ var proposeFormFillTool = {
|
|
|
13359
13573
|
};
|
|
13360
13574
|
}
|
|
13361
13575
|
};
|
|
13362
|
-
var
|
|
13363
|
-
path:
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
13367
|
-
|
|
13368
|
-
|
|
13576
|
+
var proposeRedactPiiSchema = z10.object({
|
|
13577
|
+
path: z10.string().describe("\uAC1C\uC778\uC815\uBCF4\uB97C \uBE44\uC2DD\uBCC4 \uCC98\uB9AC\uD560 \uBB38\uC11C \uACBD\uB85C"),
|
|
13578
|
+
summary: z10.string().optional().describe("\uBCC0\uACBD \uC694\uC57D")
|
|
13579
|
+
});
|
|
13580
|
+
function mergeFindings(allFindings) {
|
|
13581
|
+
const map = /* @__PURE__ */ new Map();
|
|
13582
|
+
for (const findings of allFindings) {
|
|
13583
|
+
for (const f of findings) {
|
|
13584
|
+
const existing = map.get(f.type);
|
|
13585
|
+
if (existing) {
|
|
13586
|
+
existing.count += f.count;
|
|
13587
|
+
for (const m of f.masked) {
|
|
13588
|
+
if (!existing.masked.includes(m) && existing.masked.length < 5) {
|
|
13589
|
+
existing.masked.push(m);
|
|
13590
|
+
}
|
|
13591
|
+
}
|
|
13592
|
+
} else {
|
|
13593
|
+
map.set(f.type, { type: f.type, count: f.count, masked: [...f.masked] });
|
|
13594
|
+
}
|
|
13595
|
+
}
|
|
13596
|
+
}
|
|
13597
|
+
return [...map.values()];
|
|
13598
|
+
}
|
|
13599
|
+
async function applyRedactToHwpx(hwpxBuffer) {
|
|
13600
|
+
const zip = await import_jszip5.default.loadAsync(hwpxBuffer);
|
|
13601
|
+
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
13602
|
+
const sectionXmls = [];
|
|
13603
|
+
for (const sf of sectionFiles) {
|
|
13604
|
+
const entry = zip.file(sf);
|
|
13605
|
+
const xml = entry ? await entry.async("string") : "";
|
|
13606
|
+
sectionXmls.push(xml);
|
|
13607
|
+
}
|
|
13608
|
+
const newSectionXmls = [];
|
|
13609
|
+
const allFindings = [];
|
|
13610
|
+
let anyChanged = false;
|
|
13611
|
+
for (const srcXml of sectionXmls) {
|
|
13612
|
+
const tNodeRe = /<hp:t>([\s\S]*?)<\/hp:t>/g;
|
|
13613
|
+
const sectionFindings = [];
|
|
13614
|
+
let offset = 0;
|
|
13615
|
+
let result = srcXml;
|
|
13616
|
+
let m = tNodeRe.exec(srcXml);
|
|
13617
|
+
while (m !== null) {
|
|
13618
|
+
const content = m[1];
|
|
13619
|
+
if (content.length === 0) {
|
|
13620
|
+
m = tNodeRe.exec(srcXml);
|
|
13621
|
+
continue;
|
|
13622
|
+
}
|
|
13623
|
+
const { text: redacted, findings } = redactText(content);
|
|
13624
|
+
if (redacted !== content) {
|
|
13625
|
+
const openTagLen = "<hp:t>".length;
|
|
13626
|
+
const contentStart = m.index + offset + openTagLen;
|
|
13627
|
+
const contentEnd = contentStart + content.length;
|
|
13628
|
+
result = result.substring(0, contentStart) + redacted + result.substring(contentEnd);
|
|
13629
|
+
offset += redacted.length - content.length;
|
|
13630
|
+
anyChanged = true;
|
|
13631
|
+
}
|
|
13632
|
+
if (findings.length > 0) {
|
|
13633
|
+
sectionFindings.push(findings);
|
|
13634
|
+
}
|
|
13635
|
+
m = tNodeRe.exec(srcXml);
|
|
13636
|
+
}
|
|
13637
|
+
newSectionXmls.push(result);
|
|
13638
|
+
allFindings.push(...sectionFindings);
|
|
13639
|
+
}
|
|
13640
|
+
if (!anyChanged) {
|
|
13641
|
+
return { buffer: hwpxBuffer, findings: mergeFindings(allFindings), changed: false };
|
|
13642
|
+
}
|
|
13643
|
+
const out = new import_jszip5.default();
|
|
13644
|
+
const mimetypeEntry = zip.file("mimetype");
|
|
13645
|
+
if (mimetypeEntry) {
|
|
13646
|
+
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
13647
|
+
}
|
|
13648
|
+
for (const [name, entry] of Object.entries(zip.files)) {
|
|
13649
|
+
if (name === "mimetype" || entry.dir) continue;
|
|
13650
|
+
const sectionIdx = sectionFiles.indexOf(name);
|
|
13651
|
+
if (sectionIdx >= 0) {
|
|
13652
|
+
out.file(name, newSectionXmls[sectionIdx] ?? "");
|
|
13653
|
+
} else {
|
|
13654
|
+
out.file(name, await entry.async("uint8array"));
|
|
13655
|
+
}
|
|
13656
|
+
}
|
|
13657
|
+
const buf = await out.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
|
|
13658
|
+
return {
|
|
13659
|
+
buffer: new Uint8Array(buf),
|
|
13660
|
+
findings: mergeFindings(allFindings),
|
|
13661
|
+
changed: true
|
|
13662
|
+
};
|
|
13663
|
+
}
|
|
13664
|
+
function buildDiff(findings) {
|
|
13665
|
+
const total = findings.reduce((s, f) => s + f.count, 0);
|
|
13666
|
+
const lines = [`\uAC1C\uC778\uC815\uBCF4 ${total}\uAC74 \uBE44\uC2DD\uBCC4 \uCC98\uB9AC`];
|
|
13667
|
+
for (const f of findings) {
|
|
13668
|
+
const examples = f.masked.slice(0, 3).join(", ");
|
|
13669
|
+
lines.push(`- ${f.type}: ${f.count}\uAC74 \u2192 ${examples}`);
|
|
13670
|
+
}
|
|
13671
|
+
return lines.join("\n");
|
|
13672
|
+
}
|
|
13673
|
+
var proposeRedactPiiTool = {
|
|
13674
|
+
name: "propose_redact_pii",
|
|
13675
|
+
description: "\uBB38\uC11C\uC758 \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\xB7\uC804\uD654\uBC88\uD638\xB7\uC774\uBA54\uC77C\xB7\uC2E0\uC6A9\uCE74\uB4DC\uBC88\uD638)\uB97C \uAC00\uB9AC\uAE30/\uB9C8\uC2A4\uD0B9/\uBE44\uC2DD\uBCC4 \uCC98\uB9AC\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790\uAC00 '\uAC1C\uC778\uC815\uBCF4 \uAC00\uB824\uC918/\uC9C0\uC6CC\uC918/\uBE44\uC2DD\uBCC4 \uCC98\uB9AC\uD574\uC918/\uB9C8\uC2A4\uD0B9\uD574\uC918'\uB77C\uACE0 \uD558\uBA74 \uC774 \uB3C4\uAD6C\uB85C \uC218\uC815\uC548\uC744 \uC81C\uC548\uD558\uC138\uC694(scan_pii\uB294 \uD655\uC778\uC6A9\uC77C \uBFD0 \uC218\uC815\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4). .hwpx\uB294 XML \uC9C1\uC811 \uD328\uCE58\uB85C \uAD6C\uC870(\uD45C\xB7\uC774\uBBF8\uC9C0\xB7\uC11C\uC2DD)\uB97C \uBCF4\uC874\uD558\uBA70, .md/.txt\uB3C4 \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uBCC0\uACBD\uC740 \uC2B9\uC778 \uD6C4\uC5D0\uB9CC \uC800\uC7A5\uB429\uB2C8\uB2E4. \uC6D0\uBB38 \uAC12\uC740 \uD45C\uC2DC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
13676
|
+
inputSchema: proposeRedactPiiSchema,
|
|
13677
|
+
requiresApproval: true,
|
|
13678
|
+
propose: async ({
|
|
13679
|
+
input,
|
|
13680
|
+
ctx
|
|
13681
|
+
}) => {
|
|
13682
|
+
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
13683
|
+
const ext = extname10(safePath).toLowerCase();
|
|
13684
|
+
if (ext === ".hwp") {
|
|
13685
|
+
return "\uC624\uB958: propose_redact_pii\uB294 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 XML \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
13686
|
+
}
|
|
13687
|
+
if (ext !== ".hwpx" && ext !== ".md" && ext !== ".txt") {
|
|
13688
|
+
const hint = ext === ".docx" || ext === ".xlsx" ? " .hwpx/.md/.txt\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4." : " .hwpx/.md/.txt\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4.";
|
|
13689
|
+
return `\uC624\uB958: propose_redact_pii\uB294 .hwpx/.md/.txt \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C \uD655\uC7A5\uC790: ${ext}.${hint}`;
|
|
13690
|
+
}
|
|
13691
|
+
const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
|
|
13692
|
+
if (ext === ".hwpx") {
|
|
13693
|
+
let originalBuf;
|
|
13694
|
+
try {
|
|
13695
|
+
originalBuf = await readFile10(safePath);
|
|
13696
|
+
} catch {
|
|
13697
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
13698
|
+
}
|
|
13699
|
+
if (originalBuf[0] !== 80 || originalBuf[1] !== 75) {
|
|
13700
|
+
return "\uC624\uB958: \uD30C\uC77C\uC774 \uC720\uD6A8\uD55C .hwpx(ZIP) \uD3EC\uB9F7\uC774 \uC544\uB2D9\uB2C8\uB2E4. \uD30C\uC77C\uC774 \uC190\uC0C1\uB418\uC5C8\uAC70\uB098 \uAD6C\uD615 .hwp(OLE \uBC14\uC774\uB108\uB9AC) \uD3EC\uB9F7\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
|
|
13701
|
+
}
|
|
13702
|
+
const originalBytes = new Uint8Array(
|
|
13703
|
+
originalBuf.buffer,
|
|
13704
|
+
originalBuf.byteOffset,
|
|
13705
|
+
originalBuf.byteLength
|
|
13706
|
+
);
|
|
13707
|
+
let patchResult;
|
|
13708
|
+
try {
|
|
13709
|
+
patchResult = await applyRedactToHwpx(originalBytes);
|
|
13710
|
+
} catch (e) {
|
|
13711
|
+
return `\uC624\uB958: \uBE44\uC2DD\uBCC4 \uCC98\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. ${String(e)}`;
|
|
13712
|
+
}
|
|
13713
|
+
const { buffer: newBytes, findings: findings2, changed } = patchResult;
|
|
13714
|
+
const totalCount2 = findings2.reduce((s, f) => s + f.count, 0);
|
|
13715
|
+
if (!changed || totalCount2 === 0) {
|
|
13716
|
+
return `\uAC1C\uC778\uC815\uBCF4\uAC00 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC544 \uBCC0\uACBD\uD560 \uB0B4\uC6A9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
13717
|
+
}
|
|
13718
|
+
const stagedPath2 = await stageFile(ctx.sessionId, outputPath, newBytes);
|
|
13719
|
+
const proposalId2 = crypto.randomUUID();
|
|
13720
|
+
const diff2 = buildDiff(findings2);
|
|
13721
|
+
const summaryText2 = input.summary ?? `\uAC1C\uC778\uC815\uBCF4 \uBE44\uC2DD\uBCC4 \uCC98\uB9AC(\uB9C8\uC2A4\uD0B9): ${basename4(safePath)}`;
|
|
13722
|
+
return {
|
|
13723
|
+
proposal: {
|
|
13724
|
+
id: proposalId2,
|
|
13725
|
+
kind: "redact-pii",
|
|
13726
|
+
targetPath: outputPath,
|
|
13727
|
+
stagedPath: stagedPath2,
|
|
13728
|
+
summary: summaryText2,
|
|
13729
|
+
diff: diff2,
|
|
13730
|
+
warnings: [],
|
|
13731
|
+
willConvertFormat
|
|
13732
|
+
},
|
|
13733
|
+
commit: async () => {
|
|
13734
|
+
const backupPath = await backupFile(outputPath);
|
|
13735
|
+
await commitStaged(stagedPath2, outputPath);
|
|
13736
|
+
const backupInfo = backupPath ? ` (\uBC31\uC5C5: ${backupPath})` : "";
|
|
13737
|
+
return `\uAC1C\uC778\uC815\uBCF4 \uBE44\uC2DD\uBCC4 \uC644\uB8CC: ${outputPath}${backupInfo}`;
|
|
13738
|
+
}
|
|
13739
|
+
};
|
|
13740
|
+
}
|
|
13741
|
+
let originalText;
|
|
13742
|
+
try {
|
|
13743
|
+
originalText = await readFile10(safePath, "utf-8");
|
|
13744
|
+
} catch {
|
|
13745
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
13746
|
+
}
|
|
13747
|
+
const { text: redacted, findings } = redactText(originalText);
|
|
13748
|
+
const totalCount = findings.reduce((s, f) => s + f.count, 0);
|
|
13749
|
+
if (totalCount === 0) {
|
|
13750
|
+
return `\uAC1C\uC778\uC815\uBCF4\uAC00 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC544 \uBCC0\uACBD\uD560 \uB0B4\uC6A9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
13751
|
+
}
|
|
13752
|
+
const stagedPath = await stageFile(ctx.sessionId, outputPath, redacted);
|
|
13753
|
+
const proposalId = crypto.randomUUID();
|
|
13754
|
+
const diff = buildDiff(findings);
|
|
13755
|
+
const summaryText = input.summary ?? `\uAC1C\uC778\uC815\uBCF4 \uBE44\uC2DD\uBCC4 \uCC98\uB9AC(\uB9C8\uC2A4\uD0B9): ${basename4(safePath)}`;
|
|
13756
|
+
return {
|
|
13757
|
+
proposal: {
|
|
13758
|
+
id: proposalId,
|
|
13759
|
+
kind: "redact-pii",
|
|
13760
|
+
targetPath: outputPath,
|
|
13761
|
+
stagedPath,
|
|
13762
|
+
summary: summaryText,
|
|
13763
|
+
diff,
|
|
13764
|
+
warnings: [],
|
|
13765
|
+
willConvertFormat
|
|
13766
|
+
},
|
|
13767
|
+
commit: async () => {
|
|
13768
|
+
const backupPath = await backupFile(outputPath);
|
|
13769
|
+
await commitStaged(stagedPath, outputPath);
|
|
13770
|
+
const backupInfo = backupPath ? ` (\uBC31\uC5C5: ${backupPath})` : "";
|
|
13771
|
+
return `\uAC1C\uC778\uC815\uBCF4 \uBE44\uC2DD\uBCC4 \uC644\uB8CC: ${outputPath}${backupInfo}`;
|
|
13772
|
+
}
|
|
13773
|
+
};
|
|
13774
|
+
}
|
|
13775
|
+
};
|
|
13776
|
+
var proposeSheetEditSchema = z11.object({
|
|
13777
|
+
path: z11.string().describe("\uC218\uC815\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
13778
|
+
updates: z11.array(
|
|
13779
|
+
z11.object({
|
|
13780
|
+
sheet: z11.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
|
|
13781
|
+
cell: z11.string().describe("\uC140 \uC8FC\uC18C (\uC608: A1, B3)"),
|
|
13782
|
+
value: z11.union([z11.string(), z11.number()]).describe("\uC0C8 \uAC12")
|
|
13369
13783
|
})
|
|
13370
13784
|
).min(1).describe("\uC218\uC815\uD560 \uC140 \uBAA9\uB85D. read_document\uB85C \uC6D0\uBCF8 \uC2DC\uD2B8 \uAD6C\uC870\uB97C \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694"),
|
|
13371
|
-
summary:
|
|
13785
|
+
summary: z11.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
13372
13786
|
});
|
|
13373
13787
|
var proposeSheetEditTool = {
|
|
13374
13788
|
name: "propose_sheet_edit",
|
|
@@ -13380,13 +13794,13 @@ var proposeSheetEditTool = {
|
|
|
13380
13794
|
ctx
|
|
13381
13795
|
}) => {
|
|
13382
13796
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
13383
|
-
const ext =
|
|
13797
|
+
const ext = extname11(safePath).toLowerCase();
|
|
13384
13798
|
if (ext !== ".xlsx" && ext !== ".xls") {
|
|
13385
13799
|
return `\uC624\uB958: propose_sheet_edit\uC740 .xlsx/.xls \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}.`;
|
|
13386
13800
|
}
|
|
13387
13801
|
let originalBuffer;
|
|
13388
13802
|
try {
|
|
13389
|
-
originalBuffer = await
|
|
13803
|
+
originalBuffer = await readFile11(safePath);
|
|
13390
13804
|
} catch {
|
|
13391
13805
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
|
|
13392
13806
|
}
|
|
@@ -13479,47 +13893,47 @@ function detectStructuralLoss(beforeBlocks, afterBlocks) {
|
|
|
13479
13893
|
}
|
|
13480
13894
|
return { lost: false, detail: "" };
|
|
13481
13895
|
}
|
|
13482
|
-
var insertRowOpSchema =
|
|
13483
|
-
type:
|
|
13484
|
-
row:
|
|
13485
|
-
position:
|
|
13896
|
+
var insertRowOpSchema = z12.object({
|
|
13897
|
+
type: z12.literal("insertRow"),
|
|
13898
|
+
row: z12.number().int().nonnegative().describe("\uAE30\uC900 \uD589 \uC778\uB371\uC2A4 (0-based)"),
|
|
13899
|
+
position: z12.enum(["above", "below"]).describe("\uC0BD\uC785 \uC704\uCE58: above=row \uC704\uC5D0, below=row \uC544\uB798\uC5D0")
|
|
13486
13900
|
});
|
|
13487
|
-
var deleteRowOpSchema =
|
|
13488
|
-
type:
|
|
13489
|
-
row:
|
|
13901
|
+
var deleteRowOpSchema = z12.object({
|
|
13902
|
+
type: z12.literal("deleteRow"),
|
|
13903
|
+
row: z12.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uD589 \uC778\uB371\uC2A4 (0-based)")
|
|
13490
13904
|
});
|
|
13491
|
-
var insertColumnOpSchema =
|
|
13492
|
-
type:
|
|
13493
|
-
col:
|
|
13494
|
-
position:
|
|
13905
|
+
var insertColumnOpSchema = z12.object({
|
|
13906
|
+
type: z12.literal("insertColumn"),
|
|
13907
|
+
col: z12.number().int().nonnegative().describe("\uAE30\uC900 \uC5F4 \uC778\uB371\uC2A4 (0-based)"),
|
|
13908
|
+
position: z12.enum(["left", "right"]).describe("\uC0BD\uC785 \uC704\uCE58: left=col \uC67C\uCABD\uC5D0, right=col \uC624\uB978\uCABD\uC5D0")
|
|
13495
13909
|
});
|
|
13496
|
-
var deleteColumnOpSchema =
|
|
13497
|
-
type:
|
|
13498
|
-
col:
|
|
13910
|
+
var deleteColumnOpSchema = z12.object({
|
|
13911
|
+
type: z12.literal("deleteColumn"),
|
|
13912
|
+
col: z12.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uC5F4 \uC778\uB371\uC2A4 (0-based)")
|
|
13499
13913
|
});
|
|
13500
|
-
var mergeCellsOpSchema =
|
|
13501
|
-
type:
|
|
13502
|
-
startRow:
|
|
13503
|
-
startCol:
|
|
13504
|
-
endRow:
|
|
13505
|
-
endCol:
|
|
13914
|
+
var mergeCellsOpSchema = z12.object({
|
|
13915
|
+
type: z12.literal("mergeCells"),
|
|
13916
|
+
startRow: z12.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uD589 (0-based)"),
|
|
13917
|
+
startCol: z12.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uC5F4 (0-based)"),
|
|
13918
|
+
endRow: z12.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uD589 (0-based, \uD3EC\uD568)"),
|
|
13919
|
+
endCol: z12.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uC5F4 (0-based, \uD3EC\uD568)")
|
|
13506
13920
|
});
|
|
13507
|
-
var operationSchema =
|
|
13921
|
+
var operationSchema = z12.discriminatedUnion("type", [
|
|
13508
13922
|
insertRowOpSchema,
|
|
13509
13923
|
deleteRowOpSchema,
|
|
13510
13924
|
insertColumnOpSchema,
|
|
13511
13925
|
deleteColumnOpSchema,
|
|
13512
13926
|
mergeCellsOpSchema
|
|
13513
13927
|
]).describe("\uD45C \uAD6C\uC870 \uC5F0\uC0B0. \uB098\uC911 \uC5F0\uC0B0\uC758 row/col \uC778\uB371\uC2A4\uB294 \uC55E \uC5F0\uC0B0 \uC801\uC6A9 \uD6C4 \uC0C1\uD0DC\uB97C \uAE30\uC900\uC73C\uB85C \uD55C\uB2E4.");
|
|
13514
|
-
var proposeTableStructureSchema =
|
|
13515
|
-
path:
|
|
13516
|
-
anchor:
|
|
13928
|
+
var proposeTableStructureSchema = z12.object({
|
|
13929
|
+
path: z12.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
13930
|
+
anchor: z12.string().min(1).describe(
|
|
13517
13931
|
"\uB300\uC0C1 \uD45C\uB97C \uC2DD\uBCC4\uD558\uB294 \uC575\uCEE4 \uD14D\uC2A4\uD2B8. \uD45C \uC548\uC5D0\uB9CC \uC788\uB294 \uB3C5\uD2B9\uD55C \uC140 \uD14D\uC2A4\uD2B8\uB97C \uC9C0\uC815\uD558\uC138\uC694. (\uBD80\uBD84 \uC77C\uCE58, \uACF5\uBC31 \uD2B8\uB9BC) \u2014 read_document\uB85C \uD655\uC778 \uD6C4 \uC0AC\uC6A9 \uAD8C\uC7A5."
|
|
13518
13932
|
),
|
|
13519
|
-
operations:
|
|
13933
|
+
operations: z12.array(operationSchema).min(1).describe(
|
|
13520
13934
|
"\uC801\uC6A9\uD560 \uD45C \uAD6C\uC870 \uC5F0\uC0B0 \uBAA9\uB85D (\uC21C\uC11C\uB300\uB85C \uC2E4\uD589). \uAC01 \uC5F0\uC0B0\uC740 \uC774\uC804 \uC5F0\uC0B0\uC774 \uC801\uC6A9\uB41C \uD6C4\uC758 \uD45C \uC0C1\uD0DC \uAE30\uC900\uC73C\uB85C row/col\uC744 \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4."
|
|
13521
13935
|
),
|
|
13522
|
-
summary:
|
|
13936
|
+
summary: z12.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
|
|
13523
13937
|
});
|
|
13524
13938
|
function tokenizeHwpxXml2(xml) {
|
|
13525
13939
|
const tokens = [];
|
|
@@ -14076,7 +14490,7 @@ function getTblDims(tblXml) {
|
|
|
14076
14490
|
return parseTblDimensions(tblXml, 0);
|
|
14077
14491
|
}
|
|
14078
14492
|
async function applyOpsToHwpx(hwpxBuffer, anchor, operations) {
|
|
14079
|
-
const zip = await
|
|
14493
|
+
const zip = await import_jszip6.default.loadAsync(hwpxBuffer);
|
|
14080
14494
|
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
14081
14495
|
let targetSectionIdx = -1;
|
|
14082
14496
|
let targetRange = null;
|
|
@@ -14135,7 +14549,7 @@ async function applyOpsToHwpx(hwpxBuffer, anchor, operations) {
|
|
|
14135
14549
|
const afterDims = getTblDims(tblBlock);
|
|
14136
14550
|
const newSectionXml = sectionXml.substring(0, targetRange.start) + tblBlock + sectionXml.substring(targetRange.end);
|
|
14137
14551
|
sectionXmls[targetSectionIdx] = newSectionXml;
|
|
14138
|
-
const out = new
|
|
14552
|
+
const out = new import_jszip6.default();
|
|
14139
14553
|
const mimetypeEntry = zip.file("mimetype");
|
|
14140
14554
|
if (mimetypeEntry) {
|
|
14141
14555
|
out.file("mimetype", await mimetypeEntry.async("uint8array"), { compression: "STORE" });
|
|
@@ -14159,7 +14573,7 @@ async function applyOpsToHwpx(hwpxBuffer, anchor, operations) {
|
|
|
14159
14573
|
};
|
|
14160
14574
|
}
|
|
14161
14575
|
async function verifyOutputDims(newBytes, anchor, expectedRowCnt, expectedColCnt) {
|
|
14162
|
-
const zip = await
|
|
14576
|
+
const zip = await import_jszip6.default.loadAsync(newBytes);
|
|
14163
14577
|
const sectionFiles = Object.keys(zip.files).filter((name) => /^Contents\/section\d+\.xml$/.test(name)).sort();
|
|
14164
14578
|
for (const sf of sectionFiles) {
|
|
14165
14579
|
const entry = zip.file(sf);
|
|
@@ -14194,7 +14608,7 @@ var proposeTableStructureTool = {
|
|
|
14194
14608
|
ctx
|
|
14195
14609
|
}) => {
|
|
14196
14610
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14197
|
-
const ext =
|
|
14611
|
+
const ext = extname12(safePath).toLowerCase();
|
|
14198
14612
|
if (ext === ".hwp") {
|
|
14199
14613
|
return "\uC624\uB958: propose_table_structure\uB294 .hwpx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. .hwp(\uAD6C\uD615 OLE \uBC14\uC774\uB108\uB9AC)\uB294 XML \uC9C1\uC811 \uD3B8\uC9D1\uC774 \uBD88\uAC00\uD569\uB2C8\uB2E4. \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C '\uB2E4\uB978 \uC774\uB984\uC73C\uB85C \uC800\uC7A5 \u2192 .hwpx'\uB85C \uC800\uC7A5\uD55C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.";
|
|
14200
14614
|
}
|
|
@@ -14203,7 +14617,7 @@ var proposeTableStructureTool = {
|
|
|
14203
14617
|
}
|
|
14204
14618
|
let originalBuf;
|
|
14205
14619
|
try {
|
|
14206
|
-
originalBuf = await
|
|
14620
|
+
originalBuf = await readFile12(safePath);
|
|
14207
14621
|
} catch {
|
|
14208
14622
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
|
|
14209
14623
|
}
|
|
@@ -14399,11 +14813,11 @@ function searchExcerpts(markdown, query) {
|
|
|
14399
14813
|
}
|
|
14400
14814
|
return result;
|
|
14401
14815
|
}
|
|
14402
|
-
var readDocumentSchema =
|
|
14403
|
-
path:
|
|
14404
|
-
pages:
|
|
14405
|
-
outline:
|
|
14406
|
-
search:
|
|
14816
|
+
var readDocumentSchema = z13.object({
|
|
14817
|
+
path: z13.string().describe("\uC77D\uC744 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
14818
|
+
pages: z13.string().optional().describe('\uC77D\uC744 \uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: "1-3", "1,3,5") \u2014 \uBBF8\uC9C0\uC815 \uC2DC \uC804\uCCB4'),
|
|
14819
|
+
outline: z13.boolean().optional().describe("\uD5E4\uB529(\uC81C\uBAA9) \uAD6C\uC870\uB9CC \uBC18\uD658\uD574 \uBB38\uC11C \uAC1C\uC694 \uD30C\uC545 (\uB300\uD615 \uBB38\uC11C \uD0D0\uC0C9\uC6A9)"),
|
|
14820
|
+
search: z13.string().optional().describe("\uD0A4\uC6CC\uB4DC\uAC00 \uD3EC\uD568\uB41C \uBD80\uBD84\uACFC \uC8FC\uBCC0 \uB9E5\uB77D\uB9CC \uBC18\uD658 (\uB300\uD615 \uBB38\uC11C\uC5D0\uC11C \uD544\uC694\uD55C \uBD80\uBD84\uB9CC \uC77D\uAE30)")
|
|
14407
14821
|
});
|
|
14408
14822
|
function applyReadMode(body, outline, search) {
|
|
14409
14823
|
if (outline === true) {
|
|
@@ -14432,11 +14846,11 @@ var readDocumentTool = {
|
|
|
14432
14846
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14433
14847
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
14434
14848
|
}
|
|
14435
|
-
const ext =
|
|
14849
|
+
const ext = extname13(safePath).toLowerCase();
|
|
14436
14850
|
if (PLAIN_TEXT_EXTS.has(ext)) {
|
|
14437
14851
|
let raw;
|
|
14438
14852
|
try {
|
|
14439
|
-
raw = await
|
|
14853
|
+
raw = await readFile13(safePath, "utf-8");
|
|
14440
14854
|
} catch (e) {
|
|
14441
14855
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14442
14856
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
@@ -14536,8 +14950,8 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
14536
14950
|
".csv",
|
|
14537
14951
|
".log"
|
|
14538
14952
|
]);
|
|
14539
|
-
var readFileSchema =
|
|
14540
|
-
path:
|
|
14953
|
+
var readFileSchema = z14.object({
|
|
14954
|
+
path: z14.string().describe("\uC77D\uC744 \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)")
|
|
14541
14955
|
});
|
|
14542
14956
|
var readFileTool = {
|
|
14543
14957
|
name: "read_file",
|
|
@@ -14561,8 +14975,8 @@ var readFileTool = {
|
|
|
14561
14975
|
if (info.size > MAX_SIZE) {
|
|
14562
14976
|
return `\uC624\uB958: \uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4 (${Math.round(info.size / 1024)}KB). \uCD5C\uB300 256KB\uAE4C\uC9C0 \uC77D\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`;
|
|
14563
14977
|
}
|
|
14564
|
-
const { extname:
|
|
14565
|
-
const ext =
|
|
14978
|
+
const { extname: extname17 } = await import("path");
|
|
14979
|
+
const ext = extname17(safePath).toLowerCase();
|
|
14566
14980
|
if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
|
|
14567
14981
|
return `\uC624\uB958: '${ext}' \uD615\uC2DD\uC740 \uD14D\uC2A4\uD2B8 \uD30C\uC77C\uB85C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBB38\uC11C \uD30C\uC77C\uC774\uB77C\uBA74 read_document \uD234\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`;
|
|
14568
14982
|
}
|
|
@@ -14577,8 +14991,8 @@ var readFileTool = {
|
|
|
14577
14991
|
}
|
|
14578
14992
|
};
|
|
14579
14993
|
var PLAIN_TEXT_EXTS2 = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text"]);
|
|
14580
|
-
var scanPiiSchema =
|
|
14581
|
-
path:
|
|
14994
|
+
var scanPiiSchema = z15.object({
|
|
14995
|
+
path: z15.string().describe("\uAC1C\uC778\uC815\uBCF4\uB97C \uC810\uAC80\uD560 \uBB38\uC11C \uACBD\uB85C")
|
|
14582
14996
|
});
|
|
14583
14997
|
var scanPiiTool = {
|
|
14584
14998
|
name: "scan_pii",
|
|
@@ -14596,11 +15010,11 @@ var scanPiiTool = {
|
|
|
14596
15010
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14597
15011
|
return `\uC624\uB958: \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
14598
15012
|
}
|
|
14599
|
-
const ext =
|
|
15013
|
+
const ext = extname14(safePath).toLowerCase();
|
|
14600
15014
|
let text3;
|
|
14601
15015
|
if (PLAIN_TEXT_EXTS2.has(ext)) {
|
|
14602
15016
|
try {
|
|
14603
|
-
text3 = await
|
|
15017
|
+
text3 = await readFile14(safePath, "utf-8");
|
|
14604
15018
|
} catch (e) {
|
|
14605
15019
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14606
15020
|
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
@@ -14631,9 +15045,9 @@ var scanPiiTool = {
|
|
|
14631
15045
|
}
|
|
14632
15046
|
};
|
|
14633
15047
|
var MAX_PREVIEW_CHARS = 1e4;
|
|
14634
|
-
var writeNewDocumentSchema =
|
|
14635
|
-
path:
|
|
14636
|
-
markdown:
|
|
15048
|
+
var writeNewDocumentSchema = z16.object({
|
|
15049
|
+
path: z16.string().describe("\uC0DD\uC131\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
15050
|
+
markdown: z16.string().describe("\uC0C8 \uBB38\uC11C \uB0B4\uC6A9 (\uB9C8\uD06C\uB2E4\uC6B4 \uD615\uC2DD)")
|
|
14637
15051
|
});
|
|
14638
15052
|
var writeNewDocumentTool = {
|
|
14639
15053
|
name: "write_new_document",
|
|
@@ -14645,7 +15059,7 @@ var writeNewDocumentTool = {
|
|
|
14645
15059
|
ctx
|
|
14646
15060
|
}) => {
|
|
14647
15061
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14648
|
-
const ext =
|
|
15062
|
+
const ext = extname15(safePath).toLowerCase();
|
|
14649
15063
|
try {
|
|
14650
15064
|
await stat6(safePath);
|
|
14651
15065
|
return `\uC624\uB958: \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${input.path}. \uAE30\uC874 \uD30C\uC77C\uC744 \uC218\uC815\uD558\uB824\uBA74 propose_edit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`;
|
|
@@ -14654,13 +15068,7 @@ var writeNewDocumentTool = {
|
|
|
14654
15068
|
const warnings = [];
|
|
14655
15069
|
let stagedData;
|
|
14656
15070
|
if (ext === ".hwpx") {
|
|
14657
|
-
const
|
|
14658
|
-
const hwpxBuffer = await markdownToHwpx3(input.markdown, {
|
|
14659
|
-
warnings: kordocWarnings
|
|
14660
|
-
});
|
|
14661
|
-
if (kordocWarnings.length > 0) {
|
|
14662
|
-
warnings.push(...kordocWarnings.map((w) => `kordoc \uACBD\uACE0: ${w}`));
|
|
14663
|
-
}
|
|
15071
|
+
const hwpxBuffer = await markdownToHwpx(input.markdown);
|
|
14664
15072
|
stagedData = new Uint8Array(hwpxBuffer);
|
|
14665
15073
|
} else if (ext === ".docx") {
|
|
14666
15074
|
warnings.push("DOCX \uC0DD\uC131: \uBCF5\uC7A1\uD55C \uC11C\uC2DD(\uBA38\uB9AC\uAE00/\uAC01\uC8FC/\uC2A4\uD0C0\uC77C)\uC740 \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
|
|
@@ -14695,12 +15103,12 @@ ${preview}`,
|
|
|
14695
15103
|
};
|
|
14696
15104
|
}
|
|
14697
15105
|
};
|
|
14698
|
-
var writeNewSpreadsheetSchema =
|
|
14699
|
-
path:
|
|
14700
|
-
sheets:
|
|
14701
|
-
|
|
14702
|
-
name:
|
|
14703
|
-
rows:
|
|
15106
|
+
var writeNewSpreadsheetSchema = z17.object({
|
|
15107
|
+
path: z17.string().describe("\uC0DD\uC131\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
15108
|
+
sheets: z17.array(
|
|
15109
|
+
z17.object({
|
|
15110
|
+
name: z17.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
|
|
15111
|
+
rows: z17.array(z17.array(z17.string())).describe("\uD589 \uB370\uC774\uD130 \uBC30\uC5F4 (\uAC01 \uD589\uC740 \uC140 \uAC12 \uBC30\uC5F4)")
|
|
14704
15112
|
})
|
|
14705
15113
|
).min(1).describe("\uC0DD\uC131\uD560 \uC2DC\uD2B8 \uBAA9\uB85D")
|
|
14706
15114
|
});
|
|
@@ -14714,7 +15122,7 @@ var writeNewSpreadsheetTool = {
|
|
|
14714
15122
|
ctx
|
|
14715
15123
|
}) => {
|
|
14716
15124
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14717
|
-
const ext =
|
|
15125
|
+
const ext = extname16(safePath).toLowerCase();
|
|
14718
15126
|
if (ext !== ".xlsx") {
|
|
14719
15127
|
return `\uC624\uB958: write_new_spreadsheet\uC740 .xlsx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD655\uC7A5\uC790: ${ext}.`;
|
|
14720
15128
|
}
|
|
@@ -14775,10 +15183,12 @@ function createDocTools(_ctx) {
|
|
|
14775
15183
|
listBackupsTool,
|
|
14776
15184
|
readFileTool,
|
|
14777
15185
|
scanPiiTool,
|
|
15186
|
+
findInDocumentTool,
|
|
14778
15187
|
proposeEditTool,
|
|
14779
15188
|
proposeFormFillTool,
|
|
14780
15189
|
proposeCellEditTool,
|
|
14781
15190
|
proposeFindReplaceTool,
|
|
15191
|
+
proposeRedactPiiTool,
|
|
14782
15192
|
proposeSheetEditTool,
|
|
14783
15193
|
proposeTableStructureTool,
|
|
14784
15194
|
listFormObjectsTool,
|
|
@@ -15602,7 +16012,7 @@ async function runOnboarding() {
|
|
|
15602
16012
|
|
|
15603
16013
|
// src/update.ts
|
|
15604
16014
|
import { spawn } from "child_process";
|
|
15605
|
-
import { mkdir as mkdir4, readFile as
|
|
16015
|
+
import { mkdir as mkdir4, readFile as readFile15, writeFile as writeFile3 } from "fs/promises";
|
|
15606
16016
|
import { dirname as dirname3 } from "path";
|
|
15607
16017
|
function compareSemver(a, b) {
|
|
15608
16018
|
const parse7 = (v) => {
|
|
@@ -15623,7 +16033,7 @@ function compareSemver(a, b) {
|
|
|
15623
16033
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
15624
16034
|
async function readCache(cachePath) {
|
|
15625
16035
|
try {
|
|
15626
|
-
const raw = await
|
|
16036
|
+
const raw = await readFile15(cachePath, "utf-8");
|
|
15627
16037
|
const parsed = JSON.parse(raw);
|
|
15628
16038
|
if (parsed !== null && typeof parsed === "object" && "checkedAt" in parsed && "latest" in parsed && typeof parsed.checkedAt === "string" && typeof parsed.latest === "string") {
|
|
15629
16039
|
return parsed;
|