opencode-gbk-tools 0.1.22 → 0.1.23
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/opencode-tools/gbk_edit.js +56 -30
- package/dist/opencode-tools/gbk_read.js +3 -3
- package/dist/opencode-tools/gbk_search.js +3 -3
- package/dist/opencode-tools/gbk_write.js +2 -2
- package/dist/opencode-tools/text_edit.js +36 -10
- package/dist/plugin/index.js +95 -42
- package/dist/plugins/opencode-gbk-tools.js +95 -42
- package/dist/release-manifest.json +2 -2
- package/package.json +1 -1
|
@@ -16307,29 +16307,40 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16307
16307
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16308
16308
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16309
16309
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16310
|
+
var ANSI_RED = "\x1B[31m";
|
|
16311
|
+
var ANSI_GREEN = "\x1B[32m";
|
|
16312
|
+
var ANSI_DIM = "\x1B[2m";
|
|
16313
|
+
var ANSI_RESET = "\x1B[0m";
|
|
16314
|
+
var MAX_DIFF_LINES = 80;
|
|
16310
16315
|
function buildGbkLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
16311
16316
|
const beforeLines = normalizeNewlines(beforeText).split("\n");
|
|
16312
16317
|
const afterLines = normalizeNewlines(afterText).split("\n");
|
|
16313
16318
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
16314
|
-
const
|
|
16315
|
-
|
|
16316
|
-
|
|
16319
|
+
const header = [
|
|
16320
|
+
`${ANSI_DIM}--- ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`,
|
|
16321
|
+
`${ANSI_DIM}+++ ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`
|
|
16317
16322
|
];
|
|
16323
|
+
const body = [];
|
|
16318
16324
|
for (let index = 0; index < maxLines; index += 1) {
|
|
16319
16325
|
const before = beforeLines[index];
|
|
16320
16326
|
const after = afterLines[index];
|
|
16321
16327
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
16322
|
-
|
|
16328
|
+
body.push(` ${before}`);
|
|
16323
16329
|
continue;
|
|
16324
16330
|
}
|
|
16325
16331
|
if (before !== void 0) {
|
|
16326
|
-
|
|
16332
|
+
body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
|
|
16327
16333
|
}
|
|
16328
16334
|
if (after !== void 0) {
|
|
16329
|
-
|
|
16335
|
+
body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
|
|
16330
16336
|
}
|
|
16331
16337
|
}
|
|
16332
|
-
|
|
16338
|
+
if (header.length + body.length <= MAX_DIFF_LINES) {
|
|
16339
|
+
return "\n" + [...header, ...body].join("\n");
|
|
16340
|
+
}
|
|
16341
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
|
|
16342
|
+
const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
|
|
16343
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
16333
16344
|
}
|
|
16334
16345
|
function toSafeNumber(value) {
|
|
16335
16346
|
return typeof value === "bigint" ? Number(value) : value;
|
|
@@ -16353,10 +16364,10 @@ function assertInsertArguments(input) {
|
|
|
16353
16364
|
throw createGbkError("GBK_INVALID_ARGUMENT", "content \u4E0D\u80FD\u4E3A\u7A7A");
|
|
16354
16365
|
}
|
|
16355
16366
|
if (input.replaceAll !== void 0) {
|
|
16356
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16367
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? replaceAll");
|
|
16357
16368
|
}
|
|
16358
16369
|
if (input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0) {
|
|
16359
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16370
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? startLine/endLine/startAnchor/endAnchor");
|
|
16360
16371
|
}
|
|
16361
16372
|
}
|
|
16362
16373
|
function findOccurrenceIndex(text, token, occurrence) {
|
|
@@ -16380,9 +16391,9 @@ function findOccurrenceIndex(text, token, occurrence) {
|
|
|
16380
16391
|
searchFrom = index + token.length;
|
|
16381
16392
|
}
|
|
16382
16393
|
if (count === 0) {
|
|
16383
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
16394
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${token}`);
|
|
16384
16395
|
}
|
|
16385
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD
|
|
16396
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD? ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${occurrence} \u5904`);
|
|
16386
16397
|
}
|
|
16387
16398
|
function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
16388
16399
|
const alignedContent = newlineStyle === "crlf" ? content.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : newlineStyle === "lf" ? content.replace(/\r\n/g, "\n") : content;
|
|
@@ -16391,7 +16402,7 @@ function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newli
|
|
|
16391
16402
|
const alreadyExists = mode === "insertAfter" ? text.slice(insertionPoint, insertionPoint + alignedContent.length) === alignedContent : text.slice(Math.max(0, insertionPoint - alignedContent.length), insertionPoint) === alignedContent;
|
|
16392
16403
|
if (alreadyExists) {
|
|
16393
16404
|
if (ifExists === "error") {
|
|
16394
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
16405
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
16395
16406
|
}
|
|
16396
16407
|
if (ifExists === "skip") {
|
|
16397
16408
|
return {
|
|
@@ -16432,7 +16443,7 @@ function normalizeOptionalPositiveInteger(value, name) {
|
|
|
16432
16443
|
}
|
|
16433
16444
|
function assertNotBinary(buffer) {
|
|
16434
16445
|
if (buffer.includes(0)) {
|
|
16435
|
-
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD
|
|
16446
|
+
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
|
|
16436
16447
|
}
|
|
16437
16448
|
}
|
|
16438
16449
|
function detectNewlineStyle(text) {
|
|
@@ -16513,14 +16524,14 @@ function applyAnchors(text, startAnchor, endAnchor) {
|
|
|
16513
16524
|
if (startAnchor) {
|
|
16514
16525
|
const found = text.indexOf(startAnchor);
|
|
16515
16526
|
if (found === -1) {
|
|
16516
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD
|
|
16527
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD?: ${startAnchor}`);
|
|
16517
16528
|
}
|
|
16518
16529
|
rangeStart = found + startAnchor.length;
|
|
16519
16530
|
}
|
|
16520
16531
|
if (endAnchor) {
|
|
16521
16532
|
const found = text.indexOf(endAnchor, rangeStart);
|
|
16522
16533
|
if (found === -1) {
|
|
16523
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD
|
|
16534
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD?: ${endAnchor}`);
|
|
16524
16535
|
}
|
|
16525
16536
|
rangeEnd = found;
|
|
16526
16537
|
}
|
|
@@ -16573,9 +16584,9 @@ function getNearestContext(content, oldString) {
|
|
|
16573
16584
|
}
|
|
16574
16585
|
function buildNoMatchMessage(content, oldString) {
|
|
16575
16586
|
return [
|
|
16576
|
-
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD
|
|
16577
|
-
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD
|
|
16578
|
-
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD
|
|
16587
|
+
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD?",
|
|
16588
|
+
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD?/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\uFFFD?",
|
|
16589
|
+
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD?",
|
|
16579
16590
|
getNearestContext(content, oldString)
|
|
16580
16591
|
].join("\n");
|
|
16581
16592
|
}
|
|
@@ -16698,10 +16709,10 @@ async function resolveReadableGbkFile(input) {
|
|
|
16698
16709
|
try {
|
|
16699
16710
|
stat = await fs2.stat(candidatePath);
|
|
16700
16711
|
} catch (error45) {
|
|
16701
|
-
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD
|
|
16712
|
+
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
|
|
16702
16713
|
}
|
|
16703
16714
|
if (stat.isDirectory()) {
|
|
16704
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16715
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16705
16716
|
}
|
|
16706
16717
|
return {
|
|
16707
16718
|
filePath: candidatePath,
|
|
@@ -16898,7 +16909,7 @@ function replaceScopedTextContent(scopeText, oldString, newString, replaceAll, n
|
|
|
16898
16909
|
} else if (occurrencesBefore === 0) {
|
|
16899
16910
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scopeText, oldString));
|
|
16900
16911
|
} else if (occurrencesBefore > 1) {
|
|
16901
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
16912
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${oldString}`);
|
|
16902
16913
|
}
|
|
16903
16914
|
const alignedNewString = alignTextToNewlineStyle(newString, newlineStyle);
|
|
16904
16915
|
return {
|
|
@@ -17003,7 +17014,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17003
17014
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17004
17015
|
if (alreadyExists) {
|
|
17005
17016
|
if (input.ifExists === "error") {
|
|
17006
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17017
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17007
17018
|
}
|
|
17008
17019
|
if (input.ifExists === "skip") {
|
|
17009
17020
|
skipped = true;
|
|
@@ -17050,7 +17061,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17050
17061
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17051
17062
|
if (alreadyExists) {
|
|
17052
17063
|
if (input.ifExists === "error") {
|
|
17053
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17064
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17054
17065
|
}
|
|
17055
17066
|
if (input.ifExists === "skip") {
|
|
17056
17067
|
skipped = true;
|
|
@@ -17064,10 +17075,10 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17064
17075
|
}
|
|
17065
17076
|
}
|
|
17066
17077
|
if (!inserted && totalMatches === 0) {
|
|
17067
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
17078
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${input.anchor}`);
|
|
17068
17079
|
}
|
|
17069
17080
|
if (!inserted && totalMatches > 0) {
|
|
17070
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD
|
|
17081
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD? ${totalMatches} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${input.occurrence} \u5904`);
|
|
17071
17082
|
}
|
|
17072
17083
|
await finalizeInserted();
|
|
17073
17084
|
await handle.close();
|
|
@@ -17130,10 +17141,10 @@ async function replaceLargeGbkFileText(input) {
|
|
|
17130
17141
|
});
|
|
17131
17142
|
await flushText("", true);
|
|
17132
17143
|
if (occurrencesBefore === 0) {
|
|
17133
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD
|
|
17144
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD?: ${input.oldString}`);
|
|
17134
17145
|
}
|
|
17135
17146
|
if (!input.replaceAll && occurrencesBefore > 1) {
|
|
17136
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17147
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${input.oldString}`);
|
|
17137
17148
|
}
|
|
17138
17149
|
await handle.close();
|
|
17139
17150
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
@@ -17282,7 +17293,7 @@ async function replaceGbkFileText(input) {
|
|
|
17282
17293
|
} else if (occurrencesBefore === 0) {
|
|
17283
17294
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, effectiveOldString));
|
|
17284
17295
|
} else if (occurrencesBefore > 1) {
|
|
17285
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17296
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${effectiveOldString}`);
|
|
17286
17297
|
}
|
|
17287
17298
|
const fileNewlineStyle = detectNewlineStyle(current.content);
|
|
17288
17299
|
const alignedNewString = fileNewlineStyle === "crlf" ? input.newString.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : fileNewlineStyle === "lf" ? input.newString.replace(/\r\n/g, "\n") : input.newString;
|
|
@@ -17303,7 +17314,22 @@ async function replaceGbkFileText(input) {
|
|
|
17303
17314
|
};
|
|
17304
17315
|
}
|
|
17305
17316
|
|
|
17317
|
+
// src/lib/model-context.ts
|
|
17318
|
+
var _currentContextTokens = null;
|
|
17319
|
+
function getMaxOutputChars(fallback = 8e3) {
|
|
17320
|
+
if (_currentContextTokens === null) return fallback;
|
|
17321
|
+
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17322
|
+
return Math.max(4e3, Math.min(32e3, computed));
|
|
17323
|
+
}
|
|
17324
|
+
|
|
17306
17325
|
// src/tools/gbk_edit.ts
|
|
17326
|
+
function truncateToolOutput(content) {
|
|
17327
|
+
const maxChars = getMaxOutputChars();
|
|
17328
|
+
if (content.length <= maxChars) return content;
|
|
17329
|
+
const truncated = content.slice(0, maxChars);
|
|
17330
|
+
return truncated + `
|
|
17331
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17332
|
+
}
|
|
17307
17333
|
var gbk_edit_default = tool({
|
|
17308
17334
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17309
17335
|
|
|
@@ -17373,8 +17399,8 @@ Insert mode:
|
|
|
17373
17399
|
diffPreview
|
|
17374
17400
|
}
|
|
17375
17401
|
});
|
|
17376
|
-
if (diffPreview) return diffPreview;
|
|
17377
|
-
return JSON.stringify(result, null, 2);
|
|
17402
|
+
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17403
|
+
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17378
17404
|
}
|
|
17379
17405
|
});
|
|
17380
17406
|
export {
|
|
@@ -16329,7 +16329,7 @@ function normalizeOptionalPositiveInteger(value, name) {
|
|
|
16329
16329
|
}
|
|
16330
16330
|
function assertNotBinary(buffer) {
|
|
16331
16331
|
if (buffer.includes(0)) {
|
|
16332
|
-
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD
|
|
16332
|
+
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
|
|
16333
16333
|
}
|
|
16334
16334
|
}
|
|
16335
16335
|
function splitLinesWithNumbers(text, offset = 1, limit = 2e3) {
|
|
@@ -16420,10 +16420,10 @@ async function resolveReadableGbkFile(input) {
|
|
|
16420
16420
|
try {
|
|
16421
16421
|
stat = await fs2.stat(candidatePath);
|
|
16422
16422
|
} catch (error45) {
|
|
16423
|
-
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD
|
|
16423
|
+
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
|
|
16424
16424
|
}
|
|
16425
16425
|
if (stat.isDirectory()) {
|
|
16426
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16426
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16427
16427
|
}
|
|
16428
16428
|
return {
|
|
16429
16429
|
filePath: candidatePath,
|
|
@@ -16313,7 +16313,7 @@ function assertEncodingSupported(encoding) {
|
|
|
16313
16313
|
}
|
|
16314
16314
|
function assertNotBinary(buffer) {
|
|
16315
16315
|
if (buffer.includes(0)) {
|
|
16316
|
-
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD
|
|
16316
|
+
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
|
|
16317
16317
|
}
|
|
16318
16318
|
}
|
|
16319
16319
|
async function resolveReadableGbkFile(input) {
|
|
@@ -16324,10 +16324,10 @@ async function resolveReadableGbkFile(input) {
|
|
|
16324
16324
|
try {
|
|
16325
16325
|
stat = await fs2.stat(candidatePath);
|
|
16326
16326
|
} catch (error45) {
|
|
16327
|
-
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD
|
|
16327
|
+
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
|
|
16328
16328
|
}
|
|
16329
16329
|
if (stat.isDirectory()) {
|
|
16330
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16330
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16331
16331
|
}
|
|
16332
16332
|
return {
|
|
16333
16333
|
filePath: candidatePath,
|
|
@@ -16370,10 +16370,10 @@ async function writeGbkFile(input) {
|
|
|
16370
16370
|
try {
|
|
16371
16371
|
const stat = await fs2.stat(candidatePath);
|
|
16372
16372
|
if (stat.isDirectory()) {
|
|
16373
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16373
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16374
16374
|
}
|
|
16375
16375
|
if (!overwrite) {
|
|
16376
|
-
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD
|
|
16376
|
+
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD?: ${candidatePath}`);
|
|
16377
16377
|
}
|
|
16378
16378
|
} catch (error45) {
|
|
16379
16379
|
if (error45 instanceof Error && "code" in error45) {
|
|
@@ -16577,29 +16577,40 @@ function assertInsertArguments(input) {
|
|
|
16577
16577
|
throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 startLine/endLine/startAnchor/endAnchor");
|
|
16578
16578
|
}
|
|
16579
16579
|
}
|
|
16580
|
+
var ANSI_RED = "\x1B[31m";
|
|
16581
|
+
var ANSI_GREEN = "\x1B[32m";
|
|
16582
|
+
var ANSI_DIM = "\x1B[2m";
|
|
16583
|
+
var ANSI_RESET = "\x1B[0m";
|
|
16584
|
+
var MAX_DIFF_LINES = 80;
|
|
16580
16585
|
function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
16581
16586
|
const beforeLines = normalizeNewlines(beforeText).split("\n");
|
|
16582
16587
|
const afterLines = normalizeNewlines(afterText).split("\n");
|
|
16583
16588
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
16584
|
-
const
|
|
16585
|
-
|
|
16586
|
-
|
|
16589
|
+
const header = [
|
|
16590
|
+
`${ANSI_DIM}--- ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`,
|
|
16591
|
+
`${ANSI_DIM}+++ ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`
|
|
16587
16592
|
];
|
|
16593
|
+
const body = [];
|
|
16588
16594
|
for (let index = 0; index < maxLines; index += 1) {
|
|
16589
16595
|
const before = beforeLines[index];
|
|
16590
16596
|
const after = afterLines[index];
|
|
16591
16597
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
16592
|
-
|
|
16598
|
+
body.push(` ${before}`);
|
|
16593
16599
|
continue;
|
|
16594
16600
|
}
|
|
16595
16601
|
if (before !== void 0) {
|
|
16596
|
-
|
|
16602
|
+
body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
|
|
16597
16603
|
}
|
|
16598
16604
|
if (after !== void 0) {
|
|
16599
|
-
|
|
16605
|
+
body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
|
|
16600
16606
|
}
|
|
16601
16607
|
}
|
|
16602
|
-
|
|
16608
|
+
if (header.length + body.length <= MAX_DIFF_LINES) {
|
|
16609
|
+
return "\n" + [...header, ...body].join("\n");
|
|
16610
|
+
}
|
|
16611
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
|
|
16612
|
+
const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
|
|
16613
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
16603
16614
|
}
|
|
16604
16615
|
function buildInsertOutput(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
16605
16616
|
const alignedContent = alignTextToNewlineStyle(content, newlineStyle);
|
|
@@ -16975,11 +16986,26 @@ async function replaceTextFileText(input) {
|
|
|
16975
16986
|
bytesRead: loaded.bytesRead,
|
|
16976
16987
|
bytesWritten: buffer.byteLength,
|
|
16977
16988
|
newlineStyle: detectNewlineStyle(outputText),
|
|
16978
|
-
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding,
|
|
16989
|
+
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding, input.oldString, alignedNewString)
|
|
16979
16990
|
};
|
|
16980
16991
|
}
|
|
16981
16992
|
|
|
16993
|
+
// src/lib/model-context.ts
|
|
16994
|
+
var _currentContextTokens = null;
|
|
16995
|
+
function getMaxOutputChars(fallback = 8e3) {
|
|
16996
|
+
if (_currentContextTokens === null) return fallback;
|
|
16997
|
+
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
16998
|
+
return Math.max(4e3, Math.min(32e3, computed));
|
|
16999
|
+
}
|
|
17000
|
+
|
|
16982
17001
|
// src/tools/text_edit.ts
|
|
17002
|
+
function truncateToolOutput(content) {
|
|
17003
|
+
const maxChars = getMaxOutputChars();
|
|
17004
|
+
if (content.length <= maxChars) return content;
|
|
17005
|
+
const truncated = content.slice(0, maxChars);
|
|
17006
|
+
return truncated + `
|
|
17007
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17008
|
+
}
|
|
16983
17009
|
var text_edit_default = tool({
|
|
16984
17010
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
16985
17011
|
|
|
@@ -17030,8 +17056,8 @@ var text_edit_default = tool({
|
|
|
17030
17056
|
diffPreview
|
|
17031
17057
|
}
|
|
17032
17058
|
});
|
|
17033
|
-
if (diffPreview) return diffPreview;
|
|
17034
|
-
return JSON.stringify(result, null, 2);
|
|
17059
|
+
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17060
|
+
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17035
17061
|
}
|
|
17036
17062
|
});
|
|
17037
17063
|
export {
|
package/dist/plugin/index.js
CHANGED
|
@@ -16308,29 +16308,40 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16308
16308
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16309
16309
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16310
16310
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16311
|
+
var ANSI_RED = "\x1B[31m";
|
|
16312
|
+
var ANSI_GREEN = "\x1B[32m";
|
|
16313
|
+
var ANSI_DIM = "\x1B[2m";
|
|
16314
|
+
var ANSI_RESET = "\x1B[0m";
|
|
16315
|
+
var MAX_DIFF_LINES = 80;
|
|
16311
16316
|
function buildGbkLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
16312
16317
|
const beforeLines = normalizeNewlines(beforeText).split("\n");
|
|
16313
16318
|
const afterLines = normalizeNewlines(afterText).split("\n");
|
|
16314
16319
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
16315
|
-
const
|
|
16316
|
-
|
|
16317
|
-
|
|
16320
|
+
const header = [
|
|
16321
|
+
`${ANSI_DIM}--- ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`,
|
|
16322
|
+
`${ANSI_DIM}+++ ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`
|
|
16318
16323
|
];
|
|
16324
|
+
const body = [];
|
|
16319
16325
|
for (let index = 0; index < maxLines; index += 1) {
|
|
16320
16326
|
const before = beforeLines[index];
|
|
16321
16327
|
const after = afterLines[index];
|
|
16322
16328
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
16323
|
-
|
|
16329
|
+
body.push(` ${before}`);
|
|
16324
16330
|
continue;
|
|
16325
16331
|
}
|
|
16326
16332
|
if (before !== void 0) {
|
|
16327
|
-
|
|
16333
|
+
body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
|
|
16328
16334
|
}
|
|
16329
16335
|
if (after !== void 0) {
|
|
16330
|
-
|
|
16336
|
+
body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
|
|
16331
16337
|
}
|
|
16332
16338
|
}
|
|
16333
|
-
|
|
16339
|
+
if (header.length + body.length <= MAX_DIFF_LINES) {
|
|
16340
|
+
return "\n" + [...header, ...body].join("\n");
|
|
16341
|
+
}
|
|
16342
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
|
|
16343
|
+
const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
|
|
16344
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
16334
16345
|
}
|
|
16335
16346
|
function toSafeNumber(value) {
|
|
16336
16347
|
return typeof value === "bigint" ? Number(value) : value;
|
|
@@ -16354,10 +16365,10 @@ function assertInsertArguments(input) {
|
|
|
16354
16365
|
throw createGbkError("GBK_INVALID_ARGUMENT", "content \u4E0D\u80FD\u4E3A\u7A7A");
|
|
16355
16366
|
}
|
|
16356
16367
|
if (input.replaceAll !== void 0) {
|
|
16357
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16368
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? replaceAll");
|
|
16358
16369
|
}
|
|
16359
16370
|
if (input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0) {
|
|
16360
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16371
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? startLine/endLine/startAnchor/endAnchor");
|
|
16361
16372
|
}
|
|
16362
16373
|
}
|
|
16363
16374
|
function findOccurrenceIndex(text, token, occurrence) {
|
|
@@ -16381,9 +16392,9 @@ function findOccurrenceIndex(text, token, occurrence) {
|
|
|
16381
16392
|
searchFrom = index + token.length;
|
|
16382
16393
|
}
|
|
16383
16394
|
if (count === 0) {
|
|
16384
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
16395
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${token}`);
|
|
16385
16396
|
}
|
|
16386
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD
|
|
16397
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD? ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${occurrence} \u5904`);
|
|
16387
16398
|
}
|
|
16388
16399
|
function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
16389
16400
|
const alignedContent = newlineStyle === "crlf" ? content.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : newlineStyle === "lf" ? content.replace(/\r\n/g, "\n") : content;
|
|
@@ -16392,7 +16403,7 @@ function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newli
|
|
|
16392
16403
|
const alreadyExists = mode === "insertAfter" ? text.slice(insertionPoint, insertionPoint + alignedContent.length) === alignedContent : text.slice(Math.max(0, insertionPoint - alignedContent.length), insertionPoint) === alignedContent;
|
|
16393
16404
|
if (alreadyExists) {
|
|
16394
16405
|
if (ifExists === "error") {
|
|
16395
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
16406
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
16396
16407
|
}
|
|
16397
16408
|
if (ifExists === "skip") {
|
|
16398
16409
|
return {
|
|
@@ -16433,7 +16444,7 @@ function normalizeOptionalPositiveInteger(value, name) {
|
|
|
16433
16444
|
}
|
|
16434
16445
|
function assertNotBinary(buffer) {
|
|
16435
16446
|
if (buffer.includes(0)) {
|
|
16436
|
-
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD
|
|
16447
|
+
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
|
|
16437
16448
|
}
|
|
16438
16449
|
}
|
|
16439
16450
|
function splitLinesWithNumbers(text, offset = 1, limit = 2e3) {
|
|
@@ -16563,14 +16574,14 @@ function applyAnchors(text, startAnchor, endAnchor) {
|
|
|
16563
16574
|
if (startAnchor) {
|
|
16564
16575
|
const found = text.indexOf(startAnchor);
|
|
16565
16576
|
if (found === -1) {
|
|
16566
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD
|
|
16577
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD?: ${startAnchor}`);
|
|
16567
16578
|
}
|
|
16568
16579
|
rangeStart = found + startAnchor.length;
|
|
16569
16580
|
}
|
|
16570
16581
|
if (endAnchor) {
|
|
16571
16582
|
const found = text.indexOf(endAnchor, rangeStart);
|
|
16572
16583
|
if (found === -1) {
|
|
16573
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD
|
|
16584
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD?: ${endAnchor}`);
|
|
16574
16585
|
}
|
|
16575
16586
|
rangeEnd = found;
|
|
16576
16587
|
}
|
|
@@ -16623,9 +16634,9 @@ function getNearestContext(content, oldString) {
|
|
|
16623
16634
|
}
|
|
16624
16635
|
function buildNoMatchMessage(content, oldString) {
|
|
16625
16636
|
return [
|
|
16626
|
-
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD
|
|
16627
|
-
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD
|
|
16628
|
-
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD
|
|
16637
|
+
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD?",
|
|
16638
|
+
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD?/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\uFFFD?",
|
|
16639
|
+
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD?",
|
|
16629
16640
|
getNearestContext(content, oldString)
|
|
16630
16641
|
].join("\n");
|
|
16631
16642
|
}
|
|
@@ -16748,10 +16759,10 @@ async function resolveReadableGbkFile(input) {
|
|
|
16748
16759
|
try {
|
|
16749
16760
|
stat = await fs2.stat(candidatePath);
|
|
16750
16761
|
} catch (error45) {
|
|
16751
|
-
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD
|
|
16762
|
+
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
|
|
16752
16763
|
}
|
|
16753
16764
|
if (stat.isDirectory()) {
|
|
16754
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16765
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16755
16766
|
}
|
|
16756
16767
|
return {
|
|
16757
16768
|
filePath: candidatePath,
|
|
@@ -16956,7 +16967,7 @@ function replaceScopedTextContent(scopeText, oldString, newString, replaceAll, n
|
|
|
16956
16967
|
} else if (occurrencesBefore === 0) {
|
|
16957
16968
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scopeText, oldString));
|
|
16958
16969
|
} else if (occurrencesBefore > 1) {
|
|
16959
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
16970
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${oldString}`);
|
|
16960
16971
|
}
|
|
16961
16972
|
const alignedNewString = alignTextToNewlineStyle(newString, newlineStyle);
|
|
16962
16973
|
return {
|
|
@@ -17061,7 +17072,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17061
17072
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17062
17073
|
if (alreadyExists) {
|
|
17063
17074
|
if (input.ifExists === "error") {
|
|
17064
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17075
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17065
17076
|
}
|
|
17066
17077
|
if (input.ifExists === "skip") {
|
|
17067
17078
|
skipped = true;
|
|
@@ -17108,7 +17119,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17108
17119
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17109
17120
|
if (alreadyExists) {
|
|
17110
17121
|
if (input.ifExists === "error") {
|
|
17111
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17122
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17112
17123
|
}
|
|
17113
17124
|
if (input.ifExists === "skip") {
|
|
17114
17125
|
skipped = true;
|
|
@@ -17122,10 +17133,10 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17122
17133
|
}
|
|
17123
17134
|
}
|
|
17124
17135
|
if (!inserted && totalMatches === 0) {
|
|
17125
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
17136
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${input.anchor}`);
|
|
17126
17137
|
}
|
|
17127
17138
|
if (!inserted && totalMatches > 0) {
|
|
17128
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD
|
|
17139
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD? ${totalMatches} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${input.occurrence} \u5904`);
|
|
17129
17140
|
}
|
|
17130
17141
|
await finalizeInserted();
|
|
17131
17142
|
await handle.close();
|
|
@@ -17188,10 +17199,10 @@ async function replaceLargeGbkFileText(input) {
|
|
|
17188
17199
|
});
|
|
17189
17200
|
await flushText("", true);
|
|
17190
17201
|
if (occurrencesBefore === 0) {
|
|
17191
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD
|
|
17202
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD?: ${input.oldString}`);
|
|
17192
17203
|
}
|
|
17193
17204
|
if (!input.replaceAll && occurrencesBefore > 1) {
|
|
17194
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17205
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${input.oldString}`);
|
|
17195
17206
|
}
|
|
17196
17207
|
await handle.close();
|
|
17197
17208
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
@@ -17417,7 +17428,7 @@ async function replaceGbkFileText(input) {
|
|
|
17417
17428
|
} else if (occurrencesBefore === 0) {
|
|
17418
17429
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, effectiveOldString));
|
|
17419
17430
|
} else if (occurrencesBefore > 1) {
|
|
17420
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17431
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${effectiveOldString}`);
|
|
17421
17432
|
}
|
|
17422
17433
|
const fileNewlineStyle = detectNewlineStyle(current.content);
|
|
17423
17434
|
const alignedNewString = fileNewlineStyle === "crlf" ? input.newString.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : fileNewlineStyle === "lf" ? input.newString.replace(/\r\n/g, "\n") : input.newString;
|
|
@@ -17550,10 +17561,10 @@ async function writeGbkFile(input) {
|
|
|
17550
17561
|
try {
|
|
17551
17562
|
const stat = await fs2.stat(candidatePath);
|
|
17552
17563
|
if (stat.isDirectory()) {
|
|
17553
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
17564
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
17554
17565
|
}
|
|
17555
17566
|
if (!overwrite) {
|
|
17556
|
-
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD
|
|
17567
|
+
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD?: ${candidatePath}`);
|
|
17557
17568
|
}
|
|
17558
17569
|
} catch (error45) {
|
|
17559
17570
|
if (error45 instanceof Error && "code" in error45) {
|
|
@@ -17599,7 +17610,25 @@ async function writeGbkFile(input) {
|
|
|
17599
17610
|
}
|
|
17600
17611
|
}
|
|
17601
17612
|
|
|
17613
|
+
// src/lib/model-context.ts
|
|
17614
|
+
var _currentContextTokens = null;
|
|
17615
|
+
function setCurrentContextTokens(tokens) {
|
|
17616
|
+
_currentContextTokens = tokens;
|
|
17617
|
+
}
|
|
17618
|
+
function getMaxOutputChars(fallback = 8e3) {
|
|
17619
|
+
if (_currentContextTokens === null) return fallback;
|
|
17620
|
+
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17621
|
+
return Math.max(4e3, Math.min(32e3, computed));
|
|
17622
|
+
}
|
|
17623
|
+
|
|
17602
17624
|
// src/tools/gbk_edit.ts
|
|
17625
|
+
function truncateToolOutput(content) {
|
|
17626
|
+
const maxChars = getMaxOutputChars();
|
|
17627
|
+
if (content.length <= maxChars) return content;
|
|
17628
|
+
const truncated = content.slice(0, maxChars);
|
|
17629
|
+
return truncated + `
|
|
17630
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17631
|
+
}
|
|
17603
17632
|
var gbk_edit_default = tool({
|
|
17604
17633
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17605
17634
|
|
|
@@ -17669,8 +17698,8 @@ Insert mode:
|
|
|
17669
17698
|
diffPreview
|
|
17670
17699
|
}
|
|
17671
17700
|
});
|
|
17672
|
-
if (diffPreview) return diffPreview;
|
|
17673
|
-
return JSON.stringify(result, null, 2);
|
|
17701
|
+
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17702
|
+
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17674
17703
|
}
|
|
17675
17704
|
});
|
|
17676
17705
|
|
|
@@ -18051,29 +18080,40 @@ function assertInsertArguments2(input) {
|
|
|
18051
18080
|
throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 startLine/endLine/startAnchor/endAnchor");
|
|
18052
18081
|
}
|
|
18053
18082
|
}
|
|
18083
|
+
var ANSI_RED2 = "\x1B[31m";
|
|
18084
|
+
var ANSI_GREEN2 = "\x1B[32m";
|
|
18085
|
+
var ANSI_DIM2 = "\x1B[2m";
|
|
18086
|
+
var ANSI_RESET2 = "\x1B[0m";
|
|
18087
|
+
var MAX_DIFF_LINES2 = 80;
|
|
18054
18088
|
function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
18055
18089
|
const beforeLines = normalizeNewlines2(beforeText).split("\n");
|
|
18056
18090
|
const afterLines = normalizeNewlines2(afterText).split("\n");
|
|
18057
18091
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
18058
|
-
const
|
|
18059
|
-
|
|
18060
|
-
|
|
18092
|
+
const header = [
|
|
18093
|
+
`${ANSI_DIM2}--- ${path3.basename(filePath)} (${encoding})${ANSI_RESET2}`,
|
|
18094
|
+
`${ANSI_DIM2}+++ ${path3.basename(filePath)} (${encoding})${ANSI_RESET2}`
|
|
18061
18095
|
];
|
|
18096
|
+
const body = [];
|
|
18062
18097
|
for (let index = 0; index < maxLines; index += 1) {
|
|
18063
18098
|
const before = beforeLines[index];
|
|
18064
18099
|
const after = afterLines[index];
|
|
18065
18100
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
18066
|
-
|
|
18101
|
+
body.push(` ${before}`);
|
|
18067
18102
|
continue;
|
|
18068
18103
|
}
|
|
18069
18104
|
if (before !== void 0) {
|
|
18070
|
-
|
|
18105
|
+
body.push(`${ANSI_RED2}-${before}${ANSI_RESET2}`);
|
|
18071
18106
|
}
|
|
18072
18107
|
if (after !== void 0) {
|
|
18073
|
-
|
|
18108
|
+
body.push(`${ANSI_GREEN2}+${after}${ANSI_RESET2}`);
|
|
18074
18109
|
}
|
|
18075
18110
|
}
|
|
18076
|
-
|
|
18111
|
+
if (header.length + body.length <= MAX_DIFF_LINES2) {
|
|
18112
|
+
return "\n" + [...header, ...body].join("\n");
|
|
18113
|
+
}
|
|
18114
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED2) || l.startsWith(ANSI_GREEN2));
|
|
18115
|
+
const notice = `${ANSI_DIM2}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET2}`;
|
|
18116
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
18077
18117
|
}
|
|
18078
18118
|
function buildInsertOutput(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
18079
18119
|
const alignedContent = alignTextToNewlineStyle2(content, newlineStyle);
|
|
@@ -18720,11 +18760,18 @@ async function replaceTextFileText(input) {
|
|
|
18720
18760
|
bytesRead: loaded.bytesRead,
|
|
18721
18761
|
bytesWritten: buffer.byteLength,
|
|
18722
18762
|
newlineStyle: detectNewlineStyle(outputText),
|
|
18723
|
-
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding,
|
|
18763
|
+
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding, input.oldString, alignedNewString)
|
|
18724
18764
|
};
|
|
18725
18765
|
}
|
|
18726
18766
|
|
|
18727
18767
|
// src/tools/text_edit.ts
|
|
18768
|
+
function truncateToolOutput2(content) {
|
|
18769
|
+
const maxChars = getMaxOutputChars();
|
|
18770
|
+
if (content.length <= maxChars) return content;
|
|
18771
|
+
const truncated = content.slice(0, maxChars);
|
|
18772
|
+
return truncated + `
|
|
18773
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
18774
|
+
}
|
|
18728
18775
|
var text_edit_default = tool({
|
|
18729
18776
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
18730
18777
|
|
|
@@ -18775,8 +18822,8 @@ var text_edit_default = tool({
|
|
|
18775
18822
|
diffPreview
|
|
18776
18823
|
}
|
|
18777
18824
|
});
|
|
18778
|
-
if (diffPreview) return diffPreview;
|
|
18779
|
-
return JSON.stringify(result, null, 2);
|
|
18825
|
+
if (diffPreview) return truncateToolOutput2(diffPreview);
|
|
18826
|
+
return truncateToolOutput2(JSON.stringify(result, null, 2));
|
|
18780
18827
|
}
|
|
18781
18828
|
});
|
|
18782
18829
|
|
|
@@ -18868,6 +18915,12 @@ function createOpencodeGbkHooks() {
|
|
|
18868
18915
|
text_write: text_write_default,
|
|
18869
18916
|
text_edit: text_edit_default
|
|
18870
18917
|
},
|
|
18918
|
+
async "chat.params"(input) {
|
|
18919
|
+
const contextTokens = input.model?.limit?.context;
|
|
18920
|
+
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
18921
|
+
setCurrentContextTokens(contextTokens);
|
|
18922
|
+
}
|
|
18923
|
+
},
|
|
18871
18924
|
async "experimental.chat.system.transform"(_input, output) {
|
|
18872
18925
|
appendTextToolSystemPrompt(output.system);
|
|
18873
18926
|
}
|
|
@@ -16308,29 +16308,40 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16308
16308
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16309
16309
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16310
16310
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16311
|
+
var ANSI_RED = "\x1B[31m";
|
|
16312
|
+
var ANSI_GREEN = "\x1B[32m";
|
|
16313
|
+
var ANSI_DIM = "\x1B[2m";
|
|
16314
|
+
var ANSI_RESET = "\x1B[0m";
|
|
16315
|
+
var MAX_DIFF_LINES = 80;
|
|
16311
16316
|
function buildGbkLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
16312
16317
|
const beforeLines = normalizeNewlines(beforeText).split("\n");
|
|
16313
16318
|
const afterLines = normalizeNewlines(afterText).split("\n");
|
|
16314
16319
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
16315
|
-
const
|
|
16316
|
-
|
|
16317
|
-
|
|
16320
|
+
const header = [
|
|
16321
|
+
`${ANSI_DIM}--- ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`,
|
|
16322
|
+
`${ANSI_DIM}+++ ${path2.basename(filePath)} (${encoding})${ANSI_RESET}`
|
|
16318
16323
|
];
|
|
16324
|
+
const body = [];
|
|
16319
16325
|
for (let index = 0; index < maxLines; index += 1) {
|
|
16320
16326
|
const before = beforeLines[index];
|
|
16321
16327
|
const after = afterLines[index];
|
|
16322
16328
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
16323
|
-
|
|
16329
|
+
body.push(` ${before}`);
|
|
16324
16330
|
continue;
|
|
16325
16331
|
}
|
|
16326
16332
|
if (before !== void 0) {
|
|
16327
|
-
|
|
16333
|
+
body.push(`${ANSI_RED}-${before}${ANSI_RESET}`);
|
|
16328
16334
|
}
|
|
16329
16335
|
if (after !== void 0) {
|
|
16330
|
-
|
|
16336
|
+
body.push(`${ANSI_GREEN}+${after}${ANSI_RESET}`);
|
|
16331
16337
|
}
|
|
16332
16338
|
}
|
|
16333
|
-
|
|
16339
|
+
if (header.length + body.length <= MAX_DIFF_LINES) {
|
|
16340
|
+
return "\n" + [...header, ...body].join("\n");
|
|
16341
|
+
}
|
|
16342
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED) || l.startsWith(ANSI_GREEN));
|
|
16343
|
+
const notice = `${ANSI_DIM}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET}`;
|
|
16344
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
16334
16345
|
}
|
|
16335
16346
|
function toSafeNumber(value) {
|
|
16336
16347
|
return typeof value === "bigint" ? Number(value) : value;
|
|
@@ -16354,10 +16365,10 @@ function assertInsertArguments(input) {
|
|
|
16354
16365
|
throw createGbkError("GBK_INVALID_ARGUMENT", "content \u4E0D\u80FD\u4E3A\u7A7A");
|
|
16355
16366
|
}
|
|
16356
16367
|
if (input.replaceAll !== void 0) {
|
|
16357
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16368
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? replaceAll");
|
|
16358
16369
|
}
|
|
16359
16370
|
if (input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0) {
|
|
16360
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD
|
|
16371
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\uFFFD? startLine/endLine/startAnchor/endAnchor");
|
|
16361
16372
|
}
|
|
16362
16373
|
}
|
|
16363
16374
|
function findOccurrenceIndex(text, token, occurrence) {
|
|
@@ -16381,9 +16392,9 @@ function findOccurrenceIndex(text, token, occurrence) {
|
|
|
16381
16392
|
searchFrom = index + token.length;
|
|
16382
16393
|
}
|
|
16383
16394
|
if (count === 0) {
|
|
16384
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
16395
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${token}`);
|
|
16385
16396
|
}
|
|
16386
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD
|
|
16397
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\uFFFD? ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${occurrence} \u5904`);
|
|
16387
16398
|
}
|
|
16388
16399
|
function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
16389
16400
|
const alignedContent = newlineStyle === "crlf" ? content.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : newlineStyle === "lf" ? content.replace(/\r\n/g, "\n") : content;
|
|
@@ -16392,7 +16403,7 @@ function insertByAnchor(text, mode, anchor, content, occurrence, ifExists, newli
|
|
|
16392
16403
|
const alreadyExists = mode === "insertAfter" ? text.slice(insertionPoint, insertionPoint + alignedContent.length) === alignedContent : text.slice(Math.max(0, insertionPoint - alignedContent.length), insertionPoint) === alignedContent;
|
|
16393
16404
|
if (alreadyExists) {
|
|
16394
16405
|
if (ifExists === "error") {
|
|
16395
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
16406
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
16396
16407
|
}
|
|
16397
16408
|
if (ifExists === "skip") {
|
|
16398
16409
|
return {
|
|
@@ -16433,7 +16444,7 @@ function normalizeOptionalPositiveInteger(value, name) {
|
|
|
16433
16444
|
}
|
|
16434
16445
|
function assertNotBinary(buffer) {
|
|
16435
16446
|
if (buffer.includes(0)) {
|
|
16436
|
-
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD
|
|
16447
|
+
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\uFFFD? GBK \u6587\u672C\u5904\u7406");
|
|
16437
16448
|
}
|
|
16438
16449
|
}
|
|
16439
16450
|
function splitLinesWithNumbers(text, offset = 1, limit = 2e3) {
|
|
@@ -16563,14 +16574,14 @@ function applyAnchors(text, startAnchor, endAnchor) {
|
|
|
16563
16574
|
if (startAnchor) {
|
|
16564
16575
|
const found = text.indexOf(startAnchor);
|
|
16565
16576
|
if (found === -1) {
|
|
16566
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD
|
|
16577
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\uFFFD?: ${startAnchor}`);
|
|
16567
16578
|
}
|
|
16568
16579
|
rangeStart = found + startAnchor.length;
|
|
16569
16580
|
}
|
|
16570
16581
|
if (endAnchor) {
|
|
16571
16582
|
const found = text.indexOf(endAnchor, rangeStart);
|
|
16572
16583
|
if (found === -1) {
|
|
16573
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD
|
|
16584
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\uFFFD?: ${endAnchor}`);
|
|
16574
16585
|
}
|
|
16575
16586
|
rangeEnd = found;
|
|
16576
16587
|
}
|
|
@@ -16623,9 +16634,9 @@ function getNearestContext(content, oldString) {
|
|
|
16623
16634
|
}
|
|
16624
16635
|
function buildNoMatchMessage(content, oldString) {
|
|
16625
16636
|
return [
|
|
16626
|
-
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD
|
|
16627
|
-
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD
|
|
16628
|
-
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD
|
|
16637
|
+
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\uFFFD?",
|
|
16638
|
+
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\uFFFD?/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\uFFFD?",
|
|
16639
|
+
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFFFD?",
|
|
16629
16640
|
getNearestContext(content, oldString)
|
|
16630
16641
|
].join("\n");
|
|
16631
16642
|
}
|
|
@@ -16748,10 +16759,10 @@ async function resolveReadableGbkFile(input) {
|
|
|
16748
16759
|
try {
|
|
16749
16760
|
stat = await fs2.stat(candidatePath);
|
|
16750
16761
|
} catch (error45) {
|
|
16751
|
-
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD
|
|
16762
|
+
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\uFFFD?: ${candidatePath}`, error45);
|
|
16752
16763
|
}
|
|
16753
16764
|
if (stat.isDirectory()) {
|
|
16754
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
16765
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
16755
16766
|
}
|
|
16756
16767
|
return {
|
|
16757
16768
|
filePath: candidatePath,
|
|
@@ -16956,7 +16967,7 @@ function replaceScopedTextContent(scopeText, oldString, newString, replaceAll, n
|
|
|
16956
16967
|
} else if (occurrencesBefore === 0) {
|
|
16957
16968
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scopeText, oldString));
|
|
16958
16969
|
} else if (occurrencesBefore > 1) {
|
|
16959
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
16970
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${oldString}`);
|
|
16960
16971
|
}
|
|
16961
16972
|
const alignedNewString = alignTextToNewlineStyle(newString, newlineStyle);
|
|
16962
16973
|
return {
|
|
@@ -17061,7 +17072,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17061
17072
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17062
17073
|
if (alreadyExists) {
|
|
17063
17074
|
if (input.ifExists === "error") {
|
|
17064
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17075
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17065
17076
|
}
|
|
17066
17077
|
if (input.ifExists === "skip") {
|
|
17067
17078
|
skipped = true;
|
|
@@ -17108,7 +17119,7 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17108
17119
|
const alreadyExists = input.mode === "insertAfter" ? after.startsWith(alignedContent) : before.endsWith(alignedContent);
|
|
17109
17120
|
if (alreadyExists) {
|
|
17110
17121
|
if (input.ifExists === "error") {
|
|
17111
|
-
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD
|
|
17122
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\uFFFD?");
|
|
17112
17123
|
}
|
|
17113
17124
|
if (input.ifExists === "skip") {
|
|
17114
17125
|
skipped = true;
|
|
@@ -17122,10 +17133,10 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17122
17133
|
}
|
|
17123
17134
|
}
|
|
17124
17135
|
if (!inserted && totalMatches === 0) {
|
|
17125
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD
|
|
17136
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\uFFFD?: ${input.anchor}`);
|
|
17126
17137
|
}
|
|
17127
17138
|
if (!inserted && totalMatches > 0) {
|
|
17128
|
-
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD
|
|
17139
|
+
throw createGbkError("GBK_NO_MATCH", `\u951A\u70B9 ${input.anchor} \u53EA\u627E\uFFFD? ${totalMatches} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\uFFFD? ${input.occurrence} \u5904`);
|
|
17129
17140
|
}
|
|
17130
17141
|
await finalizeInserted();
|
|
17131
17142
|
await handle.close();
|
|
@@ -17188,10 +17199,10 @@ async function replaceLargeGbkFileText(input) {
|
|
|
17188
17199
|
});
|
|
17189
17200
|
await flushText("", true);
|
|
17190
17201
|
if (occurrencesBefore === 0) {
|
|
17191
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD
|
|
17202
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\uFFFD?: ${input.oldString}`);
|
|
17192
17203
|
}
|
|
17193
17204
|
if (!input.replaceAll && occurrencesBefore > 1) {
|
|
17194
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17205
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${input.oldString}`);
|
|
17195
17206
|
}
|
|
17196
17207
|
await handle.close();
|
|
17197
17208
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
@@ -17417,7 +17428,7 @@ async function replaceGbkFileText(input) {
|
|
|
17417
17428
|
} else if (occurrencesBefore === 0) {
|
|
17418
17429
|
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, effectiveOldString));
|
|
17419
17430
|
} else if (occurrencesBefore > 1) {
|
|
17420
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD
|
|
17431
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\uFFFD?: ${effectiveOldString}`);
|
|
17421
17432
|
}
|
|
17422
17433
|
const fileNewlineStyle = detectNewlineStyle(current.content);
|
|
17423
17434
|
const alignedNewString = fileNewlineStyle === "crlf" ? input.newString.replace(/\r\n/g, "\n").replace(/\n/g, "\r\n") : fileNewlineStyle === "lf" ? input.newString.replace(/\r\n/g, "\n") : input.newString;
|
|
@@ -17550,10 +17561,10 @@ async function writeGbkFile(input) {
|
|
|
17550
17561
|
try {
|
|
17551
17562
|
const stat = await fs2.stat(candidatePath);
|
|
17552
17563
|
if (stat.isDirectory()) {
|
|
17553
|
-
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD
|
|
17564
|
+
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\uFFFD?: ${candidatePath}`);
|
|
17554
17565
|
}
|
|
17555
17566
|
if (!overwrite) {
|
|
17556
|
-
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD
|
|
17567
|
+
throw createGbkError("GBK_FILE_EXISTS", `\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\uFFFD?: ${candidatePath}`);
|
|
17557
17568
|
}
|
|
17558
17569
|
} catch (error45) {
|
|
17559
17570
|
if (error45 instanceof Error && "code" in error45) {
|
|
@@ -17599,7 +17610,25 @@ async function writeGbkFile(input) {
|
|
|
17599
17610
|
}
|
|
17600
17611
|
}
|
|
17601
17612
|
|
|
17613
|
+
// src/lib/model-context.ts
|
|
17614
|
+
var _currentContextTokens = null;
|
|
17615
|
+
function setCurrentContextTokens(tokens) {
|
|
17616
|
+
_currentContextTokens = tokens;
|
|
17617
|
+
}
|
|
17618
|
+
function getMaxOutputChars(fallback = 8e3) {
|
|
17619
|
+
if (_currentContextTokens === null) return fallback;
|
|
17620
|
+
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17621
|
+
return Math.max(4e3, Math.min(32e3, computed));
|
|
17622
|
+
}
|
|
17623
|
+
|
|
17602
17624
|
// src/tools/gbk_edit.ts
|
|
17625
|
+
function truncateToolOutput(content) {
|
|
17626
|
+
const maxChars = getMaxOutputChars();
|
|
17627
|
+
if (content.length <= maxChars) return content;
|
|
17628
|
+
const truncated = content.slice(0, maxChars);
|
|
17629
|
+
return truncated + `
|
|
17630
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17631
|
+
}
|
|
17603
17632
|
var gbk_edit_default = tool({
|
|
17604
17633
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17605
17634
|
|
|
@@ -17669,8 +17698,8 @@ Insert mode:
|
|
|
17669
17698
|
diffPreview
|
|
17670
17699
|
}
|
|
17671
17700
|
});
|
|
17672
|
-
if (diffPreview) return diffPreview;
|
|
17673
|
-
return JSON.stringify(result, null, 2);
|
|
17701
|
+
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17702
|
+
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17674
17703
|
}
|
|
17675
17704
|
});
|
|
17676
17705
|
|
|
@@ -18051,29 +18080,40 @@ function assertInsertArguments2(input) {
|
|
|
18051
18080
|
throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 startLine/endLine/startAnchor/endAnchor");
|
|
18052
18081
|
}
|
|
18053
18082
|
}
|
|
18083
|
+
var ANSI_RED2 = "\x1B[31m";
|
|
18084
|
+
var ANSI_GREEN2 = "\x1B[32m";
|
|
18085
|
+
var ANSI_DIM2 = "\x1B[2m";
|
|
18086
|
+
var ANSI_RESET2 = "\x1B[0m";
|
|
18087
|
+
var MAX_DIFF_LINES2 = 80;
|
|
18054
18088
|
function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
18055
18089
|
const beforeLines = normalizeNewlines2(beforeText).split("\n");
|
|
18056
18090
|
const afterLines = normalizeNewlines2(afterText).split("\n");
|
|
18057
18091
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
18058
|
-
const
|
|
18059
|
-
|
|
18060
|
-
|
|
18092
|
+
const header = [
|
|
18093
|
+
`${ANSI_DIM2}--- ${path3.basename(filePath)} (${encoding})${ANSI_RESET2}`,
|
|
18094
|
+
`${ANSI_DIM2}+++ ${path3.basename(filePath)} (${encoding})${ANSI_RESET2}`
|
|
18061
18095
|
];
|
|
18096
|
+
const body = [];
|
|
18062
18097
|
for (let index = 0; index < maxLines; index += 1) {
|
|
18063
18098
|
const before = beforeLines[index];
|
|
18064
18099
|
const after = afterLines[index];
|
|
18065
18100
|
if (before !== void 0 && after !== void 0 && before === after) {
|
|
18066
|
-
|
|
18101
|
+
body.push(` ${before}`);
|
|
18067
18102
|
continue;
|
|
18068
18103
|
}
|
|
18069
18104
|
if (before !== void 0) {
|
|
18070
|
-
|
|
18105
|
+
body.push(`${ANSI_RED2}-${before}${ANSI_RESET2}`);
|
|
18071
18106
|
}
|
|
18072
18107
|
if (after !== void 0) {
|
|
18073
|
-
|
|
18108
|
+
body.push(`${ANSI_GREEN2}+${after}${ANSI_RESET2}`);
|
|
18074
18109
|
}
|
|
18075
18110
|
}
|
|
18076
|
-
|
|
18111
|
+
if (header.length + body.length <= MAX_DIFF_LINES2) {
|
|
18112
|
+
return "\n" + [...header, ...body].join("\n");
|
|
18113
|
+
}
|
|
18114
|
+
const changedOnly = body.filter((l) => l.startsWith(ANSI_RED2) || l.startsWith(ANSI_GREEN2));
|
|
18115
|
+
const notice = `${ANSI_DIM2}... (\u4E0A\u4E0B\u6587\u5DF2\u7701\u7565\uFF0C\u4EC5\u663E\u793A\u53D8\u66F4\u884C)${ANSI_RESET2}`;
|
|
18116
|
+
return "\n" + [...header, notice, ...changedOnly].join("\n");
|
|
18077
18117
|
}
|
|
18078
18118
|
function buildInsertOutput(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
|
|
18079
18119
|
const alignedContent = alignTextToNewlineStyle2(content, newlineStyle);
|
|
@@ -18720,11 +18760,18 @@ async function replaceTextFileText(input) {
|
|
|
18720
18760
|
bytesRead: loaded.bytesRead,
|
|
18721
18761
|
bytesWritten: buffer.byteLength,
|
|
18722
18762
|
newlineStyle: detectNewlineStyle(outputText),
|
|
18723
|
-
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding,
|
|
18763
|
+
diffPreview: buildLineDiffPreview(loaded.filePath, targetEncoding, input.oldString, alignedNewString)
|
|
18724
18764
|
};
|
|
18725
18765
|
}
|
|
18726
18766
|
|
|
18727
18767
|
// src/tools/text_edit.ts
|
|
18768
|
+
function truncateToolOutput2(content) {
|
|
18769
|
+
const maxChars = getMaxOutputChars();
|
|
18770
|
+
if (content.length <= maxChars) return content;
|
|
18771
|
+
const truncated = content.slice(0, maxChars);
|
|
18772
|
+
return truncated + `
|
|
18773
|
+
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
18774
|
+
}
|
|
18728
18775
|
var text_edit_default = tool({
|
|
18729
18776
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
18730
18777
|
|
|
@@ -18775,8 +18822,8 @@ var text_edit_default = tool({
|
|
|
18775
18822
|
diffPreview
|
|
18776
18823
|
}
|
|
18777
18824
|
});
|
|
18778
|
-
if (diffPreview) return diffPreview;
|
|
18779
|
-
return JSON.stringify(result, null, 2);
|
|
18825
|
+
if (diffPreview) return truncateToolOutput2(diffPreview);
|
|
18826
|
+
return truncateToolOutput2(JSON.stringify(result, null, 2));
|
|
18780
18827
|
}
|
|
18781
18828
|
});
|
|
18782
18829
|
|
|
@@ -18868,6 +18915,12 @@ function createOpencodeGbkHooks() {
|
|
|
18868
18915
|
text_write: text_write_default,
|
|
18869
18916
|
text_edit: text_edit_default
|
|
18870
18917
|
},
|
|
18918
|
+
async "chat.params"(input) {
|
|
18919
|
+
const contextTokens = input.model?.limit?.context;
|
|
18920
|
+
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
18921
|
+
setCurrentContextTokens(contextTokens);
|
|
18922
|
+
}
|
|
18923
|
+
},
|
|
18871
18924
|
async "experimental.chat.system.transform"(_input, output) {
|
|
18872
18925
|
appendTextToolSystemPrompt(output.system);
|
|
18873
18926
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"packageName": "opencode-gbk-tools",
|
|
4
|
-
"packageVersion": "0.1.
|
|
4
|
+
"packageVersion": "0.1.23",
|
|
5
5
|
"artifacts": [
|
|
6
6
|
{
|
|
7
7
|
"relativePath": "plugins/opencode-gbk-tools.js",
|
|
8
8
|
"kind": "plugin",
|
|
9
|
-
"expectedHash": "
|
|
9
|
+
"expectedHash": "28e00665097934ea390c85f9a991f9074f77d31ff7ffe6f118035e834b911d2d",
|
|
10
10
|
"hashAlgorithm": "sha256"
|
|
11
11
|
}
|
|
12
12
|
]
|