@kodocagent/cli 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +223 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9851,6 +9851,49 @@ var KODOC_PATHS = {
|
|
|
9851
9851
|
function projectMcpConfigPath(cwd) {
|
|
9852
9852
|
return join(cwd, ".kodocagent", "mcp.json");
|
|
9853
9853
|
}
|
|
9854
|
+
var PATTERNS = [
|
|
9855
|
+
{
|
|
9856
|
+
type: "\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638",
|
|
9857
|
+
re: /\b\d{6}-[1-4]\d{6}\b/g,
|
|
9858
|
+
mask: (m) => `${m.slice(0, 8)}******`
|
|
9859
|
+
},
|
|
9860
|
+
{
|
|
9861
|
+
type: "\uC2E0\uC6A9\uCE74\uB4DC\uBC88\uD638",
|
|
9862
|
+
re: /\b\d{4}-\d{4}-\d{4}-\d{4}\b/g,
|
|
9863
|
+
mask: (m) => `${m.slice(0, 4)}-****-****-${m.slice(-4)}`
|
|
9864
|
+
},
|
|
9865
|
+
{
|
|
9866
|
+
type: "\uC804\uD654\uBC88\uD638",
|
|
9867
|
+
re: /\b0\d{1,2}-\d{3,4}-\d{4}\b/g,
|
|
9868
|
+
mask: (m) => {
|
|
9869
|
+
const p = m.split("-");
|
|
9870
|
+
return `${p[0]}-${"*".repeat((p[1] ?? "").length)}-${p[2]}`;
|
|
9871
|
+
}
|
|
9872
|
+
},
|
|
9873
|
+
{
|
|
9874
|
+
type: "\uC774\uBA54\uC77C",
|
|
9875
|
+
re: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
|
|
9876
|
+
mask: (m) => {
|
|
9877
|
+
const [u, d] = m.split("@");
|
|
9878
|
+
return `${u?.[0] ?? ""}***@${d}`;
|
|
9879
|
+
}
|
|
9880
|
+
}
|
|
9881
|
+
];
|
|
9882
|
+
function detectPii(text3) {
|
|
9883
|
+
if (!text3) return [];
|
|
9884
|
+
const out = [];
|
|
9885
|
+
for (const { type, re, mask } of PATTERNS) {
|
|
9886
|
+
const matches = text3.match(re);
|
|
9887
|
+
if (matches && matches.length > 0) {
|
|
9888
|
+
const uniq = [...new Set(matches)];
|
|
9889
|
+
out.push({ type, count: matches.length, masked: uniq.slice(0, 5).map(mask) });
|
|
9890
|
+
}
|
|
9891
|
+
}
|
|
9892
|
+
return out;
|
|
9893
|
+
}
|
|
9894
|
+
function summarizePii(findings) {
|
|
9895
|
+
return findings.map((f) => `${f.type} ${f.count}\uAC74`).join(", ");
|
|
9896
|
+
}
|
|
9854
9897
|
|
|
9855
9898
|
// ../core/dist/index.js
|
|
9856
9899
|
import { stepCountIs, streamText } from "ai";
|
|
@@ -9869,7 +9912,12 @@ import { appendFile, mkdir as mkdir2, readdir, readFile as readFile2, stat } fro
|
|
|
9869
9912
|
import { join as join2 } from "path";
|
|
9870
9913
|
import { tool } from "ai";
|
|
9871
9914
|
function buildSystemPrompt(ctx) {
|
|
9872
|
-
const stable = [
|
|
9915
|
+
const stable = [
|
|
9916
|
+
ROLE_SECTION,
|
|
9917
|
+
DOCUMENT_RULES_SECTION,
|
|
9918
|
+
EDIT_SAFETY_SECTION,
|
|
9919
|
+
LAW_RULES_SECTION
|
|
9920
|
+
].join("\n\n");
|
|
9873
9921
|
const dynamic = buildDynamicContext(ctx);
|
|
9874
9922
|
return `${stable}
|
|
9875
9923
|
|
|
@@ -9892,6 +9940,15 @@ var DOCUMENT_RULES_SECTION = `## \uBB38\uC11C \uADDC\uCE59
|
|
|
9892
9940
|
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
9941
|
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
9942
|
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.`;
|
|
9943
|
+
var EDIT_SAFETY_SECTION = `## \uD3B8\uC9D1 \uC548\uC804 \uADDC\uCE59
|
|
9944
|
+
|
|
9945
|
+
1. \uC694\uCCAD\uBC1B\uC740 \uBD80\uBD84\uB9CC \uC218\uC815\uD558\uACE0, \uC694\uCCAD\uD558\uC9C0 \uC54A\uC740 \uBB38\uC7A5\xB7\uC11C\uC2DD\xB7\uAD6C\uC870\xB7\uD45C\uD604\uC740 \uADF8\uB300\uB85C \uB461\uB2C8\uB2E4. \uBB38\uC11C \uC804\uCCB4\uB97C \uC784\uC758\uB85C \uC7AC\uC791\uC131\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.
|
|
9946
|
+
2. \uBB38\uC11C\uC5D0 \uC5C6\uB294 \uC815\uBCF4\uB97C \uB9CC\uB4E4\uC5B4\uB0B4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC218\uCE58\xB7\uAE08\uC561\xB7\uB0A0\uC9DC\xB7\uC778\uBA85\xB7\uAE30\uAD00\uBA85\xB7\uACC4\uC57D \uC870\uD56D \uB4F1\uC744 \uCD94\uCE21\uD574 \uC0C8\uB85C \uC4F0\uAC70\uB098 \uBC14\uAFB8\uC9C0 \uC54A\uC73C\uBA70, \uBD88\uD655\uC2E4\uD558\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD655\uC778\uD569\uB2C8\uB2E4.
|
|
9947
|
+
3. \uC0AC\uC6A9\uC790\uAC00 \uBA85\uC2DC\uC801\uC73C\uB85C \uBC14\uAFB8\uB77C\uACE0 \uD558\uC9C0 \uC54A\uC740 \uD55C \uC22B\uC790\xB7\uAE08\uC561\xB7\uB0A0\uC9DC\xB7\uB2E8\uC704\xB7\uACE0\uC720\uBA85\uC0AC\xB7\uBC95\uB839 \uC870\uBB38 \uBC88\uD638\uC640 \uC778\uC6A9\uBD80\uD638(" ", ' ', \u300C \u300D) \uB0B4\uBD80 \uB0B4\uC6A9\uC740 \uBCF4\uC874\uD569\uB2C8\uB2E4.
|
|
9948
|
+
4. \uC804\uBB38 \uC6A9\uC5B4\uB294 \uC784\uC758\uB85C \uB2E4\uB978 \uD45C\uD604\uC73C\uB85C \uBC14\uAFB8\uC9C0 \uC54A\uACE0 \uBB38\uC11C \uC804\uCCB4\uC5D0\uC11C \uC77C\uAD00\uB418\uAC8C \uC720\uC9C0\uD569\uB2C8\uB2E4.
|
|
9949
|
+
5. \uACC4\uC57D\uC11C\xB7\uC57D\uAD00\xB7\uACF5\uC2DC\xB7\uB17C\uBB38 \uB4F1 \uBC95\uC801\xB7\uACF5\uC2DD \uBB38\uC11C\uB294 \uB2E8\uC5B4 \uD558\uB098\uAC00 \uC758\uBBF8\uB97C \uBC14\uAFC0 \uC218 \uC788\uC73C\uBBC0\uB85C, \uD45C\uD604\uC744 \uC790\uB3D9\uC73C\uB85C \uB2E4\uB4EC\uC9C0 \uB9D0\uACE0 \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uBCC0\uACBD\uB9CC \uC218\uD589\uD569\uB2C8\uB2E4.
|
|
9950
|
+
6. \uC758\uBBF8\uAC00 \uBC14\uB014 \uC218 \uC788\uB294 \uC218\uC815\uC740 \uC2E4\uD589 \uC804\uC5D0 \uADF8 \uC0AC\uC2E4\uC744 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC54C\uB9AC\uACE0, \uC218\uC815 \uC81C\uC548\uC758 \uC694\uC57D(summary)\uC5D0\uB294 \uBB34\uC5C7\uC744\xB7\uC65C \uBC14\uAFB8\uB294\uC9C0 \uD568\uAED8 \uC801\uC2B5\uB2C8\uB2E4.
|
|
9951
|
+
7. \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\xB7\uC804\uD654\uBC88\uD638\xB7\uC774\uBA54\uC77C\xB7\uACC4\uC88C\xB7\uCE74\uB4DC\uBC88\uD638 \uB4F1)\uAC00 \uC788\uC744 \uC218 \uC788\uB294 \uBB38\uC11C\uB97C \uB2E4\uB8F0 \uB54C \uC8FC\uC758\uD558\uACE0, \uC0AC\uC6A9\uC790\uAC00 \uAC1C\uC778\uC815\uBCF4 \uC810\uAC80\uC744 \uC694\uCCAD\uD558\uBA74 \`scan_pii\` \uB3C4\uAD6C\uB85C \uD655\uC778\uD569\uB2C8\uB2E4.`;
|
|
9895
9952
|
var LAW_RULES_SECTION = `## \uBC95\uB839 \uADDC\uCE59
|
|
9896
9953
|
|
|
9897
9954
|
1. \uBC95\uB839 \uC778\uC6A9 \uD615\uC2DD: \u300C\uBC95\uB839\uBA85\u300D \uC81CN\uC870 \uC81CN\uD56D \uC81CN\uD638
|
|
@@ -10017,6 +10074,26 @@ var AgentSession = class {
|
|
|
10017
10074
|
this.openDocuments.push(p);
|
|
10018
10075
|
}
|
|
10019
10076
|
}
|
|
10077
|
+
/**
|
|
10078
|
+
* 저장된 메시지(어시스턴트 tool-call 파트)에서 열람·작성한 문서 경로를 도출해 기록한다.
|
|
10079
|
+
* 세션이 턴마다 재생성되므로, 시스템 프롬프트("열람한 문서")가 이전 턴의 열람 기록을
|
|
10080
|
+
* 반영하려면 히스토리에서 다시 복원해야 한다.
|
|
10081
|
+
*/
|
|
10082
|
+
recordOpenDocumentsFromMessage(msg) {
|
|
10083
|
+
const content = msg.content;
|
|
10084
|
+
if (!Array.isArray(content)) return;
|
|
10085
|
+
for (const part of content) {
|
|
10086
|
+
if (!part || typeof part !== "object") continue;
|
|
10087
|
+
const p = part;
|
|
10088
|
+
if (p.type !== "tool-call" || !p.input) continue;
|
|
10089
|
+
if (p.toolName === "read_document" || p.toolName === "write_new_document" || p.toolName === "write_new_spreadsheet") {
|
|
10090
|
+
this.recordOpenDocument(p.input.path);
|
|
10091
|
+
} else if (p.toolName === "compare_documents") {
|
|
10092
|
+
this.recordOpenDocument(p.input.pathA);
|
|
10093
|
+
this.recordOpenDocument(p.input.pathB);
|
|
10094
|
+
}
|
|
10095
|
+
}
|
|
10096
|
+
}
|
|
10020
10097
|
/** approval-required 이벤트를 run() 스트림에 전달하기 위한 큐 */
|
|
10021
10098
|
pendingApprovalEvents = [];
|
|
10022
10099
|
/**
|
|
@@ -10025,6 +10102,9 @@ var AgentSession = class {
|
|
|
10025
10102
|
async loadHistory() {
|
|
10026
10103
|
const msgs = await this.opts.store.loadMessages();
|
|
10027
10104
|
this.messages.push(...msgs);
|
|
10105
|
+
for (const msg of msgs) {
|
|
10106
|
+
this.recordOpenDocumentsFromMessage(msg);
|
|
10107
|
+
}
|
|
10028
10108
|
}
|
|
10029
10109
|
/**
|
|
10030
10110
|
* 사용자 메시지를 처리하고 에이전트 이벤트를 스트리밍한다.
|
|
@@ -10079,7 +10159,7 @@ var AgentSession = class {
|
|
|
10079
10159
|
} else if (part.toolName === "compare_documents") {
|
|
10080
10160
|
this.recordOpenDocument(inp.pathA);
|
|
10081
10161
|
this.recordOpenDocument(inp.pathB);
|
|
10082
|
-
} else if (part.toolName === "write_new_document") {
|
|
10162
|
+
} else if (part.toolName === "write_new_document" || part.toolName === "write_new_spreadsheet") {
|
|
10083
10163
|
this.recordOpenDocument(inp.path);
|
|
10084
10164
|
}
|
|
10085
10165
|
} catch {
|
|
@@ -10788,6 +10868,13 @@ var ToolRegistry = class {
|
|
|
10788
10868
|
return outcome;
|
|
10789
10869
|
}
|
|
10790
10870
|
const { proposal, commit } = outcome;
|
|
10871
|
+
const piiFindings = detectPii(proposal.diff ?? "");
|
|
10872
|
+
if (piiFindings.length > 0) {
|
|
10873
|
+
proposal.warnings = [
|
|
10874
|
+
...proposal.warnings ?? [],
|
|
10875
|
+
`\uAC1C\uC778\uC815\uBCF4 \uD3EC\uD568: \uC774\uBC88 \uBCC0\uACBD \uC601\uC5ED\uC5D0 ${summarizePii(piiFindings)}\uC774(\uAC00) \uC788\uC2B5\uB2C8\uB2E4. \uC678\uBD80 \uACF5\uC720 \uC2DC \uC8FC\uC758\uD558\uC138\uC694.`
|
|
10876
|
+
];
|
|
10877
|
+
}
|
|
10791
10878
|
getEventEmitter()?.(proposal);
|
|
10792
10879
|
const approvalResult = await approvalHandler(proposal);
|
|
10793
10880
|
if (!approvalResult.approved) {
|
|
@@ -10883,14 +10970,18 @@ import { parse as parse5 } from "@clazic/kordoc";
|
|
|
10883
10970
|
import { z as z11 } from "zod";
|
|
10884
10971
|
import { readFile as fsReadFile, stat as stat5 } from "fs/promises";
|
|
10885
10972
|
import { z as z12 } from "zod";
|
|
10886
|
-
import {
|
|
10973
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
10887
10974
|
import { extname as extname12 } from "path";
|
|
10888
|
-
import {
|
|
10975
|
+
import { parse as parse6 } from "@clazic/kordoc";
|
|
10889
10976
|
import { z as z13 } from "zod";
|
|
10890
|
-
import { stat as
|
|
10977
|
+
import { stat as stat6 } from "fs/promises";
|
|
10891
10978
|
import { extname as extname13 } from "path";
|
|
10892
|
-
import
|
|
10979
|
+
import { markdownToHwpx as markdownToHwpx3 } from "@clazic/kordoc";
|
|
10893
10980
|
import { z as z14 } from "zod";
|
|
10981
|
+
import { stat as stat7 } from "fs/promises";
|
|
10982
|
+
import { extname as extname14 } from "path";
|
|
10983
|
+
import ExcelJS2 from "exceljs";
|
|
10984
|
+
import { z as z15 } from "zod";
|
|
10894
10985
|
async function resolveSafePath(cwd, p) {
|
|
10895
10986
|
const normalizedCwd = normalize(cwd).normalize("NFC");
|
|
10896
10987
|
const normalizedP = p.normalize("NFC");
|
|
@@ -11022,8 +11113,10 @@ async function cleanOldBackups(maxAgeDays = 30, baseDir) {
|
|
|
11022
11113
|
function resolveOutputPath(targetPath) {
|
|
11023
11114
|
const ext = extname(targetPath).toLowerCase();
|
|
11024
11115
|
if (ext === ".hwp") {
|
|
11025
|
-
|
|
11026
|
-
|
|
11116
|
+
return { outputPath: targetPath.slice(0, -4) + ".hwpx", willConvertFormat: ".hwp \u2192 .hwpx" };
|
|
11117
|
+
}
|
|
11118
|
+
if (ext === ".xls") {
|
|
11119
|
+
return { outputPath: targetPath.slice(0, -4) + ".xlsx", willConvertFormat: ".xls \u2192 .xlsx" };
|
|
11027
11120
|
}
|
|
11028
11121
|
return { outputPath: targetPath, willConvertFormat: void 0 };
|
|
11029
11122
|
}
|
|
@@ -11153,19 +11246,29 @@ var restoreBackupTool = {
|
|
|
11153
11246
|
if (candidates.length === 0) {
|
|
11154
11247
|
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
11248
|
}
|
|
11249
|
+
const byNewest = (a, b) => b.mtimeMs !== a.mtimeMs ? b.mtimeMs - a.mtimeMs : b.tsToken.localeCompare(a.tsToken);
|
|
11156
11250
|
let chosen;
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
);
|
|
11161
|
-
if (
|
|
11162
|
-
|
|
11251
|
+
let ambiguityNote = null;
|
|
11252
|
+
const requested = input.backup?.trim();
|
|
11253
|
+
if (requested) {
|
|
11254
|
+
const exact = candidates.find((c) => c.filename === requested);
|
|
11255
|
+
if (exact) {
|
|
11256
|
+
chosen = exact;
|
|
11257
|
+
} else {
|
|
11258
|
+
const matches = candidates.filter(
|
|
11259
|
+
(c) => c.filename.endsWith(requested) || c.fullPath.endsWith(requested)
|
|
11260
|
+
);
|
|
11261
|
+
if (matches.length === 0) {
|
|
11262
|
+
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\uC758 \uC815\uD655\uD55C \uD30C\uC77C\uBA85\uC744 \uD655\uC778\uD558\uC138\uC694.`;
|
|
11263
|
+
}
|
|
11264
|
+
matches.sort(byNewest);
|
|
11265
|
+
chosen = matches[0];
|
|
11266
|
+
if (matches.length > 1) {
|
|
11267
|
+
ambiguityNote = `'${input.backup}'\uC640 \uC77C\uCE58\uD558\uB294 \uBC31\uC5C5\uC774 ${matches.length}\uAC1C\uC5EC\uC11C \uAC00\uC7A5 \uCD5C\uADFC(${formatTimestamp(chosen.tsToken)}) \uAC83\uC744 \uC120\uD0DD\uD588\uC2B5\uB2C8\uB2E4. \uD2B9\uC815 \uBC31\uC5C5\uC744 \uC6D0\uD558\uBA74 list_backups\uC758 \uC804\uCCB4 \uD30C\uC77C\uBA85\uC744 \uC9C0\uC815\uD558\uC138\uC694.`;
|
|
11268
|
+
}
|
|
11163
11269
|
}
|
|
11164
|
-
chosen = found;
|
|
11165
11270
|
} else {
|
|
11166
|
-
candidates.sort(
|
|
11167
|
-
(a, b) => b.mtimeMs !== a.mtimeMs ? b.mtimeMs - a.mtimeMs : b.tsToken.localeCompare(a.tsToken)
|
|
11168
|
-
);
|
|
11271
|
+
candidates.sort(byNewest);
|
|
11169
11272
|
chosen = candidates[0];
|
|
11170
11273
|
}
|
|
11171
11274
|
let backupBytes;
|
|
@@ -11206,12 +11309,15 @@ var restoreBackupTool = {
|
|
|
11206
11309
|
].join("\n");
|
|
11207
11310
|
}
|
|
11208
11311
|
const warnings = [];
|
|
11209
|
-
const autoSelected = !
|
|
11312
|
+
const autoSelected = !requested && candidates.length > 1;
|
|
11210
11313
|
if (autoSelected) {
|
|
11211
11314
|
warnings.push(
|
|
11212
11315
|
`\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
11316
|
);
|
|
11214
11317
|
}
|
|
11318
|
+
if (ambiguityNote) {
|
|
11319
|
+
warnings.push(ambiguityNote);
|
|
11320
|
+
}
|
|
11215
11321
|
warnings.push(
|
|
11216
11322
|
"\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
11323
|
);
|
|
@@ -13116,7 +13222,7 @@ var proposeFindReplaceTool = {
|
|
|
13116
13222
|
const remaining = countOccurrences(normAfter, normFind);
|
|
13117
13223
|
if (remaining > 0) {
|
|
13118
13224
|
warnings.push(
|
|
13119
|
-
`\uC77C\uBD80 "${input.find}"(${remaining}\uACF3)\uC774 \uAD50\uCCB4\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uAC00 \uC5EC\uB7EC \uC11C\uC2DD \uB7F0\uC5D0 \uB098\uB258\uC5B4 \uC788\uC5B4 \uACBD\uACC4\uB97C \uAC00\uB85C\uC9C0\uB974\uB294 \uD328\uD134\uC740 \uAD50\uCCB4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uC11C\uC2DD\uC774 \uB098\uB25C \uD14D\uC2A4\uD2B8). \uC774\uBBF8 \uAD50\uCCB4\uB41C ${replacedCount}\uACF3\uC740 \uC815\uC0C1 \uBC18\uC601\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`
|
|
13225
|
+
`\uC77C\uBD80 "${input.find}"(${remaining}\uACF3)\uC774 \uAD50\uCCB4\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD14D\uC2A4\uD2B8\uAC00 \uC5EC\uB7EC \uC11C\uC2DD \uB7F0\uC5D0 \uB098\uB258\uC5B4 \uC788\uC5B4 \uACBD\uACC4\uB97C \uAC00\uB85C\uC9C0\uB974\uB294 \uD328\uD134\uC740 \uAD50\uCCB4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uC11C\uC2DD\uC774 \uB098\uB25C \uD14D\uC2A4\uD2B8). \uC774\uBBF8 \uAD50\uCCB4\uB41C ${replacedCount}\uACF3\uC740 \uC815\uC0C1 \uBC18\uC601\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB0A8\uC740 ${remaining}\uACF3\uC740 \uD45C \uC548\uC758 \uC140\uC774\uBA74 propose_cell_edit\uC73C\uB85C \uD55C \uACF3\uC529 \uC218\uC815\uD558\uAC70\uB098, \uD55C\uAE00 \uD504\uB85C\uADF8\uB7A8\uC5D0\uC11C \uC9C1\uC811 \uCC3E\uAE30\xB7\uBC14\uAFB8\uAE30\uB85C \uCC98\uB9AC\uD558\uC138\uC694.`
|
|
13120
13226
|
);
|
|
13121
13227
|
}
|
|
13122
13228
|
}
|
|
@@ -13319,23 +13425,25 @@ var proposeSheetEditTool = {
|
|
|
13319
13425
|
return `\uC624\uB958: \uC6CC\uD06C\uBD81 \uC800\uC7A5 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
13320
13426
|
}
|
|
13321
13427
|
const stagedData = modifiedBuffer;
|
|
13322
|
-
const
|
|
13428
|
+
const { outputPath, willConvertFormat } = resolveOutputPath(safePath);
|
|
13429
|
+
const stagedPath = await stageFile(ctx.sessionId, outputPath, stagedData);
|
|
13323
13430
|
const proposalId = crypto.randomUUID();
|
|
13324
13431
|
return {
|
|
13325
13432
|
proposal: {
|
|
13326
13433
|
id: proposalId,
|
|
13327
13434
|
kind: "sheet-edit",
|
|
13328
|
-
targetPath:
|
|
13435
|
+
targetPath: outputPath,
|
|
13329
13436
|
stagedPath,
|
|
13330
13437
|
summary: input.summary,
|
|
13331
13438
|
diff,
|
|
13332
|
-
warnings: []
|
|
13439
|
+
warnings: [],
|
|
13440
|
+
willConvertFormat
|
|
13333
13441
|
},
|
|
13334
13442
|
commit: async () => {
|
|
13335
|
-
const backupPath = await backupFile(
|
|
13336
|
-
await commitStaged(stagedPath,
|
|
13443
|
+
const backupPath = await backupFile(outputPath);
|
|
13444
|
+
await commitStaged(stagedPath, outputPath);
|
|
13337
13445
|
const backupInfo = backupPath ? ` (\uBC31\uC5C5: ${backupPath})` : "";
|
|
13338
|
-
return `\uC800\uC7A5 \uC644\uB8CC: ${
|
|
13446
|
+
return `\uC800\uC7A5 \uC644\uB8CC: ${outputPath}${backupInfo}`;
|
|
13339
13447
|
}
|
|
13340
13448
|
};
|
|
13341
13449
|
}
|
|
@@ -14453,8 +14561,8 @@ var readFileTool = {
|
|
|
14453
14561
|
if (info.size > MAX_SIZE) {
|
|
14454
14562
|
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.`;
|
|
14455
14563
|
}
|
|
14456
|
-
const { extname:
|
|
14457
|
-
const ext =
|
|
14564
|
+
const { extname: extname15 } = await import("path");
|
|
14565
|
+
const ext = extname15(safePath).toLowerCase();
|
|
14458
14566
|
if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
|
|
14459
14567
|
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.`;
|
|
14460
14568
|
}
|
|
@@ -14468,10 +14576,64 @@ var readFileTool = {
|
|
|
14468
14576
|
return content;
|
|
14469
14577
|
}
|
|
14470
14578
|
};
|
|
14579
|
+
var PLAIN_TEXT_EXTS2 = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text"]);
|
|
14580
|
+
var scanPiiSchema = z13.object({
|
|
14581
|
+
path: z13.string().describe("\uAC1C\uC778\uC815\uBCF4\uB97C \uC810\uAC80\uD560 \uBB38\uC11C \uACBD\uB85C")
|
|
14582
|
+
});
|
|
14583
|
+
var scanPiiTool = {
|
|
14584
|
+
name: "scan_pii",
|
|
14585
|
+
description: "\uBB38\uC11C\uC5D0\uC11C \uD55C\uAD6D \uAC1C\uC778\uC815\uBCF4(\uC8FC\uBBFC\uB4F1\uB85D\uBC88\uD638\xB7\uC2E0\uC6A9\uCE74\uB4DC\uBC88\uD638\xB7\uC804\uD654\uBC88\uD638\xB7\uC774\uBA54\uC77C)\uB97C \uD0D0\uC9C0\uD569\uB2C8\uB2E4. \uC6D0\uBB38 \uAC12\uC740 \uBC18\uD658\uD558\uC9C0 \uC54A\uACE0 \uB9C8\uC2A4\uD0B9\uB41C \uC608\uC2DC\uB9CC \uD45C\uC2DC\uD569\uB2C8\uB2E4. \uC678\uBD80 \uACF5\uC720 \uC804 \uAC80\uD1A0\uC5D0 \uD65C\uC6A9\uD558\uC138\uC694.",
|
|
14586
|
+
inputSchema: scanPiiSchema,
|
|
14587
|
+
requiresApproval: false,
|
|
14588
|
+
execute: async ({
|
|
14589
|
+
input,
|
|
14590
|
+
ctx
|
|
14591
|
+
}) => {
|
|
14592
|
+
let safePath;
|
|
14593
|
+
try {
|
|
14594
|
+
safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14595
|
+
} catch (e) {
|
|
14596
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14597
|
+
return `\uC624\uB958: \uACBD\uB85C\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
14598
|
+
}
|
|
14599
|
+
const ext = extname12(safePath).toLowerCase();
|
|
14600
|
+
let text3;
|
|
14601
|
+
if (PLAIN_TEXT_EXTS2.has(ext)) {
|
|
14602
|
+
try {
|
|
14603
|
+
text3 = await readFile12(safePath, "utf-8");
|
|
14604
|
+
} catch (e) {
|
|
14605
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14606
|
+
return `\uC624\uB958: \uD30C\uC77C\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
14607
|
+
}
|
|
14608
|
+
} else {
|
|
14609
|
+
let parseResult;
|
|
14610
|
+
try {
|
|
14611
|
+
parseResult = await parse6(safePath);
|
|
14612
|
+
} catch (e) {
|
|
14613
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
14614
|
+
return `\uC624\uB958: \uBB38\uC11C\uB97C \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`;
|
|
14615
|
+
}
|
|
14616
|
+
if (!parseResult.success) {
|
|
14617
|
+
return `\uC624\uB958: \uBB38\uC11C\uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${parseResult.error ?? "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`;
|
|
14618
|
+
}
|
|
14619
|
+
text3 = parseResult.markdown;
|
|
14620
|
+
}
|
|
14621
|
+
const findings = detectPii(text3);
|
|
14622
|
+
if (findings.length === 0) {
|
|
14623
|
+
return `\uAC1C\uC778\uC815\uBCF4\uAC00 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4: ${input.path}`;
|
|
14624
|
+
}
|
|
14625
|
+
const lines = [`\uBC1C\uACAC\uB41C \uAC1C\uC778\uC815\uBCF4 (${input.path}):`];
|
|
14626
|
+
for (const f of findings) {
|
|
14627
|
+
lines.push(`- ${f.type}: ${f.count}\uAC74 (\uC608: ${f.masked.join(", ")})`);
|
|
14628
|
+
}
|
|
14629
|
+
lines.push("\u203B \uB9C8\uC2A4\uD0B9\uB41C \uC608\uC2DC\uC774\uBA70 \uC6D0\uBB38 \uAC12\uC740 \uD45C\uC2DC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC678\uBD80 \uACF5\uC720 \uC804 \uD655\uC778\uD558\uC138\uC694.");
|
|
14630
|
+
return lines.join("\n");
|
|
14631
|
+
}
|
|
14632
|
+
};
|
|
14471
14633
|
var MAX_PREVIEW_CHARS = 1e4;
|
|
14472
|
-
var writeNewDocumentSchema =
|
|
14473
|
-
path:
|
|
14474
|
-
markdown:
|
|
14634
|
+
var writeNewDocumentSchema = z14.object({
|
|
14635
|
+
path: z14.string().describe("\uC0DD\uC131\uD560 \uBB38\uC11C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
14636
|
+
markdown: z14.string().describe("\uC0C8 \uBB38\uC11C \uB0B4\uC6A9 (\uB9C8\uD06C\uB2E4\uC6B4 \uD615\uC2DD)")
|
|
14475
14637
|
});
|
|
14476
14638
|
var writeNewDocumentTool = {
|
|
14477
14639
|
name: "write_new_document",
|
|
@@ -14483,7 +14645,7 @@ var writeNewDocumentTool = {
|
|
|
14483
14645
|
ctx
|
|
14484
14646
|
}) => {
|
|
14485
14647
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14486
|
-
const ext =
|
|
14648
|
+
const ext = extname13(safePath).toLowerCase();
|
|
14487
14649
|
try {
|
|
14488
14650
|
await stat6(safePath);
|
|
14489
14651
|
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.`;
|
|
@@ -14533,12 +14695,12 @@ ${preview}`,
|
|
|
14533
14695
|
};
|
|
14534
14696
|
}
|
|
14535
14697
|
};
|
|
14536
|
-
var writeNewSpreadsheetSchema =
|
|
14537
|
-
path:
|
|
14538
|
-
sheets:
|
|
14539
|
-
|
|
14540
|
-
name:
|
|
14541
|
-
rows:
|
|
14698
|
+
var writeNewSpreadsheetSchema = z15.object({
|
|
14699
|
+
path: z15.string().describe("\uC0DD\uC131\uD560 XLSX \uD30C\uC77C \uACBD\uB85C (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C \uB610\uB294 \uC808\uB300 \uACBD\uB85C)"),
|
|
14700
|
+
sheets: z15.array(
|
|
14701
|
+
z15.object({
|
|
14702
|
+
name: z15.string().describe("\uC2DC\uD2B8 \uC774\uB984"),
|
|
14703
|
+
rows: z15.array(z15.array(z15.string())).describe("\uD589 \uB370\uC774\uD130 \uBC30\uC5F4 (\uAC01 \uD589\uC740 \uC140 \uAC12 \uBC30\uC5F4)")
|
|
14542
14704
|
})
|
|
14543
14705
|
).min(1).describe("\uC0DD\uC131\uD560 \uC2DC\uD2B8 \uBAA9\uB85D")
|
|
14544
14706
|
});
|
|
@@ -14552,7 +14714,7 @@ var writeNewSpreadsheetTool = {
|
|
|
14552
14714
|
ctx
|
|
14553
14715
|
}) => {
|
|
14554
14716
|
const safePath = await resolveSafePath(ctx.cwd, input.path);
|
|
14555
|
-
const ext =
|
|
14717
|
+
const ext = extname14(safePath).toLowerCase();
|
|
14556
14718
|
if (ext !== ".xlsx") {
|
|
14557
14719
|
return `\uC624\uB958: write_new_spreadsheet\uC740 .xlsx \uD30C\uC77C\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4. \uD604\uC7AC \uD655\uC7A5\uC790: ${ext}.`;
|
|
14558
14720
|
}
|
|
@@ -14612,6 +14774,7 @@ function createDocTools(_ctx) {
|
|
|
14612
14774
|
listFilesTool,
|
|
14613
14775
|
listBackupsTool,
|
|
14614
14776
|
readFileTool,
|
|
14777
|
+
scanPiiTool,
|
|
14615
14778
|
proposeEditTool,
|
|
14616
14779
|
proposeFormFillTool,
|
|
14617
14780
|
proposeCellEditTool,
|
|
@@ -14711,6 +14874,14 @@ function createCliApprovalHandler() {
|
|
|
14711
14874
|
|
|
14712
14875
|
// src/chat.ts
|
|
14713
14876
|
var HELP_TEXT = `
|
|
14877
|
+
\uD560 \uC218 \uC788\uB294 \uC77C:
|
|
14878
|
+
\u2022 \uBB38\uC11C \uC77D\uAE30\xB7\uC694\uC57D\xB7\uAC80\uD1A0 \u2014 .hwp/.hwpx/.docx/.xlsx/.pdf (\uC608: "\uC774 \uBCF4\uB3C4\uC790\uB8CC \uC694\uC57D\uD574\uC918")
|
|
14879
|
+
\u2022 \uD45C\xB7\uC591\uC2DD \uC218\uC815 \u2014 \uC140 \uAC12, \uC591\uC2DD \uBE48\uCE78, \uD589\xB7\uC5F4 \uCD94\uAC00/\uC0AD\uC81C (\uC608: "\uC774 \uD45C\uC758 \uAE08\uC561\uC744 30000\uC73C\uB85C \uACE0\uCCD0\uC918")
|
|
14880
|
+
\u2022 \uBB38\uC11C \uC804\uCCB4 \uCC3E\uAE30\xB7\uBC14\uAFB8\uAE30 (\uC608: "'\uAD6D\uBBFC\uC8FC\uAD8C'\uC744 '\uAD6D\uBBFC\uC911\uC2EC'\uC73C\uB85C \uB2E4 \uBC14\uAFD4\uC918")
|
|
14881
|
+
\u2022 \uB418\uB3CC\uB9AC\uAE30 \u2014 \uC9C1\uC804 \uBCC0\uACBD\uC744 \uBC31\uC5C5\uC73C\uB85C \uBCF5\uC6D0 (\uC608: "\uBC29\uAE08 \uC218\uC815 \uB418\uB3CC\uB824\uC918")
|
|
14882
|
+
\u2022 \uD55C\uAD6D \uBC95\uB839 \uAE30\uBC18 \uAC80\uD1A0 (\uC608: "\uC774 \uCDE8\uC5C5\uADDC\uCE59\uC774 \uADFC\uB85C\uAE30\uC900\uBC95\uC5D0 \uB9DE\uB294\uC9C0 \uBD10\uC918")
|
|
14883
|
+
\u203B .hwp\uB294 \uD55C\uAE00\uC5D0\uC11C .hwpx\uB85C \uC800\uC7A5\uD55C \uD6C4 \uC218\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.
|
|
14884
|
+
|
|
14714
14885
|
\uC2AC\uB798\uC2DC \uBA85\uB839:
|
|
14715
14886
|
/model \u2014 \uD504\uB85C\uBC14\uC774\uB354/\uBAA8\uB378 \uC804\uD658
|
|
14716
14887
|
/context \u2014 \uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8 \uC0AC\uC6A9\uB7C9 \uD45C\uC2DC
|
|
@@ -14833,6 +15004,11 @@ async function runChat(opts) {
|
|
|
14833
15004
|
|
|
14834
15005
|
`)
|
|
14835
15006
|
);
|
|
15007
|
+
process.stdout.write(
|
|
15008
|
+
chalk2.dim(
|
|
15009
|
+
'\uBB38\uC11C\uB97C \uC77D\uACE0 \uD45C\xB7\uC591\uC2DD \uC218\uC815, \uCC3E\uAE30\xB7\uBC14\uAFB8\uAE30, \uB418\uB3CC\uB9AC\uAE30\uAE4C\uC9C0 \uC790\uC5F0\uC5B4\uB85C \uC694\uCCAD\uD558\uC138\uC694. \uC608: "\uC774 \uD45C\uC758 \uD569\uACC4\uB97C \uB2E4\uC2DC \uACC4\uC0B0\uD574\uC918", "\uBC29\uAE08 \uC218\uC815 \uB418\uB3CC\uB824\uC918". \uC790\uC138\uD788: /help\n'
|
|
15010
|
+
)
|
|
15011
|
+
);
|
|
14836
15012
|
while (true) {
|
|
14837
15013
|
let clearActiveSpinner2 = function() {
|
|
14838
15014
|
if (!sharedActiveInterval) return;
|
|
@@ -15426,10 +15602,10 @@ async function runOnboarding() {
|
|
|
15426
15602
|
|
|
15427
15603
|
// src/update.ts
|
|
15428
15604
|
import { spawn } from "child_process";
|
|
15429
|
-
import { mkdir as mkdir4, readFile as
|
|
15605
|
+
import { mkdir as mkdir4, readFile as readFile13, writeFile as writeFile3 } from "fs/promises";
|
|
15430
15606
|
import { dirname as dirname3 } from "path";
|
|
15431
15607
|
function compareSemver(a, b) {
|
|
15432
|
-
const
|
|
15608
|
+
const parse7 = (v) => {
|
|
15433
15609
|
const clean = v.replace(/^v/, "").split("-")[0] ?? "";
|
|
15434
15610
|
const parts = clean.split(".").map((p) => {
|
|
15435
15611
|
const n = parseInt(p, 10);
|
|
@@ -15437,8 +15613,8 @@ function compareSemver(a, b) {
|
|
|
15437
15613
|
});
|
|
15438
15614
|
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
|
|
15439
15615
|
};
|
|
15440
|
-
const [aMaj, aMin, aPat] =
|
|
15441
|
-
const [bMaj, bMin, bPat] =
|
|
15616
|
+
const [aMaj, aMin, aPat] = parse7(a);
|
|
15617
|
+
const [bMaj, bMin, bPat] = parse7(b);
|
|
15442
15618
|
if (aMaj !== bMaj) return aMaj < bMaj ? -1 : 1;
|
|
15443
15619
|
if (aMin !== bMin) return aMin < bMin ? -1 : 1;
|
|
15444
15620
|
if (aPat !== bPat) return aPat < bPat ? -1 : 1;
|
|
@@ -15447,7 +15623,7 @@ function compareSemver(a, b) {
|
|
|
15447
15623
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
15448
15624
|
async function readCache(cachePath) {
|
|
15449
15625
|
try {
|
|
15450
|
-
const raw = await
|
|
15626
|
+
const raw = await readFile13(cachePath, "utf-8");
|
|
15451
15627
|
const parsed = JSON.parse(raw);
|
|
15452
15628
|
if (parsed !== null && typeof parsed === "object" && "checkedAt" in parsed && "latest" in parsed && typeof parsed.checkedAt === "string" && typeof parsed.latest === "string") {
|
|
15453
15629
|
return parsed;
|
|
@@ -15730,7 +15906,9 @@ async function runSingleTurn(prompt) {
|
|
|
15730
15906
|
});
|
|
15731
15907
|
const tools = new ToolRegistry();
|
|
15732
15908
|
for (const tool2 of createDocTools({ cwd })) {
|
|
15733
|
-
|
|
15909
|
+
const t = tool2;
|
|
15910
|
+
if (t.requiresApproval) continue;
|
|
15911
|
+
tools.register(t);
|
|
15734
15912
|
}
|
|
15735
15913
|
for (const mcpTool of mcpManager.getToolDefinitions()) {
|
|
15736
15914
|
tools.register(mcpTool);
|