@kodocagent/cli 0.4.1 → 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": {
@@ -10775,7 +10795,12 @@ var ToolRegistry = class {
10775
10795
  return `\uC0AC\uC6A9\uC790\uAC00 \uBCC0\uACBD\uC744 \uAC70\uC808\uD558\uC5EC \uC800\uC7A5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4${reasonPart}. \uAC19\uC740 \uC218\uC815\uC548\uC744 \uC790\uB3D9\uC73C\uB85C \uB2E4\uC2DC \uC81C\uC548\uD558\uC9C0 \uB9D0\uACE0, \uC0AC\uC6A9\uC790\uC758 \uB2E4\uC74C \uC9C0\uC2DC\uB97C \uAE30\uB2E4\uB9AC\uC138\uC694.`;
10776
10796
  }
10777
10797
  try {
10778
- return await commit();
10798
+ const commitMsg = await commit();
10799
+ if (proposal.warnings && proposal.warnings.length > 0) {
10800
+ return `${commitMsg}
10801
+ [\uACBD\uACE0] ${proposal.warnings.join("\n[\uACBD\uACE0] ")}`;
10802
+ }
10803
+ return commitMsg;
10779
10804
  } catch (err) {
10780
10805
  const msg = err instanceof Error ? err.message : String(err);
10781
10806
  return `\uC800\uC7A5 \uC624\uB958: ${msg}`;
@@ -10801,26 +10826,29 @@ import { realpath } from "fs/promises";
10801
10826
  import { basename, dirname as dirname2, isAbsolute, join as join3, normalize, relative, resolve } from "path";
10802
10827
  import { copyFile, mkdir as mkdir3, readdir as readdir2, readFile as readFile3, rename, rm, stat as stat2, writeFile as writeFile2 } from "fs/promises";
10803
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";
10804
10832
  var import_jszip = __toESM(require_lib3(), 1);
10805
10833
  var import_jszip2 = __toESM(require_lib3(), 1);
10806
10834
  var import_jszip3 = __toESM(require_lib3(), 1);
10807
- import { createTwoFilesPatch } from "diff";
10808
- import { readFile as readFile22 } from "fs/promises";
10809
- import { blocksToMarkdown, compare } from "@clazic/kordoc";
10810
10835
  import { z as z3 } from "zod";
10811
10836
  import { readFile as readFile32 } from "fs/promises";
10812
- import { extname as extname2 } from "path";
10837
+ import { blocksToMarkdown, compare } from "@clazic/kordoc";
10813
10838
  import { z as z22 } from "zod";
10814
- import { readdir as readdir22, stat as stat22 } from "fs/promises";
10815
- import { extname as extname3, join as join32, relative as relative2 } from "path";
10816
- import { z as z32 } from "zod";
10817
10839
  import { readFile as readFile4 } from "fs/promises";
10818
- 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";
10819
10844
  import { z as z4 } from "zod";
10820
10845
  import { readFile as readFile5 } from "fs/promises";
10821
10846
  import { extname as extname5 } from "path";
10822
- import { compare as compare2, markdownToHwpx, parse } from "@clazic/kordoc";
10823
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";
10824
10852
  import {
10825
10853
  Document,
10826
10854
  HeadingLevel,
@@ -10832,37 +10860,37 @@ import {
10832
10860
  TextRun,
10833
10861
  WidthType
10834
10862
  } from "docx";
10835
- import { readFile as readFile6 } from "fs/promises";
10836
- import { extname as extname6 } from "path";
10837
- import { parse as parse2 } from "@clazic/kordoc";
10838
- import { z as z6 } from "zod";
10839
10863
  import { readFile as readFile7 } from "fs/promises";
10840
10864
  import { extname as extname7 } from "path";
10841
- import { extractFormFields, markdownToHwpx as markdownToHwpx2, parse as parse3 } from "@clazic/kordoc";
10842
- var import_jszip4 = __toESM(require_lib3(), 1);
10865
+ import { parse as parse2 } from "@clazic/kordoc";
10843
10866
  import { z as z7 } from "zod";
10844
10867
  import { readFile as readFile8 } from "fs/promises";
10845
10868
  import { extname as extname8 } from "path";
10846
- import ExcelJS from "exceljs";
10869
+ import { extractFormFields, markdownToHwpx as markdownToHwpx2, parse as parse3 } from "@clazic/kordoc";
10870
+ var import_jszip4 = __toESM(require_lib3(), 1);
10847
10871
  import { z as z8 } from "zod";
10848
10872
  import { readFile as readFile9 } from "fs/promises";
10849
10873
  import { extname as extname9 } from "path";
10850
- import { parse as parse4 } from "@clazic/kordoc";
10874
+ import ExcelJS from "exceljs";
10851
10875
  import { z as z9 } from "zod";
10852
- import { readFile as readFile10, stat as stat3 } from "fs/promises";
10876
+ import { readFile as readFile10 } from "fs/promises";
10853
10877
  import { extname as extname10 } from "path";
10854
- import { parse as parse5 } from "@clazic/kordoc";
10878
+ import { parse as parse4 } from "@clazic/kordoc";
10855
10879
  import { z as z10 } from "zod";
10856
- import { readFile as fsReadFile, stat as stat4 } from "fs/promises";
10857
- import { z as z11 } from "zod";
10858
- import { stat as stat5 } from "fs/promises";
10880
+ import { readFile as readFile11, stat as stat4 } from "fs/promises";
10859
10881
  import { extname as extname11 } from "path";
10860
- 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";
10861
10885
  import { z as z12 } from "zod";
10862
10886
  import { stat as stat6 } from "fs/promises";
10863
10887
  import { extname as extname12 } from "path";
10864
- import ExcelJS2 from "exceljs";
10888
+ import { markdownToHwpx as markdownToHwpx3 } from "@clazic/kordoc";
10865
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";
10866
10894
  async function resolveSafePath(cwd, p) {
10867
10895
  const normalizedCwd = normalize(cwd).normalize("NFC");
10868
10896
  const normalizedP = p.normalize("NFC");
@@ -10999,11 +11027,220 @@ function resolveOutputPath(targetPath) {
10999
11027
  }
11000
11028
  return { outputPath: targetPath, willConvertFormat: void 0 };
11001
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
+ };
11002
11239
  var MAX_MARKDOWN_LENGTH = 8e4;
11003
11240
  var MAX_BLOCK_TEXT_LENGTH = 200;
11004
- var compareDocumentsSchema = z3.object({
11005
- 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)"),
11006
- 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)")
11007
11244
  });
11008
11245
  function bufferToArrayBuffer(buf) {
11009
11246
  return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
@@ -11041,13 +11278,13 @@ var compareDocumentsTool = {
11041
11278
  let bufA;
11042
11279
  let bufB;
11043
11280
  try {
11044
- bufA = await readFile22(safePathA);
11281
+ bufA = await readFile32(safePathA);
11045
11282
  } catch (e) {
11046
11283
  const msg = e instanceof Error ? e.message : String(e);
11047
11284
  return `\uC624\uB958: \uCCAB \uBC88\uC9F8 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${input.pathA}): ${msg}`;
11048
11285
  }
11049
11286
  try {
11050
- bufB = await readFile22(safePathB);
11287
+ bufB = await readFile32(safePathB);
11051
11288
  } catch (e) {
11052
11289
  const msg = e instanceof Error ? e.message : String(e);
11053
11290
  return `\uC624\uB958: \uB450 \uBC88\uC9F8 \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${input.pathB}): ${msg}`;
@@ -11495,14 +11732,14 @@ function validateHwpxBuffer(ext, buffer) {
11495
11732
  }
11496
11733
  return null;
11497
11734
  }
11498
- var listFormObjectsSchema = z22.object({
11499
- 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")
11500
11737
  });
11501
- var formEditSetSchema = z22.object({
11502
- caption: z22.string().optional().describe("PushButton \uCEA1\uC158 \uD14D\uC2A4\uD2B8"),
11503
- checked: z22.boolean().optional().describe("CheckBox/RadioButton \uCCB4\uD06C \uC0C1\uD0DC (true=CHECKED)"),
11504
- selected: z22.string().optional().describe("ComboBox \uC120\uD0DD \uAC12 (listItem \uC911 \uD558\uB098\uC5EC\uC57C \uD568)"),
11505
- 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")
11506
11743
  }).refine(
11507
11744
  (v) => {
11508
11745
  const keys = ["caption", "checked", "selected", "text"].filter(
@@ -11512,24 +11749,24 @@ var formEditSetSchema = z22.object({
11512
11749
  },
11513
11750
  { message: "set \uD544\uB4DC\uB294 caption/checked/selected/text \uC911 \uC815\uD655\uD788 \uD558\uB098\uB9CC \uC9C0\uC815\uD574\uC57C \uD569\uB2C8\uB2E4." }
11514
11751
  );
11515
- var formEditExpectedSchema = z22.object({
11516
- caption: z22.string().optional(),
11517
- checked: z22.boolean().optional(),
11518
- selected: z22.string().optional(),
11519
- 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()
11520
11757
  }).optional();
11521
- var formEditItemSchema = z22.object({
11522
- name: z22.string().describe("\uC591\uC2DD \uAC1C\uCCB4\uC758 name \uC18D\uC131 \uAC12"),
11523
- 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"),
11524
11761
  set: formEditSetSchema.describe("\uBCC0\uACBD\uD560 \uAC12 (caption/checked/selected/text \uC911 \uD558\uB098)"),
11525
11762
  expected: formEditExpectedSchema.describe(
11526
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."
11527
11764
  )
11528
11765
  });
11529
- var proposeFormObjectSchema = z22.object({
11530
- path: z22.string().describe("\uC218\uC815\uD560 .hwpx \uD30C\uC77C \uACBD\uB85C"),
11531
- edits: z22.array(formEditItemSchema).min(1).describe("\uC591\uC2DD \uAC1C\uCCB4 \uD3B8\uC9D1 \uBAA9\uB85D"),
11532
- 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)")
11533
11770
  });
11534
11771
  var listFormObjectsTool = {
11535
11772
  name: "list_form_objects",
@@ -11541,10 +11778,10 @@ var listFormObjectsTool = {
11541
11778
  ctx
11542
11779
  }) => {
11543
11780
  const safePath = await resolveSafePath(ctx.cwd, input.path);
11544
- const ext = extname2(safePath).toLowerCase();
11781
+ const ext = extname3(safePath).toLowerCase();
11545
11782
  let buffer;
11546
11783
  try {
11547
- buffer = await readFile32(safePath);
11784
+ buffer = await readFile4(safePath);
11548
11785
  } catch {
11549
11786
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
11550
11787
  }
@@ -11596,10 +11833,10 @@ var proposeFormObjectTool = {
11596
11833
  ctx
11597
11834
  }) => {
11598
11835
  const safePath = await resolveSafePath(ctx.cwd, input.path);
11599
- const ext = extname2(safePath).toLowerCase();
11836
+ const ext = extname3(safePath).toLowerCase();
11600
11837
  let originalBuffer;
11601
11838
  try {
11602
- originalBuffer = await readFile32(safePath);
11839
+ originalBuffer = await readFile4(safePath);
11603
11840
  } catch {
11604
11841
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
11605
11842
  }
@@ -11786,14 +12023,14 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
11786
12023
  ]);
11787
12024
  var MAX_DEPTH = 4;
11788
12025
  var MAX_FILES = 500;
11789
- var listFilesSchema = z32.object({
11790
- 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)")
11791
12028
  });
11792
12029
  async function collectFiles(dir, cwd, depth, entries) {
11793
12030
  if (depth > MAX_DEPTH || entries.length >= MAX_FILES) return;
11794
12031
  let items;
11795
12032
  try {
11796
- items = await readdir22(dir);
12033
+ items = await readdir3(dir);
11797
12034
  } catch {
11798
12035
  return;
11799
12036
  }
@@ -11801,15 +12038,15 @@ async function collectFiles(dir, cwd, depth, entries) {
11801
12038
  if (entries.length >= MAX_FILES) break;
11802
12039
  if (item.startsWith(".")) continue;
11803
12040
  if (SKIP_DIRS.has(item)) continue;
11804
- const fullPath = join32(dir, item);
12041
+ const fullPath = join4(dir, item);
11805
12042
  let info;
11806
12043
  try {
11807
- info = await stat22(fullPath);
12044
+ info = await stat3(fullPath);
11808
12045
  } catch {
11809
12046
  continue;
11810
12047
  }
11811
12048
  const relPath = relative2(cwd, fullPath);
11812
- const ext = extname3(item).toLowerCase();
12049
+ const ext = extname4(item).toLowerCase();
11813
12050
  const isDoc = DOC_EXTENSIONS.has(ext);
11814
12051
  if (info.isDirectory()) {
11815
12052
  entries.push({ path: relPath + "/", isDir: true, isDoc: false });
@@ -11847,29 +12084,29 @@ var listFilesTool = {
11847
12084
  return lines.join("\n") + truncateNotice;
11848
12085
  }
11849
12086
  };
11850
- var cellEditItemSchema = z4.object({
11851
- tableIndex: z4.number().int().nonnegative().optional().describe(
12087
+ var cellEditItemSchema = z5.object({
12088
+ tableIndex: z5.number().int().nonnegative().optional().describe(
11852
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)."
11853
12090
  ),
11854
- row: z4.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 rowAddr (0-based)"),
11855
- col: z4.number().int().nonnegative().optional().describe("\uC88C\uD45C \uBAA8\uB4DC: \uC140\uC758 colAddr (0-based)"),
11856
- 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(
11857
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."
11858
12095
  ),
11859
- 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."),
11860
- newText: z4.string().describe("\uC140\uC5D0 \uC4F8 \uC0C8 \uD14D\uC2A4\uD2B8"),
11861
- 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(
11862
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."
11863
12100
  )
11864
12101
  }).describe(
11865
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."
11866
12103
  );
11867
- var proposeCellEditSchema = z4.object({
11868
- 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)"),
11869
- 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(
11870
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"
11871
12108
  ),
11872
- 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)")
11873
12110
  });
11874
12111
  function tokenizeHwpxXml(xml) {
11875
12112
  const tokens = [];
@@ -12204,7 +12441,7 @@ var proposeCellEditTool = {
12204
12441
  ctx
12205
12442
  }) => {
12206
12443
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12207
- const ext = extname4(safePath).toLowerCase();
12444
+ const ext = extname5(safePath).toLowerCase();
12208
12445
  if (ext === ".hwp") {
12209
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.";
12210
12447
  }
@@ -12213,7 +12450,7 @@ var proposeCellEditTool = {
12213
12450
  }
12214
12451
  let originalBuffer;
12215
12452
  try {
12216
- originalBuffer = await readFile4(safePath);
12453
+ originalBuffer = await readFile5(safePath);
12217
12454
  } catch {
12218
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.`;
12219
12456
  }
@@ -12542,10 +12779,10 @@ async function markdownToDocx(markdown) {
12542
12779
  });
12543
12780
  return Packer.toBuffer(doc);
12544
12781
  }
12545
- var proposeEditSchema = z5.object({
12546
- path: z5.string().describe("\uC218\uC815\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12547
- 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"),
12548
- 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)")
12549
12786
  });
12550
12787
  var proposeEditTool = {
12551
12788
  name: "propose_edit",
@@ -12557,10 +12794,10 @@ var proposeEditTool = {
12557
12794
  ctx
12558
12795
  }) => {
12559
12796
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12560
- const ext = extname5(safePath).toLowerCase();
12797
+ const ext = extname6(safePath).toLowerCase();
12561
12798
  let originalBuffer;
12562
12799
  try {
12563
- originalBuffer = await readFile5(safePath);
12800
+ originalBuffer = await readFile6(safePath);
12564
12801
  } catch {
12565
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.`;
12566
12803
  }
@@ -12631,17 +12868,48 @@ ${diff}`;
12631
12868
  };
12632
12869
  }
12633
12870
  };
12634
- var proposeFindReplaceSchema = z6.object({
12635
- 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)"),
12636
- find: z6.string().min(1).describe("\uCC3E\uC744 \uD14D\uC2A4\uD2B8"),
12637
- replace: z6.string().describe("\uBC14\uAFC0 \uD14D\uC2A4\uD2B8"),
12638
- caseSensitive: z6.boolean().optional().default(false).describe("\uB300\uC18C\uBB38\uC790 \uAD6C\uBD84 (\uAE30\uBCF8\uAC12: false)"),
12639
- 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"),
12640
- 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)")
12641
12878
  });
12879
+ var MAX_DIFF_SAMPLES = 20;
12642
12880
  function escapeXml3(text3) {
12643
12881
  return text3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12644
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
+ }
12645
12913
  function replaceInSectionXml(xml, find, replace, caseSensitive, replaceAll, alreadyReplaced) {
12646
12914
  if (!replaceAll && alreadyReplaced > 0) {
12647
12915
  return { xml, count: 0 };
@@ -12749,7 +13017,19 @@ async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive,
12749
13017
  }
12750
13018
  }
12751
13019
  if (totalCount === 0) {
12752
- 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
+ }
12753
13033
  }
12754
13034
  const out = new import_jszip3.default();
12755
13035
  const mimetypeEntry = zip.file("mimetype");
@@ -12768,7 +13048,8 @@ async function applyFindReplaceToHwpx(hwpxBuffer, find, replace, caseSensitive,
12768
13048
  const buf = await out.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
12769
13049
  return {
12770
13050
  buffer: new Uint8Array(buf),
12771
- count: totalCount
13051
+ count: totalCount,
13052
+ samples
12772
13053
  };
12773
13054
  }
12774
13055
  var proposeFindReplaceTool = {
@@ -12781,7 +13062,7 @@ var proposeFindReplaceTool = {
12781
13062
  ctx
12782
13063
  }) => {
12783
13064
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12784
- const ext = extname6(safePath).toLowerCase();
13065
+ const ext = extname7(safePath).toLowerCase();
12785
13066
  if (ext === ".hwp") {
12786
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.";
12787
13068
  }
@@ -12790,7 +13071,7 @@ var proposeFindReplaceTool = {
12790
13071
  }
12791
13072
  let originalBuf;
12792
13073
  try {
12793
- originalBuf = await readFile6(safePath);
13074
+ originalBuf = await readFile7(safePath);
12794
13075
  } catch {
12795
13076
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12796
13077
  }
@@ -12804,6 +13085,7 @@ var proposeFindReplaceTool = {
12804
13085
  );
12805
13086
  let newBytes;
12806
13087
  let replacedCount;
13088
+ let diffSamples;
12807
13089
  try {
12808
13090
  const result = await applyFindReplaceToHwpx(
12809
13091
  originalBytes,
@@ -12814,6 +13096,7 @@ var proposeFindReplaceTool = {
12814
13096
  );
12815
13097
  newBytes = result.buffer;
12816
13098
  replacedCount = result.count;
13099
+ diffSamples = result.samples;
12817
13100
  } catch (e) {
12818
13101
  return `\uC624\uB958: \uCE58\uD658 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. ${String(e)}`;
12819
13102
  }
@@ -12842,7 +13125,23 @@ var proposeFindReplaceTool = {
12842
13125
  }
12843
13126
  const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
12844
13127
  const allLabel = input.all ?? true ? `${replacedCount}\uACF3` : "\uCCAB \uBC88\uC9F8 1\uACF3";
12845
- 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
+ }
12846
13145
  const stagedPath = await stageFile(ctx.sessionId, outputPath, newBytes);
12847
13146
  const proposalId = crypto.randomUUID();
12848
13147
  return {
@@ -12865,10 +13164,10 @@ var proposeFindReplaceTool = {
12865
13164
  };
12866
13165
  }
12867
13166
  };
12868
- var proposeFormFillSchema = z7.object({
12869
- path: z7.string().describe("\uC591\uC2DD \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
12870
- 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"),
12871
- 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)")
12872
13171
  });
12873
13172
  var proposeFormFillTool = {
12874
13173
  name: "propose_form_fill",
@@ -12880,13 +13179,13 @@ var proposeFormFillTool = {
12880
13179
  ctx
12881
13180
  }) => {
12882
13181
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12883
- const ext = extname7(safePath).toLowerCase();
13182
+ const ext = extname8(safePath).toLowerCase();
12884
13183
  if (ext !== ".hwpx" && ext !== ".hwp") {
12885
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.`;
12886
13185
  }
12887
13186
  let originalBuffer;
12888
13187
  try {
12889
- originalBuffer = await readFile7(safePath);
13188
+ originalBuffer = await readFile8(safePath);
12890
13189
  } catch {
12891
13190
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12892
13191
  }
@@ -12954,16 +13253,16 @@ var proposeFormFillTool = {
12954
13253
  };
12955
13254
  }
12956
13255
  };
12957
- var proposeSheetEditSchema = z8.object({
12958
- 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)"),
12959
- updates: z8.array(
12960
- z8.object({
12961
- sheet: z8.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
12962
- cell: z8.string().describe("\uC140 \uC8FC\uC18C (\uC608: A1, B3)"),
12963
- 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")
12964
13263
  })
12965
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"),
12966
- 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)")
12967
13266
  });
12968
13267
  var proposeSheetEditTool = {
12969
13268
  name: "propose_sheet_edit",
@@ -12975,13 +13274,13 @@ var proposeSheetEditTool = {
12975
13274
  ctx
12976
13275
  }) => {
12977
13276
  const safePath = await resolveSafePath(ctx.cwd, input.path);
12978
- const ext = extname8(safePath).toLowerCase();
13277
+ const ext = extname9(safePath).toLowerCase();
12979
13278
  if (ext !== ".xlsx" && ext !== ".xls") {
12980
13279
  return `\uC624\uB958: propose_sheet_edit\uC740 .xlsx/.xls \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD30C\uC77C: ${ext}.`;
12981
13280
  }
12982
13281
  let originalBuffer;
12983
13282
  try {
12984
- originalBuffer = await readFile8(safePath);
13283
+ originalBuffer = await readFile9(safePath);
12985
13284
  } catch {
12986
13285
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
12987
13286
  }
@@ -13072,47 +13371,47 @@ function detectStructuralLoss(beforeBlocks, afterBlocks) {
13072
13371
  }
13073
13372
  return { lost: false, detail: "" };
13074
13373
  }
13075
- var insertRowOpSchema = z9.object({
13076
- type: z9.literal("insertRow"),
13077
- row: z9.number().int().nonnegative().describe("\uAE30\uC900 \uD589 \uC778\uB371\uC2A4 (0-based)"),
13078
- 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")
13079
13378
  });
13080
- var deleteRowOpSchema = z9.object({
13081
- type: z9.literal("deleteRow"),
13082
- 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)")
13083
13382
  });
13084
- var insertColumnOpSchema = z9.object({
13085
- type: z9.literal("insertColumn"),
13086
- col: z9.number().int().nonnegative().describe("\uAE30\uC900 \uC5F4 \uC778\uB371\uC2A4 (0-based)"),
13087
- 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")
13088
13387
  });
13089
- var deleteColumnOpSchema = z9.object({
13090
- type: z9.literal("deleteColumn"),
13091
- 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)")
13092
13391
  });
13093
- var mergeCellsOpSchema = z9.object({
13094
- type: z9.literal("mergeCells"),
13095
- startRow: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uD589 (0-based)"),
13096
- startCol: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uC2DC\uC791 \uC5F4 (0-based)"),
13097
- endRow: z9.number().int().nonnegative().describe("\uBCD1\uD569 \uB05D \uD589 (0-based, \uD3EC\uD568)"),
13098
- 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)")
13099
13398
  });
13100
- var operationSchema = z9.discriminatedUnion("type", [
13399
+ var operationSchema = z10.discriminatedUnion("type", [
13101
13400
  insertRowOpSchema,
13102
13401
  deleteRowOpSchema,
13103
13402
  insertColumnOpSchema,
13104
13403
  deleteColumnOpSchema,
13105
13404
  mergeCellsOpSchema
13106
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.");
13107
- var proposeTableStructureSchema = z9.object({
13108
- 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)"),
13109
- 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(
13110
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."
13111
13410
  ),
13112
- operations: z9.array(operationSchema).min(1).describe(
13411
+ operations: z10.array(operationSchema).min(1).describe(
13113
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."
13114
13413
  ),
13115
- 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)")
13116
13415
  });
13117
13416
  function tokenizeHwpxXml2(xml) {
13118
13417
  const tokens = [];
@@ -13787,7 +14086,7 @@ var proposeTableStructureTool = {
13787
14086
  ctx
13788
14087
  }) => {
13789
14088
  const safePath = await resolveSafePath(ctx.cwd, input.path);
13790
- const ext = extname9(safePath).toLowerCase();
14089
+ const ext = extname10(safePath).toLowerCase();
13791
14090
  if (ext === ".hwp") {
13792
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.";
13793
14092
  }
@@ -13796,7 +14095,7 @@ var proposeTableStructureTool = {
13796
14095
  }
13797
14096
  let originalBuf;
13798
14097
  try {
13799
- originalBuf = await readFile9(safePath);
14098
+ originalBuf = await readFile10(safePath);
13800
14099
  } catch {
13801
14100
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}. \uACBD\uB85C\uB97C \uD655\uC778\uD558\uC138\uC694.`;
13802
14101
  }
@@ -13992,11 +14291,11 @@ function searchExcerpts(markdown, query) {
13992
14291
  }
13993
14292
  return result;
13994
14293
  }
13995
- var readDocumentSchema = z10.object({
13996
- path: z10.string().describe("\uC77D\uC744 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
13997
- 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'),
13998
- 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)"),
13999
- 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)")
14000
14299
  });
14001
14300
  function applyReadMode(body, outline, search) {
14002
14301
  if (outline === true) {
@@ -14018,18 +14317,18 @@ var readDocumentTool = {
14018
14317
  }) => {
14019
14318
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14020
14319
  try {
14021
- const fileStat = await stat3(safePath);
14320
+ const fileStat = await stat4(safePath);
14022
14321
  const guardMsg = fileSizeGuardMessage(fileStat.size, MAX_FILE_SIZE_BYTES);
14023
14322
  if (guardMsg !== null) return guardMsg;
14024
14323
  } catch (e) {
14025
14324
  const msg = e instanceof Error ? e.message : String(e);
14026
14325
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
14027
14326
  }
14028
- const ext = extname10(safePath).toLowerCase();
14327
+ const ext = extname11(safePath).toLowerCase();
14029
14328
  if (PLAIN_TEXT_EXTS.has(ext)) {
14030
14329
  let raw;
14031
14330
  try {
14032
- raw = await readFile10(safePath, "utf-8");
14331
+ raw = await readFile11(safePath, "utf-8");
14033
14332
  } catch (e) {
14034
14333
  const msg = e instanceof Error ? e.message : String(e);
14035
14334
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
@@ -14129,8 +14428,8 @@ var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
14129
14428
  ".csv",
14130
14429
  ".log"
14131
14430
  ]);
14132
- var readFileSchema = z11.object({
14133
- 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)")
14134
14433
  });
14135
14434
  var readFileTool = {
14136
14435
  name: "read_file",
@@ -14144,7 +14443,7 @@ var readFileTool = {
14144
14443
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14145
14444
  let info;
14146
14445
  try {
14147
- info = await stat4(safePath);
14446
+ info = await stat5(safePath);
14148
14447
  } catch {
14149
14448
  return `\uC624\uB958: \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${input.path}`;
14150
14449
  }
@@ -14154,8 +14453,8 @@ var readFileTool = {
14154
14453
  if (info.size > MAX_SIZE) {
14155
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.`;
14156
14455
  }
14157
- const { extname: extname13 } = await import("path");
14158
- const ext = extname13(safePath).toLowerCase();
14456
+ const { extname: extname14 } = await import("path");
14457
+ const ext = extname14(safePath).toLowerCase();
14159
14458
  if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
14160
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.`;
14161
14460
  }
@@ -14170,9 +14469,9 @@ var readFileTool = {
14170
14469
  }
14171
14470
  };
14172
14471
  var MAX_PREVIEW_CHARS = 1e4;
14173
- var writeNewDocumentSchema = z12.object({
14174
- path: z12.string().describe("\uC0DD\uC131\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
14175
- 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)")
14176
14475
  });
14177
14476
  var writeNewDocumentTool = {
14178
14477
  name: "write_new_document",
@@ -14184,9 +14483,9 @@ var writeNewDocumentTool = {
14184
14483
  ctx
14185
14484
  }) => {
14186
14485
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14187
- const ext = extname11(safePath).toLowerCase();
14486
+ const ext = extname12(safePath).toLowerCase();
14188
14487
  try {
14189
- await stat5(safePath);
14488
+ await stat6(safePath);
14190
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.`;
14191
14490
  } catch {
14192
14491
  }
@@ -14234,12 +14533,12 @@ ${preview}`,
14234
14533
  };
14235
14534
  }
14236
14535
  };
14237
- var writeNewSpreadsheetSchema = z13.object({
14238
- 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)"),
14239
- sheets: z13.array(
14240
- z13.object({
14241
- name: z13.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
14242
- 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)")
14243
14542
  })
14244
14543
  ).min(1).describe("\uC0DD\uC131\uD560 \uC2DC\uD2B8 \uBAA9\uB85D")
14245
14544
  });
@@ -14253,12 +14552,12 @@ var writeNewSpreadsheetTool = {
14253
14552
  ctx
14254
14553
  }) => {
14255
14554
  const safePath = await resolveSafePath(ctx.cwd, input.path);
14256
- const ext = extname12(safePath).toLowerCase();
14555
+ const ext = extname13(safePath).toLowerCase();
14257
14556
  if (ext !== ".xlsx") {
14258
14557
  return `\uC624\uB958: write_new_spreadsheet\uC740 .xlsx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD655\uC7A5\uC790: ${ext}.`;
14259
14558
  }
14260
14559
  try {
14261
- await stat6(safePath);
14560
+ await stat7(safePath);
14262
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.`;
14263
14562
  } catch {
14264
14563
  }
@@ -14311,6 +14610,7 @@ function createDocTools(_ctx) {
14311
14610
  readDocumentTool,
14312
14611
  compareDocumentsTool,
14313
14612
  listFilesTool,
14613
+ listBackupsTool,
14314
14614
  readFileTool,
14315
14615
  proposeEditTool,
14316
14616
  proposeFormFillTool,
@@ -14321,7 +14621,8 @@ function createDocTools(_ctx) {
14321
14621
  listFormObjectsTool,
14322
14622
  proposeFormObjectTool,
14323
14623
  writeNewDocumentTool,
14324
- writeNewSpreadsheetTool
14624
+ writeNewSpreadsheetTool,
14625
+ restoreBackupTool
14325
14626
  ];
14326
14627
  }
14327
14628
 
@@ -15125,7 +15426,7 @@ async function runOnboarding() {
15125
15426
 
15126
15427
  // src/update.ts
15127
15428
  import { spawn } from "child_process";
15128
- 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";
15129
15430
  import { dirname as dirname3 } from "path";
15130
15431
  function compareSemver(a, b) {
15131
15432
  const parse6 = (v) => {
@@ -15146,7 +15447,7 @@ function compareSemver(a, b) {
15146
15447
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
15147
15448
  async function readCache(cachePath) {
15148
15449
  try {
15149
- const raw = await readFile11(cachePath, "utf-8");
15450
+ const raw = await readFile12(cachePath, "utf-8");
15150
15451
  const parsed = JSON.parse(raw);
15151
15452
  if (parsed !== null && typeof parsed === "object" && "checkedAt" in parsed && "latest" in parsed && typeof parsed.checkedAt === "string" && typeof parsed.latest === "string") {
15152
15453
  return parsed;