@kodocagent/cli 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -318,7 +318,7 @@ var require_BufferList = __commonJS({
318
318
  this.head = this.tail = null;
319
319
  this.length = 0;
320
320
  };
321
- BufferList.prototype.join = function join4(s) {
321
+ BufferList.prototype.join = function join5(s) {
322
322
  if (this.length === 0) return "";
323
323
  var p = this.head;
324
324
  var ret = "" + p.data;
@@ -9890,7 +9890,8 @@ var DOCUMENT_RULES_SECTION = `## \uBB38\uC11C \uADDC\uCE59
9890
9890
  4. \`.hwp\` \uD30C\uC77C\uC744 \uD3B8\uC9D1\uD55C \uACB0\uACFC\uB294 \`.hwpx\` \uD615\uC2DD\uC73C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4. \uC774 \uBCC0\uD658 \uC0AC\uC2E4\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBBF8\uB9AC \uC548\uB0B4\uD558\uC138\uC694.
9891
9891
  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.
9892
9892
  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.
9893
- 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.`;
9893
+ 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.
9894
+ 8. \uC0AC\uC6A9\uC790\uAC00 \uC9C1\uC804 \uBCC0\uACBD\uC744 \uB418\uB3CC\uB9AC\uAE38 \uC6D0\uD558\uBA74 \`list_backups\`\uB85C \uBC31\uC5C5\uC744 \uD655\uC778\uD558\uACE0 \`restore_backup\`\uC73C\uB85C \uBCF5\uC6D0\uD558\uC138\uC694. \uBCF5\uC6D0\uB3C4 \uC2B9\uC778\uC744 \uAC70\uCE58\uBA70, \uBCF5\uC6D0 \uC804 \uD604\uC7AC \uC0C1\uD0DC\uAC00 \uC790\uB3D9 \uBC31\uC5C5\uB429\uB2C8\uB2E4.`;
9894
9895
  var LAW_RULES_SECTION = `## \uBC95\uB839 \uADDC\uCE59
9895
9896
 
9896
9897
  1. \uBC95\uB839 \uC778\uC6A9 \uD615\uC2DD: \u300C\uBC95\uB839\uBA85\u300D \uC81CN\uC870 \uC81CN\uD56D \uC81CN\uD638
@@ -10009,6 +10010,13 @@ var AgentSession = class {
10009
10010
  opts;
10010
10011
  messages = [];
10011
10012
  openDocuments = [];
10013
+ /** 열람한 문서 경로를 중복 없이 기록한다 (방어적: 비문자열/오류는 무시). */
10014
+ recordOpenDocument(p) {
10015
+ if (typeof p !== "string" || p.trim() === "") return;
10016
+ if (!this.openDocuments.includes(p)) {
10017
+ this.openDocuments.push(p);
10018
+ }
10019
+ }
10012
10020
  /** approval-required 이벤트를 run() 스트림에 전달하기 위한 큐 */
10013
10021
  pendingApprovalEvents = [];
10014
10022
  /**
@@ -10064,6 +10072,18 @@ var AgentSession = class {
10064
10072
  args: part.input,
10065
10073
  callId: part.toolCallId
10066
10074
  };
10075
+ try {
10076
+ const inp = part.input;
10077
+ if (part.toolName === "read_document") {
10078
+ this.recordOpenDocument(inp.path);
10079
+ } else if (part.toolName === "compare_documents") {
10080
+ this.recordOpenDocument(inp.pathA);
10081
+ this.recordOpenDocument(inp.pathB);
10082
+ } else if (part.toolName === "write_new_document") {
10083
+ this.recordOpenDocument(inp.path);
10084
+ }
10085
+ } catch {
10086
+ }
10067
10087
  break;
10068
10088
  }
10069
10089
  case "tool-result": {
@@ -10806,26 +10826,29 @@ import { realpath } from "fs/promises";
10806
10826
  import { basename, dirname as dirname2, isAbsolute, join as join3, normalize, relative, resolve } from "path";
10807
10827
  import { copyFile, mkdir as mkdir3, readdir as readdir2, readFile as readFile3, rename, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
10808
10828
  import { basename as basename2, dirname as dirname22, extname, join as join22 } from "path";
10829
+ import { createTwoFilesPatch } from "diff";
10830
+ import { readdir as readdir22, readFile as readFile22, stat as stat22 } from "fs/promises";
10831
+ import { basename as basename3, extname as extname2, join as join32 } from "path";
10809
10832
  var import_jszip = __toESM(require_lib3(), 1);
10810
10833
  var import_jszip2 = __toESM(require_lib3(), 1);
10811
10834
  var import_jszip3 = __toESM(require_lib3(), 1);
10812
- import { createTwoFilesPatch } from "diff";
10813
- import { readFile as readFile22 } from "fs/promises";
10814
- import { blocksToMarkdown, compare } from "@clazic/kordoc";
10815
10835
  import { z as z3 } from "zod";
10816
10836
  import { readFile as readFile32 } from "fs/promises";
10817
- import { extname as extname2 } from "path";
10837
+ import { blocksToMarkdown, compare } from "@clazic/kordoc";
10818
10838
  import { z as z22 } from "zod";
10819
- import { readdir as readdir22, stat as stat22 } from "fs/promises";
10820
- import { extname as extname3, join as join32, relative as relative2 } from "path";
10821
- import { z as z32 } from "zod";
10822
10839
  import { readFile as readFile4 } from "fs/promises";
10823
- import { extname as extname4 } from "path";
10840
+ import { extname as extname3 } from "path";
10841
+ import { z as z32 } from "zod";
10842
+ import { readdir as readdir3, stat as stat3 } from "fs/promises";
10843
+ import { extname as extname4, join as join4, relative as relative2 } from "path";
10824
10844
  import { z as z4 } from "zod";
10825
10845
  import { readFile as readFile5 } from "fs/promises";
10826
10846
  import { extname as extname5 } from "path";
10827
- import { compare as compare2, markdownToHwpx, parse } from "@clazic/kordoc";
10828
10847
  import { z as z5 } from "zod";
10848
+ import { readFile as readFile6 } from "fs/promises";
10849
+ import { extname as extname6 } from "path";
10850
+ import { compare as compare2, markdownToHwpx, parse } from "@clazic/kordoc";
10851
+ import { z as z6 } from "zod";
10829
10852
  import {
10830
10853
  Document,
10831
10854
  HeadingLevel,
@@ -10837,37 +10860,37 @@ import {
10837
10860
  TextRun,
10838
10861
  WidthType
10839
10862
  } from "docx";
10840
- import { readFile as readFile6 } from "fs/promises";
10841
- import { extname as extname6 } from "path";
10842
- import { parse as parse2 } from "@clazic/kordoc";
10843
- import { z as z6 } from "zod";
10844
10863
  import { readFile as readFile7 } from "fs/promises";
10845
10864
  import { extname as extname7 } from "path";
10846
- import { extractFormFields, markdownToHwpx as markdownToHwpx2, parse as parse3 } from "@clazic/kordoc";
10847
- var import_jszip4 = __toESM(require_lib3(), 1);
10865
+ import { parse as parse2 } from "@clazic/kordoc";
10848
10866
  import { z as z7 } from "zod";
10849
10867
  import { readFile as readFile8 } from "fs/promises";
10850
10868
  import { extname as extname8 } from "path";
10851
- import ExcelJS from "exceljs";
10869
+ import { extractFormFields, markdownToHwpx as markdownToHwpx2, parse as parse3 } from "@clazic/kordoc";
10870
+ var import_jszip4 = __toESM(require_lib3(), 1);
10852
10871
  import { z as z8 } from "zod";
10853
10872
  import { readFile as readFile9 } from "fs/promises";
10854
10873
  import { extname as extname9 } from "path";
10855
- import { parse as parse4 } from "@clazic/kordoc";
10874
+ import ExcelJS from "exceljs";
10856
10875
  import { z as z9 } from "zod";
10857
- import { readFile as readFile10, stat as stat3 } from "fs/promises";
10876
+ import { readFile as readFile10 } from "fs/promises";
10858
10877
  import { extname as extname10 } from "path";
10859
- import { parse as parse5 } from "@clazic/kordoc";
10878
+ import { parse as parse4 } from "@clazic/kordoc";
10860
10879
  import { z as z10 } from "zod";
10861
- import { readFile as fsReadFile, stat as stat4 } from "fs/promises";
10862
- import { z as z11 } from "zod";
10863
- import { stat as stat5 } from "fs/promises";
10880
+ import { readFile as readFile11, stat as stat4 } from "fs/promises";
10864
10881
  import { extname as extname11 } from "path";
10865
- import { markdownToHwpx as markdownToHwpx3 } from "@clazic/kordoc";
10882
+ import { parse as parse5 } from "@clazic/kordoc";
10883
+ import { z as z11 } from "zod";
10884
+ import { readFile as fsReadFile, stat as stat5 } from "fs/promises";
10866
10885
  import { z as z12 } from "zod";
10867
10886
  import { stat as stat6 } from "fs/promises";
10868
10887
  import { extname as extname12 } from "path";
10869
- import ExcelJS2 from "exceljs";
10888
+ import { markdownToHwpx as markdownToHwpx3 } from "@clazic/kordoc";
10870
10889
  import { z as z13 } from "zod";
10890
+ import { stat as stat7 } from "fs/promises";
10891
+ import { extname as extname13 } from "path";
10892
+ import ExcelJS2 from "exceljs";
10893
+ import { z as z14 } from "zod";
10871
10894
  async function resolveSafePath(cwd, p) {
10872
10895
  const normalizedCwd = normalize(cwd).normalize("NFC");
10873
10896
  const normalizedP = p.normalize("NFC");
@@ -11004,11 +11027,220 @@ function resolveOutputPath(targetPath) {
11004
11027
  }
11005
11028
  return { outputPath: targetPath, willConvertFormat: void 0 };
11006
11029
  }
11030
+ function parseBackupFilename(filename) {
11031
+ const m = filename.match(/^(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)-(.+)$/);
11032
+ if (!m) return null;
11033
+ return { tsToken: m[1], origBasename: m[2] };
11034
+ }
11035
+ function formatTimestamp(tsToken) {
11036
+ const restored = tsToken.replace(
11037
+ /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/,
11038
+ "$1T$2:$3:$4.$5Z"
11039
+ );
11040
+ try {
11041
+ const d = new Date(restored);
11042
+ if (Number.isNaN(d.getTime())) return tsToken;
11043
+ return d.toISOString().replace("T", " ").slice(0, 19);
11044
+ } catch {
11045
+ return tsToken;
11046
+ }
11047
+ }
11048
+ var MAX_BACKUP_LIST = 50;
11049
+ var listBackupsSchema = z3.object({
11050
+ path: z3.string().optional().describe("\uD2B9\uC815 \uD30C\uC77C\uC758 \uBC31\uC5C5\uB9CC \uBCF4\uB824\uBA74 \uADF8 \uD30C\uC77C \uACBD\uB85C (\uBBF8\uC9C0\uC815 \uC2DC \uC804\uCCB4 \uBC31\uC5C5)")
11051
+ });
11052
+ var listBackupsTool = {
11053
+ name: "list_backups",
11054
+ description: "\uBC31\uC5C5 \uB514\uB809\uD130\uB9AC\uC758 \uBC31\uC5C5 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. path\uB97C \uC9C0\uC815\uD558\uBA74 \uD574\uB2F9 \uD30C\uC77C\uC758 \uBC31\uC5C5\uB9CC, \uBBF8\uC9C0\uC815 \uC2DC \uC804\uCCB4 \uBC31\uC5C5\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4. \uCD5C\uB300 50\uAC74, \uCD5C\uC2E0\uC21C \uC815\uB82C.",
11055
+ inputSchema: listBackupsSchema,
11056
+ requiresApproval: false,
11057
+ execute: async ({
11058
+ input
11059
+ }) => {
11060
+ const backupsDir = KODOC_PATHS.backups;
11061
+ let allEntries;
11062
+ try {
11063
+ allEntries = await readdir22(backupsDir);
11064
+ } catch {
11065
+ return "\uBC31\uC5C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
11066
+ }
11067
+ if (allEntries.length === 0) {
11068
+ return "\uBC31\uC5C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
11069
+ }
11070
+ const parsed = [];
11071
+ for (const filename of allEntries) {
11072
+ const info = parseBackupFilename(filename);
11073
+ if (!info) continue;
11074
+ const fullPath = join32(backupsDir, filename);
11075
+ let mtimeMs = 0;
11076
+ try {
11077
+ const s = await stat22(fullPath);
11078
+ mtimeMs = s.mtimeMs;
11079
+ } catch {
11080
+ mtimeMs = 0;
11081
+ }
11082
+ parsed.push({ filename, fullPath, ...info, mtimeMs });
11083
+ }
11084
+ let filtered = parsed;
11085
+ if (input.path) {
11086
+ const targetBase = basename3(input.path);
11087
+ filtered = parsed.filter((e) => e.origBasename === targetBase);
11088
+ }
11089
+ if (filtered.length === 0) {
11090
+ if (input.path) {
11091
+ return `\uD574\uB2F9 \uD30C\uC77C\uC758 \uBC31\uC5C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${basename3(input.path)}`;
11092
+ }
11093
+ return "\uBC31\uC5C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
11094
+ }
11095
+ filtered.sort((a, b) => {
11096
+ if (b.mtimeMs !== a.mtimeMs) return b.mtimeMs - a.mtimeMs;
11097
+ return b.tsToken.localeCompare(a.tsToken);
11098
+ });
11099
+ const total = filtered.length;
11100
+ const truncated = filtered.length > MAX_BACKUP_LIST;
11101
+ const display = filtered.slice(0, MAX_BACKUP_LIST);
11102
+ const lines = display.map(
11103
+ (e, i) => `${i + 1}. ${e.origBasename} [${formatTimestamp(e.tsToken)}] ${e.fullPath}`
11104
+ );
11105
+ const notice = truncated ? `
11106
+ (\uCD1D ${total}\uAC74 \uC911 \uCD5C\uC2E0 ${MAX_BACKUP_LIST}\uAC74\uB9CC \uD45C\uC2DC\uB429\uB2C8\uB2E4.)` : "";
11107
+ return lines.join("\n") + notice;
11108
+ }
11109
+ };
11110
+ var restoreBackupSchema = z3.object({
11111
+ path: z3.string().describe("\uBCF5\uC6D0\uD560 \uB300\uC0C1 \uD30C\uC77C \uACBD\uB85C"),
11112
+ backup: z3.string().optional().describe("\uBCF5\uC6D0\uD560 \uD2B9\uC815 \uBC31\uC5C5 \uD30C\uC77C\uBA85 (list_backups \uACB0\uACFC\uC758 \uD30C\uC77C\uBA85; \uBBF8\uC9C0\uC815 \uC2DC \uAC00\uC7A5 \uCD5C\uADFC \uBC31\uC5C5)"),
11113
+ summary: z3.string().optional().describe("\uBCF5\uC6D0 \uC0AC\uC720/\uC694\uC57D")
11114
+ });
11115
+ var restoreBackupTool = {
11116
+ name: "restore_backup",
11117
+ description: "\uBC31\uC5C5 \uD30C\uC77C\uB85C \uB300\uC0C1 \uD30C\uC77C\uC744 \uBCF5\uC6D0\uD569\uB2C8\uB2E4. backup\uC744 \uBBF8\uC9C0\uC815 \uC2DC \uAC00\uC7A5 \uCD5C\uADFC \uBC31\uC5C5\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4. \uBCF5\uC6D0 \uC804 \uD604\uC7AC \uD30C\uC77C\uB3C4 \uC790\uB3D9 \uBC31\uC5C5\uB429\uB2C8\uB2E4(\uBCF5\uC6D0\uB3C4 \uB418\uB3CC\uB9B4 \uC218 \uC788\uC74C). \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.",
11118
+ inputSchema: restoreBackupSchema,
11119
+ requiresApproval: true,
11120
+ propose: async ({
11121
+ input,
11122
+ ctx
11123
+ }) => {
11124
+ let safePath;
11125
+ try {
11126
+ safePath = await resolveSafePath(ctx.cwd, input.path);
11127
+ } catch (e) {
11128
+ return `\uACBD\uB85C \uC624\uB958: ${e instanceof Error ? e.message : String(e)}`;
11129
+ }
11130
+ const targetBase = basename3(safePath);
11131
+ const backupsDir = KODOC_PATHS.backups;
11132
+ let allEntries;
11133
+ try {
11134
+ allEntries = await readdir22(backupsDir);
11135
+ } catch {
11136
+ return `\uBC31\uC5C5\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${targetBase}. list_backups\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBC31\uC5C5\uC744 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`;
11137
+ }
11138
+ const candidates = [];
11139
+ for (const filename of allEntries) {
11140
+ const info = parseBackupFilename(filename);
11141
+ if (!info) continue;
11142
+ if (info.origBasename !== targetBase) continue;
11143
+ const fullPath = join32(backupsDir, filename);
11144
+ let mtimeMs = 0;
11145
+ try {
11146
+ const s = await stat22(fullPath);
11147
+ mtimeMs = s.mtimeMs;
11148
+ } catch {
11149
+ mtimeMs = 0;
11150
+ }
11151
+ candidates.push({ filename, fullPath, tsToken: info.tsToken, mtimeMs });
11152
+ }
11153
+ if (candidates.length === 0) {
11154
+ return `\uBC31\uC5C5\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${targetBase}. list_backups\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBC31\uC5C5\uC744 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`;
11155
+ }
11156
+ let chosen;
11157
+ if (input.backup) {
11158
+ const found = candidates.find(
11159
+ (c) => c.filename === input.backup || c.fullPath.endsWith(input.backup)
11160
+ );
11161
+ if (!found) {
11162
+ return `\uC9C0\uC815\uD55C \uBC31\uC5C5\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.backup}. list_backups\uB85C \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBC31\uC5C5\uC744 \uBA3C\uC800 \uD655\uC778\uD558\uC138\uC694.`;
11163
+ }
11164
+ chosen = found;
11165
+ } else {
11166
+ candidates.sort(
11167
+ (a, b) => b.mtimeMs !== a.mtimeMs ? b.mtimeMs - a.mtimeMs : b.tsToken.localeCompare(a.tsToken)
11168
+ );
11169
+ chosen = candidates[0];
11170
+ }
11171
+ let backupBytes;
11172
+ try {
11173
+ backupBytes = await readFile22(chosen.fullPath);
11174
+ } catch {
11175
+ return `\uBC31\uC5C5 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${chosen.fullPath}`;
11176
+ }
11177
+ const stagedPath = await stageFile(ctx.sessionId, targetBase, backupBytes);
11178
+ const ext = extname2(targetBase).toLowerCase();
11179
+ const isText = ext === ".md" || ext === ".txt";
11180
+ let diff;
11181
+ if (isText) {
11182
+ let currentText = "";
11183
+ try {
11184
+ currentText = await readFile22(safePath, "utf-8");
11185
+ } catch {
11186
+ currentText = "";
11187
+ }
11188
+ const backupText = backupBytes.toString("utf-8");
11189
+ diff = markdownDiff(currentText, backupText, targetBase);
11190
+ } else {
11191
+ let currentSize = "\uD30C\uC77C \uC5C6\uC74C";
11192
+ try {
11193
+ const s = await stat22(safePath);
11194
+ currentSize = `${s.size} bytes`;
11195
+ } catch {
11196
+ currentSize = "\uD30C\uC77C \uC5C6\uC74C";
11197
+ }
11198
+ const backupSize = `${backupBytes.length} bytes`;
11199
+ diff = [
11200
+ `\uBCF5\uC6D0 \uB300\uC0C1: ${safePath}`,
11201
+ `\uD604\uC7AC \uD30C\uC77C: ${currentSize}`,
11202
+ `\uBC31\uC5C5 \uD30C\uC77C: ${chosen.fullPath}`,
11203
+ `\uBC31\uC5C5 \uC2DC\uAC01: ${formatTimestamp(chosen.tsToken)}`,
11204
+ `\uBC31\uC5C5 \uD06C\uAE30: ${backupSize}`,
11205
+ `\u2192 \uD604\uC7AC \uD30C\uC77C\uC744 \uC704 \uBC31\uC5C5\uC73C\uB85C \uB418\uB3CC\uB9BD\uB2C8\uB2E4.`
11206
+ ].join("\n");
11207
+ }
11208
+ const warnings = [];
11209
+ const autoSelected = !input.backup && candidates.length > 1;
11210
+ if (autoSelected) {
11211
+ warnings.push(
11212
+ `\uBC31\uC5C5\uC744 \uC9C0\uC815\uD558\uC9C0 \uC54A\uC544 \uAC00\uC7A5 \uCD5C\uADFC \uBC31\uC5C5(${formatTimestamp(chosen.tsToken)})\uC744 \uC790\uB3D9\uC73C\uB85C \uC120\uD0DD\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uB978 \uBC31\uC5C5\uC744 \uC6D0\uD558\uBA74 list_backups\uB85C \uD655\uC778 \uD6C4 backup \uD30C\uB77C\uBBF8\uD130\uB97C \uC9C0\uC815\uD558\uC138\uC694.`
11213
+ );
11214
+ }
11215
+ warnings.push(
11216
+ "\uBCF5\uC6D0\uC744 \uC2E4\uD589\uD558\uBA74 \uD604\uC7AC \uD30C\uC77C\uB3C4 \uBC31\uC5C5\uB41C \uB4A4 \uB36E\uC5B4\uC4F0\uC5EC\uC9D1\uB2C8\uB2E4(\uBCF5\uC6D0 \uC790\uCCB4\uB3C4 \uB418\uB3CC\uB9B4 \uC218 \uC788\uC74C)."
11217
+ );
11218
+ const summary = input.summary ?? `\uBC31\uC5C5\uC73C\uB85C \uB418\uB3CC\uB9AC\uAE30: ${targetBase}`;
11219
+ const chosenBackupPath = chosen.fullPath;
11220
+ return {
11221
+ proposal: {
11222
+ id: crypto.randomUUID(),
11223
+ kind: "restore",
11224
+ targetPath: safePath,
11225
+ stagedPath,
11226
+ summary,
11227
+ diff,
11228
+ warnings
11229
+ },
11230
+ commit: async () => {
11231
+ const safetyBackup = await backupFile(safePath);
11232
+ await commitStaged(stagedPath, safePath);
11233
+ const safetyNote = safetyBackup ? ` (\uBCF5\uC6D0 \uC804 \uD604\uC7AC \uC0C1\uD0DC \uBC31\uC5C5: ${safetyBackup})` : "";
11234
+ return `\uBCF5\uC6D0 \uC644\uB8CC: ${safePath} \u2190 ${chosenBackupPath}${safetyNote}`;
11235
+ }
11236
+ };
11237
+ }
11238
+ };
11007
11239
  var MAX_MARKDOWN_LENGTH = 8e4;
11008
11240
  var MAX_BLOCK_TEXT_LENGTH = 200;
11009
- var compareDocumentsSchema = z3.object({
11010
- pathA: z3.string().describe("\uBE44\uAD50\uD560 \uCCAB \uBC88\uC9F8 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
11011
- pathB: z3.string().describe("\uBE44\uAD50\uD560 \uB450 \uBC88\uC9F8 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)")
11241
+ var compareDocumentsSchema = z22.object({
11242
+ pathA: z22.string().describe("\uBE44\uAD50\uD560 \uCCAB \uBC88\uC9F8 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
11243
+ pathB: z22.string().describe("\uBE44\uAD50\uD560 \uB450 \uBC88\uC9F8 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)")
11012
11244
  });
11013
11245
  function bufferToArrayBuffer(buf) {
11014
11246
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
@@ -11046,13 +11278,13 @@ var compareDocumentsTool = {
11046
11278
  let bufA;
11047
11279
  let bufB;
11048
11280
  try {
11049
- bufA = await readFile22(safePathA);
11281
+ bufA = await readFile32(safePathA);
11050
11282
  } catch (e) {
11051
11283
  const msg = e instanceof Error ? e.message : String(e);
11052
11284
  return `\uC624\uB958: \uCCAB \uBC88\uC9F8 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${input.pathA}): ${msg}`;
11053
11285
  }
11054
11286
  try {
11055
- bufB = await readFile22(safePathB);
11287
+ bufB = await readFile32(safePathB);
11056
11288
  } catch (e) {
11057
11289
  const msg = e instanceof Error ? e.message : String(e);
11058
11290
  return `\uC624\uB958: \uB450 \uBC88\uC9F8 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${input.pathB}): ${msg}`;
@@ -11500,14 +11732,14 @@ function validateHwpxBuffer(ext, buffer) {
11500
11732
  }
11501
11733
  return null;
11502
11734
  }
11503
- var listFormObjectsSchema = z22.object({
11504
- path: z22.string().describe("\uC77D\uC744 .hwpx \uD30C\uC77C \uACBD\uB85C")
11735
+ var listFormObjectsSchema = z32.object({
11736
+ path: z32.string().describe("\uC77D\uC744 .hwpx \uD30C\uC77C \uACBD\uB85C")
11505
11737
  });
11506
- var formEditSetSchema = z22.object({
11507
- caption: z22.string().optional().describe("PushButton \uCEA1\uC158 \uD14D\uC2A4\uD2B8"),
11508
- checked: z22.boolean().optional().describe("CheckBox/RadioButton \uCCB4\uD06C \uC0C1\uD0DC (true=CHECKED)"),
11509
- selected: z22.string().optional().describe("ComboBox \uC120\uD0DD \uAC12 (listItem \uC911 \uD558\uB098\uC5EC\uC57C \uD568)"),
11510
- text: z22.string().optional().describe("Edit \uD14D\uC2A4\uD2B8 \uB0B4\uC6A9")
11738
+ var formEditSetSchema = z32.object({
11739
+ caption: z32.string().optional().describe("PushButton \uCEA1\uC158 \uD14D\uC2A4\uD2B8"),
11740
+ checked: z32.boolean().optional().describe("CheckBox/RadioButton \uCCB4\uD06C \uC0C1\uD0DC (true=CHECKED)"),
11741
+ selected: z32.string().optional().describe("ComboBox \uC120\uD0DD \uAC12 (listItem \uC911 \uD558\uB098\uC5EC\uC57C \uD568)"),
11742
+ text: z32.string().optional().describe("Edit \uD14D\uC2A4\uD2B8 \uB0B4\uC6A9")
11511
11743
  }).refine(
11512
11744
  (v) => {
11513
11745
  const keys = ["caption", "checked", "selected", "text"].filter(
@@ -11517,24 +11749,24 @@ var formEditSetSchema = z22.object({
11517
11749
  },
11518
11750
  { message: "set \uD544\uB4DC\uB294 caption/checked/selected/text \uC911 \uC815\uD655\uD788 \uD558\uB098\uB9CC \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4." }
11519
11751
  );
11520
- var formEditExpectedSchema = z22.object({
11521
- caption: z22.string().optional(),
11522
- checked: z22.boolean().optional(),
11523
- selected: z22.string().optional(),
11524
- text: z22.string().optional()
11752
+ var formEditExpectedSchema = z32.object({
11753
+ caption: z32.string().optional(),
11754
+ checked: z32.boolean().optional(),
11755
+ selected: z32.string().optional(),
11756
+ text: z32.string().optional()
11525
11757
  }).optional();
11526
- var formEditItemSchema = z22.object({
11527
- name: z22.string().describe("\uC591\uC2DD \uAC1C\uCCB4\uC758 name \uC18D\uC131 \uAC12"),
11528
- index: z22.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"),
11758
+ var formEditItemSchema = z32.object({
11759
+ name: z32.string().describe("\uC591\uC2DD \uAC1C\uCCB4\uC758 name \uC18D\uC131 \uAC12"),
11760
+ 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"),
11529
11761
  set: formEditSetSchema.describe("\uBCC0\uACBD\uD560 \uAC12 (caption/checked/selected/text \uC911 \uD558\uB098)"),
11530
11762
  expected: formEditExpectedSchema.describe(
11531
11763
  "\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."
11532
11764
  )
11533
11765
  });
11534
- var proposeFormObjectSchema = z22.object({
11535
- path: z22.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C"),
11536
- edits: z22.array(formEditItemSchema).min(1).describe("\uC591\uC2DD \uAC1C\uCCB4 \uD3B8\uC9D1 \uBAA9\uB85D"),
11537
- summary: z22.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
11766
+ var proposeFormObjectSchema = z32.object({
11767
+ path: z32.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C"),
11768
+ edits: z32.array(formEditItemSchema).min(1).describe("\uC591\uC2DD \uAC1C\uCCB4 \uD3B8\uC9D1 \uBAA9\uB85D"),
11769
+ summary: z32.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
11538
11770
  });
11539
11771
  var listFormObjectsTool = {
11540
11772
  name: "list_form_objects",
@@ -11546,10 +11778,10 @@ var listFormObjectsTool = {
11546
11778
  ctx
11547
11779
  }) => {
11548
11780
  const safePath = await resolveSafePath(ctx.cwd, input.path);
11549
- const ext = extname2(safePath).toLowerCase();
11781
+ const ext = extname3(safePath).toLowerCase();
11550
11782
  let buffer;
11551
11783
  try {
11552
- buffer = await readFile32(safePath);
11784
+ buffer = await readFile4(safePath);
11553
11785
  } catch {
11554
11786
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
11555
11787
  }
@@ -11601,10 +11833,10 @@ var proposeFormObjectTool = {
11601
11833
  ctx
11602
11834
  }) => {
11603
11835
  const safePath = await resolveSafePath(ctx.cwd, input.path);
11604
- const ext = extname2(safePath).toLowerCase();
11836
+ const ext = extname3(safePath).toLowerCase();
11605
11837
  let originalBuffer;
11606
11838
  try {
11607
- originalBuffer = await readFile32(safePath);
11839
+ originalBuffer = await readFile4(safePath);
11608
11840
  } catch {
11609
11841
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
11610
11842
  }
@@ -11791,14 +12023,14 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
11791
12023
  ]);
11792
12024
  var MAX_DEPTH = 4;
11793
12025
  var MAX_FILES = 500;
11794
- var listFilesSchema = z32.object({
11795
- dir: z32.string().optional().describe("\uBAA9\uB85D\uC744 \uC870\uD68C\uD560 \uB514\uB809\uD130\uB9AC (\uBBF8\uC9C0\uC815 \uC2DC cwd \uC804\uCCB4)")
12026
+ var listFilesSchema = z4.object({
12027
+ dir: z4.string().optional().describe("\uBAA9\uB85D\uC744 \uC870\uD68C\uD560 \uB514\uB809\uD130\uB9AC (\uBBF8\uC9C0\uC815 \uC2DC cwd \uC804\uCCB4)")
11796
12028
  });
11797
12029
  async function collectFiles(dir, cwd, depth, entries) {
11798
12030
  if (depth > MAX_DEPTH || entries.length >= MAX_FILES) return;
11799
12031
  let items;
11800
12032
  try {
11801
- items = await readdir22(dir);
12033
+ items = await readdir3(dir);
11802
12034
  } catch {
11803
12035
  return;
11804
12036
  }
@@ -11806,15 +12038,15 @@ async function collectFiles(dir, cwd, depth, entries) {
11806
12038
  if (entries.length >= MAX_FILES) break;
11807
12039
  if (item.startsWith(".")) continue;
11808
12040
  if (SKIP_DIRS.has(item)) continue;
11809
- const fullPath = join32(dir, item);
12041
+ const fullPath = join4(dir, item);
11810
12042
  let info;
11811
12043
  try {
11812
- info = await stat22(fullPath);
12044
+ info = await stat3(fullPath);
11813
12045
  } catch {
11814
12046
  continue;
11815
12047
  }
11816
12048
  const relPath = relative2(cwd, fullPath);
11817
- const ext = extname3(item).toLowerCase();
12049
+ const ext = extname4(item).toLowerCase();
11818
12050
  const isDoc = DOC_EXTENSIONS.has(ext);
11819
12051
  if (info.isDirectory()) {
11820
12052
  entries.push({ path: relPath + "/", isDir: true, isDoc: false });
@@ -11852,29 +12084,29 @@ var listFilesTool = {
11852
12084
  return lines.join("\n") + truncateNotice;
11853
12085
  }
11854
12086
  };
11855
- var cellEditItemSchema = z4.object({
11856
- tableIndex: z4.number().int().nonnegative().optional().describe(
12087
+ var cellEditItemSchema = z5.object({
12088
+ tableIndex: z5.number().int().nonnegative().optional().describe(
11857
12089
  "\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)."
11858
12090
  ),
11859
- row: z4.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 rowAddr (0-based)"),
11860
- col: z4.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 colAddr (0-based)"),
11861
- label: z4.string().optional().describe(
12091
+ row: z5.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 rowAddr (0-based)"),
12092
+ col: z5.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 colAddr (0-based)"),
12093
+ label: z5.string().optional().describe(
11862
12094
  "\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."
11863
12095
  ),
11864
- direction: z4.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."),
11865
- newText: z4.string().describe("\uC140\uC5D0 \uC4F8 \uC0C8 \uD14D\uC2A4\uD2B8"),
11866
- expectedText: z4.string().optional().describe(
12096
+ 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."),
12097
+ newText: z5.string().describe("\uC140\uC5D0 \uC4F8 \uC0C8 \uD14D\uC2A4\uD2B8"),
12098
+ expectedText: z5.string().optional().describe(
11867
12099
  "\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."
11868
12100
  )
11869
12101
  }).describe(
11870
12102
  "\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."
11871
12103
  );
11872
- var proposeCellEditSchema = z4.object({
11873
- path: z4.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
11874
- edits: z4.array(cellEditItemSchema).min(1).describe(
12104
+ var proposeCellEditSchema = z5.object({
12105
+ 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)"),
12106
+ edits: z5.array(cellEditItemSchema).min(1).describe(
11875
12107
  "\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"
11876
12108
  ),
11877
- summary: z4.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12109
+ summary: z5.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
11878
12110
  });
11879
12111
  function tokenizeHwpxXml(xml) {
11880
12112
  const tokens = [];
@@ -12209,7 +12441,7 @@ var proposeCellEditTool = {
12209
12441
  ctx
12210
12442
  }) => {
12211
12443
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12212
- const ext = extname4(safePath).toLowerCase();
12444
+ const ext = extname5(safePath).toLowerCase();
12213
12445
  if (ext === ".hwp") {
12214
12446
  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.";
12215
12447
  }
@@ -12218,7 +12450,7 @@ var proposeCellEditTool = {
12218
12450
  }
12219
12451
  let originalBuffer;
12220
12452
  try {
12221
- originalBuffer = await readFile4(safePath);
12453
+ originalBuffer = await readFile5(safePath);
12222
12454
  } catch {
12223
12455
  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.`;
12224
12456
  }
@@ -12547,10 +12779,10 @@ async function markdownToDocx(markdown) {
12547
12779
  });
12548
12780
  return Packer.toBuffer(doc);
12549
12781
  }
12550
- var proposeEditSchema = z5.object({
12551
- path: z5.string().describe("\uC218\uC815\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12552
- newMarkdown: z5.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"),
12553
- summary: z5.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12782
+ var proposeEditSchema = z6.object({
12783
+ path: z6.string().describe("\uC218\uC815\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12784
+ newMarkdown: z6.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"),
12785
+ summary: z6.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12554
12786
  });
12555
12787
  var proposeEditTool = {
12556
12788
  name: "propose_edit",
@@ -12562,10 +12794,10 @@ var proposeEditTool = {
12562
12794
  ctx
12563
12795
  }) => {
12564
12796
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12565
- const ext = extname5(safePath).toLowerCase();
12797
+ const ext = extname6(safePath).toLowerCase();
12566
12798
  let originalBuffer;
12567
12799
  try {
12568
- originalBuffer = await readFile5(safePath);
12800
+ originalBuffer = await readFile6(safePath);
12569
12801
  } catch {
12570
12802
  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.`;
12571
12803
  }
@@ -12636,17 +12868,48 @@ ${diff}`;
12636
12868
  };
12637
12869
  }
12638
12870
  };
12639
- var proposeFindReplaceSchema = z6.object({
12640
- path: z6.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12641
- find: z6.string().min(1).describe("\uCC3E\uC744 \uD14D\uC2A4\uD2B8"),
12642
- replace: z6.string().describe("\uBC14\uAFC0 \uD14D\uC2A4\uD2B8"),
12643
- caseSensitive: z6.boolean().optional().default(false).describe("\uB300\uC18C\uBB38\uC790 \uAD6C\uBD84 (\uAE30\uBCF8\uAC12: false)"),
12644
- all: z6.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"),
12645
- summary: z6.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12871
+ var proposeFindReplaceSchema = z7.object({
12872
+ path: z7.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12873
+ find: z7.string().min(1).describe("\uCC3E\uC744 \uD14D\uC2A4\uD2B8"),
12874
+ replace: z7.string().describe("\uBC14\uAFC0 \uD14D\uC2A4\uD2B8"),
12875
+ caseSensitive: z7.boolean().optional().default(false).describe("\uB300\uC18C\uBB38\uC790 \uAD6C\uBD84 (\uAE30\uBCF8\uAC12: false)"),
12876
+ all: z7.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"),
12877
+ summary: z7.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12646
12878
  });
12879
+ var MAX_DIFF_SAMPLES = 20;
12647
12880
  function escapeXml3(text3) {
12648
12881
  return text3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12649
12882
  }
12883
+ function unescapeXml(text3) {
12884
+ return text3.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
12885
+ }
12886
+ function makeChangeSnippet(before, after, ctx = 24) {
12887
+ let p = 0;
12888
+ while (p < before.length && p < after.length && before[p] === after[p]) p++;
12889
+ const maxSuffix = Math.min(before.length - p, after.length - p);
12890
+ let s = 0;
12891
+ while (s < maxSuffix && before[before.length - 1 - s] === after[after.length - 1 - s]) s++;
12892
+ const slice = (str) => {
12893
+ const start = Math.max(0, p - ctx);
12894
+ const end = Math.min(str.length, str.length - s + ctx);
12895
+ return (start > 0 ? "\u2026" : "") + str.slice(start, end) + (end < str.length ? "\u2026" : "");
12896
+ };
12897
+ return { before: slice(before), after: slice(after) };
12898
+ }
12899
+ function collectChangedSnippets(beforeXml, afterXml, maxSamples) {
12900
+ const re = /<hp:t>([\s\S]*?)<\/hp:t>/g;
12901
+ const beforeNodes = [...beforeXml.matchAll(re)].map((m) => m[1] ?? "");
12902
+ const afterNodes = [...afterXml.matchAll(re)].map((m) => m[1] ?? "");
12903
+ const out = [];
12904
+ const n = Math.min(beforeNodes.length, afterNodes.length);
12905
+ for (let i = 0; i < n && out.length < maxSamples; i++) {
12906
+ if (beforeNodes[i] !== afterNodes[i]) {
12907
+ const snip = makeChangeSnippet(unescapeXml(beforeNodes[i]), unescapeXml(afterNodes[i]));
12908
+ out.push(snip);
12909
+ }
12910
+ }
12911
+ return out;
12912
+ }
12650
12913
  function replaceInSectionXml(xml, find, replace, caseSensitive, replaceAll, alreadyReplaced) {
12651
12914
  if (!replaceAll && alreadyReplaced > 0) {
12652
12915
  return { xml, count: 0 };
@@ -12754,7 +13017,19 @@ async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive,
12754
13017
  }
12755
13018
  }
12756
13019
  if (totalCount === 0) {
12757
- return { buffer: hwpxBuffer, count: 0 };
13020
+ return { buffer: hwpxBuffer, count: 0, samples: [] };
13021
+ }
13022
+ const samples = [];
13023
+ for (let si = 0; si < sectionFiles.length && samples.length < MAX_DIFF_SAMPLES; si++) {
13024
+ const remaining = MAX_DIFF_SAMPLES - samples.length;
13025
+ const snippets = collectChangedSnippets(
13026
+ sectionXmls[si] ?? "",
13027
+ newSectionXmls[si] ?? "",
13028
+ remaining
13029
+ );
13030
+ for (const snip of snippets) {
13031
+ samples.push(snip);
13032
+ }
12758
13033
  }
12759
13034
  const out = new import_jszip3.default();
12760
13035
  const mimetypeEntry = zip.file("mimetype");
@@ -12773,7 +13048,8 @@ async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive,
12773
13048
  const buf = await out.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
12774
13049
  return {
12775
13050
  buffer: new Uint8Array(buf),
12776
- count: totalCount
13051
+ count: totalCount,
13052
+ samples
12777
13053
  };
12778
13054
  }
12779
13055
  var proposeFindReplaceTool = {
@@ -12786,7 +13062,7 @@ var proposeFindReplaceTool = {
12786
13062
  ctx
12787
13063
  }) => {
12788
13064
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12789
- const ext = extname6(safePath).toLowerCase();
13065
+ const ext = extname7(safePath).toLowerCase();
12790
13066
  if (ext === ".hwp") {
12791
13067
  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.";
12792
13068
  }
@@ -12795,7 +13071,7 @@ var proposeFindReplaceTool = {
12795
13071
  }
12796
13072
  let originalBuf;
12797
13073
  try {
12798
- originalBuf = await readFile6(safePath);
13074
+ originalBuf = await readFile7(safePath);
12799
13075
  } catch {
12800
13076
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12801
13077
  }
@@ -12809,6 +13085,7 @@ var proposeFindReplaceTool = {
12809
13085
  );
12810
13086
  let newBytes;
12811
13087
  let replacedCount;
13088
+ let diffSamples;
12812
13089
  try {
12813
13090
  const result = await applyFindReplaceToHwpx(
12814
13091
  originalBytes,
@@ -12819,6 +13096,7 @@ var proposeFindReplaceTool = {
12819
13096
  );
12820
13097
  newBytes = result.buffer;
12821
13098
  replacedCount = result.count;
13099
+ diffSamples = result.samples;
12822
13100
  } catch (e) {
12823
13101
  return `\uC624\uB958: \uCE58\uD658 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. ${String(e)}`;
12824
13102
  }
@@ -12847,7 +13125,23 @@ var proposeFindReplaceTool = {
12847
13125
  }
12848
13126
  const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
12849
13127
  const allLabel = input.all ?? true ? `${replacedCount}\uACF3` : "\uCCAB \uBC88\uC9F8 1\uACF3";
12850
- const diff = `\uCC3E\uAE30: "${input.find}" \u2192 \uBC14\uAFB8\uAE30: "${input.replace}" (${allLabel} \uAD50\uCCB4\uB428)`;
13128
+ let diff;
13129
+ if (diffSamples.length === 0) {
13130
+ diff = `\uCC3E\uAE30: "${input.find}" \u2192 \uBC14\uAFB8\uAE30: "${input.replace}" (${allLabel} \uAD50\uCCB4\uB428)`;
13131
+ } else {
13132
+ const lines = [`${replacedCount}\uACF3 \uAD50\uCCB4: "${input.find}" \u2192 "${input.replace}"`];
13133
+ for (let i = 0; i < diffSamples.length; i++) {
13134
+ const sample = diffSamples[i];
13135
+ lines.push(` ${i + 1}. - ${sample.before}`);
13136
+ lines.push(` + ${sample.after}`);
13137
+ }
13138
+ if (replacedCount > diffSamples.length) {
13139
+ lines.push(
13140
+ ` \u2026 \uC678 ${replacedCount - diffSamples.length}\uACF3 (\uBBF8\uB9AC\uBCF4\uAE30\uB294 \uCD5C\uB300 ${MAX_DIFF_SAMPLES}\uACF3)`
13141
+ );
13142
+ }
13143
+ diff = lines.join("\n");
13144
+ }
12851
13145
  const stagedPath = await stageFile(ctx.sessionId, outputPath, newBytes);
12852
13146
  const proposalId = crypto.randomUUID();
12853
13147
  return {
@@ -12870,10 +13164,10 @@ var proposeFindReplaceTool = {
12870
13164
  };
12871
13165
  }
12872
13166
  };
12873
- var proposeFormFillSchema = z7.object({
12874
- path: z7.string().describe("\uC591\uC2DD \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12875
- fields: z7.record(z7.string(), z7.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"),
12876
- summary: z7.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
13167
+ var proposeFormFillSchema = z8.object({
13168
+ path: z8.string().describe("\uC591\uC2DD \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
13169
+ fields: z8.record(z8.string(), z8.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"),
13170
+ summary: z8.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12877
13171
  });
12878
13172
  var proposeFormFillTool = {
12879
13173
  name: "propose_form_fill",
@@ -12885,13 +13179,13 @@ var proposeFormFillTool = {
12885
13179
  ctx
12886
13180
  }) => {
12887
13181
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12888
- const ext = extname7(safePath).toLowerCase();
13182
+ const ext = extname8(safePath).toLowerCase();
12889
13183
  if (ext !== ".hwpx" && ext !== ".hwp") {
12890
13184
  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.`;
12891
13185
  }
12892
13186
  let originalBuffer;
12893
13187
  try {
12894
- originalBuffer = await readFile7(safePath);
13188
+ originalBuffer = await readFile8(safePath);
12895
13189
  } catch {
12896
13190
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12897
13191
  }
@@ -12959,16 +13253,16 @@ var proposeFormFillTool = {
12959
13253
  };
12960
13254
  }
12961
13255
  };
12962
- var proposeSheetEditSchema = z8.object({
12963
- path: z8.string().describe("\uC218\uC815\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12964
- updates: z8.array(
12965
- z8.object({
12966
- sheet: z8.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
12967
- cell: z8.string().describe("\uC140 \uC8FC\uC18C (\uC608: A1, B3)"),
12968
- value: z8.union([z8.string(), z8.number()]).describe("\uC0C8 \uAC12")
13256
+ var proposeSheetEditSchema = z9.object({
13257
+ path: z9.string().describe("\uC218\uC815\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
13258
+ updates: z9.array(
13259
+ z9.object({
13260
+ sheet: z9.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
13261
+ cell: z9.string().describe("\uC140 \uC8FC\uC18C (\uC608: A1, B3)"),
13262
+ value: z9.union([z9.string(), z9.number()]).describe("\uC0C8 \uAC12")
12969
13263
  })
12970
13264
  ).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"),
12971
- summary: z8.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
13265
+ summary: z9.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
12972
13266
  });
12973
13267
  var proposeSheetEditTool = {
12974
13268
  name: "propose_sheet_edit",
@@ -12980,13 +13274,13 @@ var proposeSheetEditTool = {
12980
13274
  ctx
12981
13275
  }) => {
12982
13276
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12983
- const ext = extname8(safePath).toLowerCase();
13277
+ const ext = extname9(safePath).toLowerCase();
12984
13278
  if (ext !== ".xlsx" && ext !== ".xls") {
12985
13279
  return `\uC624\uB958: propose_sheet_edit\uC740 .xlsx/.xls \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}.`;
12986
13280
  }
12987
13281
  let originalBuffer;
12988
13282
  try {
12989
- originalBuffer = await readFile8(safePath);
13283
+ originalBuffer = await readFile9(safePath);
12990
13284
  } catch {
12991
13285
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12992
13286
  }
@@ -13077,47 +13371,47 @@ function detectStructuralLoss(beforeBlocks, afterBlocks) {
13077
13371
  }
13078
13372
  return { lost: false, detail: "" };
13079
13373
  }
13080
- var insertRowOpSchema = z9.object({
13081
- type: z9.literal("insertRow"),
13082
- row: z9.number().int().nonnegative().describe("\uAE30\uC900 \uD589 \uC778\uB371\uC2A4 (0-based)"),
13083
- position: z9.enum(["above", "below"]).describe("\uC0BD\uC785 \uC704\uCE58: above=row \uC704\uC5D0, below=row \uC544\uB798\uC5D0")
13374
+ var insertRowOpSchema = z10.object({
13375
+ type: z10.literal("insertRow"),
13376
+ row: z10.number().int().nonnegative().describe("\uAE30\uC900 \uD589 \uC778\uB371\uC2A4 (0-based)"),
13377
+ position: z10.enum(["above", "below"]).describe("\uC0BD\uC785 \uC704\uCE58: above=row \uC704\uC5D0, below=row \uC544\uB798\uC5D0")
13084
13378
  });
13085
- var deleteRowOpSchema = z9.object({
13086
- type: z9.literal("deleteRow"),
13087
- row: z9.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uD589 \uC778\uB371\uC2A4 (0-based)")
13379
+ var deleteRowOpSchema = z10.object({
13380
+ type: z10.literal("deleteRow"),
13381
+ row: z10.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uD589 \uC778\uB371\uC2A4 (0-based)")
13088
13382
  });
13089
- var insertColumnOpSchema = z9.object({
13090
- type: z9.literal("insertColumn"),
13091
- col: z9.number().int().nonnegative().describe("\uAE30\uC900 \uC5F4 \uC778\uB371\uC2A4 (0-based)"),
13092
- position: z9.enum(["left", "right"]).describe("\uC0BD\uC785 \uC704\uCE58: left=col \uC67C\uCABD\uC5D0, right=col \uC624\uB978\uCABD\uC5D0")
13383
+ var insertColumnOpSchema = z10.object({
13384
+ type: z10.literal("insertColumn"),
13385
+ col: z10.number().int().nonnegative().describe("\uAE30\uC900 \uC5F4 \uC778\uB371\uC2A4 (0-based)"),
13386
+ position: z10.enum(["left", "right"]).describe("\uC0BD\uC785 \uC704\uCE58: left=col \uC67C\uCABD\uC5D0, right=col \uC624\uB978\uCABD\uC5D0")
13093
13387
  });
13094
- var deleteColumnOpSchema = z9.object({
13095
- type: z9.literal("deleteColumn"),
13096
- col: z9.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uC5F4 \uC778\uB371\uC2A4 (0-based)")
13388
+ var deleteColumnOpSchema = z10.object({
13389
+ type: z10.literal("deleteColumn"),
13390
+ col: z10.number().int().nonnegative().describe("\uC0AD\uC81C\uD560 \uC5F4 \uC778\uB371\uC2A4 (0-based)")
13097
13391
  });
13098
- var mergeCellsOpSchema = z9.object({
13099
- type: z9.literal("mergeCells"),
13100
- startRow: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uD589 (0-based)"),
13101
- startCol: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uC5F4 (0-based)"),
13102
- endRow: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uD589 (0-based, \uD3EC\uD568)"),
13103
- endCol: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uC5F4 (0-based, \uD3EC\uD568)")
13392
+ var mergeCellsOpSchema = z10.object({
13393
+ type: z10.literal("mergeCells"),
13394
+ startRow: z10.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uD589 (0-based)"),
13395
+ startCol: z10.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uC5F4 (0-based)"),
13396
+ endRow: z10.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uD589 (0-based, \uD3EC\uD568)"),
13397
+ endCol: z10.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uC5F4 (0-based, \uD3EC\uD568)")
13104
13398
  });
13105
- var operationSchema = z9.discriminatedUnion("type", [
13399
+ var operationSchema = z10.discriminatedUnion("type", [
13106
13400
  insertRowOpSchema,
13107
13401
  deleteRowOpSchema,
13108
13402
  insertColumnOpSchema,
13109
13403
  deleteColumnOpSchema,
13110
13404
  mergeCellsOpSchema
13111
13405
  ]).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.");
13112
- var proposeTableStructureSchema = z9.object({
13113
- path: z9.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
13114
- anchor: z9.string().min(1).describe(
13406
+ var proposeTableStructureSchema = z10.object({
13407
+ path: z10.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
13408
+ anchor: z10.string().min(1).describe(
13115
13409
  "\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."
13116
13410
  ),
13117
- operations: z9.array(operationSchema).min(1).describe(
13411
+ operations: z10.array(operationSchema).min(1).describe(
13118
13412
  "\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."
13119
13413
  ),
13120
- summary: z9.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
13414
+ summary: z10.string().describe("\uBCC0\uACBD \uC694\uC57D (\uD55C\uAD6D\uC5B4 1-2\uBB38\uC7A5)")
13121
13415
  });
13122
13416
  function tokenizeHwpxXml2(xml) {
13123
13417
  const tokens = [];
@@ -13792,7 +14086,7 @@ var proposeTableStructureTool = {
13792
14086
  ctx
13793
14087
  }) => {
13794
14088
  const safePath = await resolveSafePath(ctx.cwd, input.path);
13795
- const ext = extname9(safePath).toLowerCase();
14089
+ const ext = extname10(safePath).toLowerCase();
13796
14090
  if (ext === ".hwp") {
13797
14091
  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.";
13798
14092
  }
@@ -13801,7 +14095,7 @@ var proposeTableStructureTool = {
13801
14095
  }
13802
14096
  let originalBuf;
13803
14097
  try {
13804
- originalBuf = await readFile9(safePath);
14098
+ originalBuf = await readFile10(safePath);
13805
14099
  } catch {
13806
14100
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
13807
14101
  }
@@ -13997,11 +14291,11 @@ function searchExcerpts(markdown, query) {
13997
14291
  }
13998
14292
  return result;
13999
14293
  }
14000
- var readDocumentSchema = z10.object({
14001
- path: z10.string().describe("\uC77D\uC744 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14002
- pages: z10.string().optional().describe('\uC77D\uC744 \uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: "1-3", "1,3,5") \u2014 \uBBF8\uC9C0\uC815 \uC2DC \uC804\uCCB4'),
14003
- outline: z10.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)"),
14004
- search: z10.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)")
14294
+ var readDocumentSchema = z11.object({
14295
+ path: z11.string().describe("\uC77D\uC744 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14296
+ pages: z11.string().optional().describe('\uC77D\uC744 \uD398\uC774\uC9C0 \uBC94\uC704 (\uC608: "1-3", "1,3,5") \u2014 \uBBF8\uC9C0\uC815 \uC2DC \uC804\uCCB4'),
14297
+ outline: z11.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)"),
14298
+ search: z11.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)")
14005
14299
  });
14006
14300
  function applyReadMode(body, outline, search) {
14007
14301
  if (outline === true) {
@@ -14023,18 +14317,18 @@ var readDocumentTool = {
14023
14317
  }) => {
14024
14318
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14025
14319
  try {
14026
- const fileStat = await stat3(safePath);
14320
+ const fileStat = await stat4(safePath);
14027
14321
  const guardMsg = fileSizeGuardMessage(fileStat.size, MAX_FILE_SIZE_BYTES);
14028
14322
  if (guardMsg !== null) return guardMsg;
14029
14323
  } catch (e) {
14030
14324
  const msg = e instanceof Error ? e.message : String(e);
14031
14325
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
14032
14326
  }
14033
- const ext = extname10(safePath).toLowerCase();
14327
+ const ext = extname11(safePath).toLowerCase();
14034
14328
  if (PLAIN_TEXT_EXTS.has(ext)) {
14035
14329
  let raw;
14036
14330
  try {
14037
- raw = await readFile10(safePath, "utf-8");
14331
+ raw = await readFile11(safePath, "utf-8");
14038
14332
  } catch (e) {
14039
14333
  const msg = e instanceof Error ? e.message : String(e);
14040
14334
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
@@ -14134,8 +14428,8 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
14134
14428
  ".csv",
14135
14429
  ".log"
14136
14430
  ]);
14137
- var readFileSchema = z11.object({
14138
- path: z11.string().describe("\uC77D\uC744 \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)")
14431
+ var readFileSchema = z12.object({
14432
+ path: z12.string().describe("\uC77D\uC744 \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)")
14139
14433
  });
14140
14434
  var readFileTool = {
14141
14435
  name: "read_file",
@@ -14149,7 +14443,7 @@ var readFileTool = {
14149
14443
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14150
14444
  let info;
14151
14445
  try {
14152
- info = await stat4(safePath);
14446
+ info = await stat5(safePath);
14153
14447
  } catch {
14154
14448
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
14155
14449
  }
@@ -14159,8 +14453,8 @@ var readFileTool = {
14159
14453
  if (info.size > MAX_SIZE) {
14160
14454
  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.`;
14161
14455
  }
14162
- const { extname: extname13 } = await import("path");
14163
- const ext = extname13(safePath).toLowerCase();
14456
+ const { extname: extname14 } = await import("path");
14457
+ const ext = extname14(safePath).toLowerCase();
14164
14458
  if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
14165
14459
  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.`;
14166
14460
  }
@@ -14175,9 +14469,9 @@ var readFileTool = {
14175
14469
  }
14176
14470
  };
14177
14471
  var MAX_PREVIEW_CHARS = 1e4;
14178
- var writeNewDocumentSchema = z12.object({
14179
- path: z12.string().describe("\uC0DD\uC131\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14180
- markdown: z12.string().describe("\uC0C8 \uBB38\uC11C \uB0B4\uC6A9 (\uB9C8\uD06C\uB2E4\uC6B4 \uD615\uC2DD)")
14472
+ var writeNewDocumentSchema = z13.object({
14473
+ path: z13.string().describe("\uC0DD\uC131\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14474
+ markdown: z13.string().describe("\uC0C8 \uBB38\uC11C \uB0B4\uC6A9 (\uB9C8\uD06C\uB2E4\uC6B4 \uD615\uC2DD)")
14181
14475
  });
14182
14476
  var writeNewDocumentTool = {
14183
14477
  name: "write_new_document",
@@ -14189,9 +14483,9 @@ var writeNewDocumentTool = {
14189
14483
  ctx
14190
14484
  }) => {
14191
14485
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14192
- const ext = extname11(safePath).toLowerCase();
14486
+ const ext = extname12(safePath).toLowerCase();
14193
14487
  try {
14194
- await stat5(safePath);
14488
+ await stat6(safePath);
14195
14489
  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.`;
14196
14490
  } catch {
14197
14491
  }
@@ -14239,12 +14533,12 @@ ${preview}`,
14239
14533
  };
14240
14534
  }
14241
14535
  };
14242
- var writeNewSpreadsheetSchema = z13.object({
14243
- path: z13.string().describe("\uC0DD\uC131\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14244
- sheets: z13.array(
14245
- z13.object({
14246
- name: z13.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
14247
- rows: z13.array(z13.array(z13.string())).describe("\uD589 \uB370\uC774\uD130 \uBC30\uC5F4 (\uAC01 \uD589\uC740 \uC140 \uAC12 \uBC30\uC5F4)")
14536
+ var writeNewSpreadsheetSchema = z14.object({
14537
+ path: z14.string().describe("\uC0DD\uC131\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14538
+ sheets: z14.array(
14539
+ z14.object({
14540
+ name: z14.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
14541
+ rows: z14.array(z14.array(z14.string())).describe("\uD589 \uB370\uC774\uD130 \uBC30\uC5F4 (\uAC01 \uD589\uC740 \uC140 \uAC12 \uBC30\uC5F4)")
14248
14542
  })
14249
14543
  ).min(1).describe("\uC0DD\uC131\uD560 \uC2DC\uD2B8 \uBAA9\uB85D")
14250
14544
  });
@@ -14258,12 +14552,12 @@ var writeNewSpreadsheetTool = {
14258
14552
  ctx
14259
14553
  }) => {
14260
14554
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14261
- const ext = extname12(safePath).toLowerCase();
14555
+ const ext = extname13(safePath).toLowerCase();
14262
14556
  if (ext !== ".xlsx") {
14263
14557
  return `\uC624\uB958: write_new_spreadsheet\uC740 .xlsx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD655\uC7A5\uC790: ${ext}.`;
14264
14558
  }
14265
14559
  try {
14266
- await stat6(safePath);
14560
+ await stat7(safePath);
14267
14561
  return `\uC624\uB958: \uD30C\uC77C\uC774 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4: ${input.path}. \uAE30\uC874 \uD30C\uC77C \uC140 \uC218\uC815\uC740 propose_sheet_edit\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.`;
14268
14562
  } catch {
14269
14563
  }
@@ -14316,6 +14610,7 @@ function createDocTools(_ctx) {
14316
14610
  readDocumentTool,
14317
14611
  compareDocumentsTool,
14318
14612
  listFilesTool,
14613
+ listBackupsTool,
14319
14614
  readFileTool,
14320
14615
  proposeEditTool,
14321
14616
  proposeFormFillTool,
@@ -14326,7 +14621,8 @@ function createDocTools(_ctx) {
14326
14621
  listFormObjectsTool,
14327
14622
  proposeFormObjectTool,
14328
14623
  writeNewDocumentTool,
14329
- writeNewSpreadsheetTool
14624
+ writeNewSpreadsheetTool,
14625
+ restoreBackupTool
14330
14626
  ];
14331
14627
  }
14332
14628
 
@@ -15130,7 +15426,7 @@ async function runOnboarding() {
15130
15426
 
15131
15427
  // src/update.ts
15132
15428
  import { spawn } from "child_process";
15133
- import { mkdir as mkdir4, readFile as readFile11, writeFile as writeFile3 } from "fs/promises";
15429
+ import { mkdir as mkdir4, readFile as readFile12, writeFile as writeFile3 } from "fs/promises";
15134
15430
  import { dirname as dirname3 } from "path";
15135
15431
  function compareSemver(a, b) {
15136
15432
  const parse6 = (v) => {
@@ -15151,7 +15447,7 @@ function compareSemver(a, b) {
15151
15447
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
15152
15448
  async function readCache(cachePath) {
15153
15449
  try {
15154
- const raw = await readFile11(cachePath, "utf-8");
15450
+ const raw = await readFile12(cachePath, "utf-8");
15155
15451
  const parsed = JSON.parse(raw);
15156
15452
  if (parsed !== null && typeof parsed === "object" && "checkedAt" in parsed && "latest" in parsed && typeof parsed.checkedAt === "string" && typeof parsed.latest === "string") {
15157
15453
  return parsed;