opencode-gbk-tools 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/agents/gbk-engine.md +2 -0
- package/dist/cli/index.js +65 -5
- package/dist/opencode-tools/gbk_edit.js +364 -81
- package/dist/opencode-tools/gbk_read.js +230 -9
- package/dist/opencode-tools/gbk_write.js +3 -0
- package/dist/plugin/index.js +543 -65
- package/dist/release-manifest.json +5 -5
- package/package.json +3 -2
|
@@ -182,7 +182,7 @@ var require_internal = __commonJS({
|
|
|
182
182
|
// Codec.
|
|
183
183
|
_internal: InternalCodec
|
|
184
184
|
};
|
|
185
|
-
function InternalCodec(codecOptions,
|
|
185
|
+
function InternalCodec(codecOptions, iconv2) {
|
|
186
186
|
this.enc = codecOptions.encodingName;
|
|
187
187
|
this.bomAware = codecOptions.bomAware;
|
|
188
188
|
if (this.enc === "base64") {
|
|
@@ -194,7 +194,7 @@ var require_internal = __commonJS({
|
|
|
194
194
|
this.encoder = InternalEncoderCesu8;
|
|
195
195
|
if (Buffer2.from("eda0bdedb2a9", "hex").toString() !== "\u{1F4A9}") {
|
|
196
196
|
this.decoder = InternalDecoderCesu8;
|
|
197
|
-
this.defaultCharUnicode =
|
|
197
|
+
this.defaultCharUnicode = iconv2.defaultCharUnicode;
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
}
|
|
@@ -351,8 +351,8 @@ var require_utf32 = __commonJS({
|
|
|
351
351
|
"use strict";
|
|
352
352
|
var Buffer2 = require_safer().Buffer;
|
|
353
353
|
exports._utf32 = Utf32Codec;
|
|
354
|
-
function Utf32Codec(codecOptions,
|
|
355
|
-
this.iconv =
|
|
354
|
+
function Utf32Codec(codecOptions, iconv2) {
|
|
355
|
+
this.iconv = iconv2;
|
|
356
356
|
this.bomAware = true;
|
|
357
357
|
this.isLE = codecOptions.isLE;
|
|
358
358
|
}
|
|
@@ -476,8 +476,8 @@ var require_utf32 = __commonJS({
|
|
|
476
476
|
};
|
|
477
477
|
exports.utf32 = Utf32AutoCodec;
|
|
478
478
|
exports.ucs4 = "utf32";
|
|
479
|
-
function Utf32AutoCodec(options,
|
|
480
|
-
this.iconv =
|
|
479
|
+
function Utf32AutoCodec(options, iconv2) {
|
|
480
|
+
this.iconv = iconv2;
|
|
481
481
|
}
|
|
482
482
|
Utf32AutoCodec.prototype.encoder = Utf32AutoEncoder;
|
|
483
483
|
Utf32AutoCodec.prototype.decoder = Utf32AutoDecoder;
|
|
@@ -627,8 +627,8 @@ var require_utf16 = __commonJS({
|
|
|
627
627
|
this.overflowByte = -1;
|
|
628
628
|
};
|
|
629
629
|
exports.utf16 = Utf16Codec;
|
|
630
|
-
function Utf16Codec(codecOptions,
|
|
631
|
-
this.iconv =
|
|
630
|
+
function Utf16Codec(codecOptions, iconv2) {
|
|
631
|
+
this.iconv = iconv2;
|
|
632
632
|
}
|
|
633
633
|
Utf16Codec.prototype.encoder = Utf16Encoder;
|
|
634
634
|
Utf16Codec.prototype.decoder = Utf16Decoder;
|
|
@@ -726,8 +726,8 @@ var require_utf7 = __commonJS({
|
|
|
726
726
|
var Buffer2 = require_safer().Buffer;
|
|
727
727
|
exports.utf7 = Utf7Codec;
|
|
728
728
|
exports.unicode11utf7 = "utf7";
|
|
729
|
-
function Utf7Codec(codecOptions,
|
|
730
|
-
this.iconv =
|
|
729
|
+
function Utf7Codec(codecOptions, iconv2) {
|
|
730
|
+
this.iconv = iconv2;
|
|
731
731
|
}
|
|
732
732
|
Utf7Codec.prototype.encoder = Utf7Encoder;
|
|
733
733
|
Utf7Codec.prototype.decoder = Utf7Decoder;
|
|
@@ -809,8 +809,8 @@ var require_utf7 = __commonJS({
|
|
|
809
809
|
return res;
|
|
810
810
|
};
|
|
811
811
|
exports.utf7imap = Utf7IMAPCodec;
|
|
812
|
-
function Utf7IMAPCodec(codecOptions,
|
|
813
|
-
this.iconv =
|
|
812
|
+
function Utf7IMAPCodec(codecOptions, iconv2) {
|
|
813
|
+
this.iconv = iconv2;
|
|
814
814
|
}
|
|
815
815
|
Utf7IMAPCodec.prototype.encoder = Utf7IMAPEncoder;
|
|
816
816
|
Utf7IMAPCodec.prototype.decoder = Utf7IMAPDecoder;
|
|
@@ -943,7 +943,7 @@ var require_sbcs_codec = __commonJS({
|
|
|
943
943
|
"use strict";
|
|
944
944
|
var Buffer2 = require_safer().Buffer;
|
|
945
945
|
exports._sbcs = SBCSCodec;
|
|
946
|
-
function SBCSCodec(codecOptions,
|
|
946
|
+
function SBCSCodec(codecOptions, iconv2) {
|
|
947
947
|
if (!codecOptions) {
|
|
948
948
|
throw new Error("SBCS codec is called without the data.");
|
|
949
949
|
}
|
|
@@ -958,7 +958,7 @@ var require_sbcs_codec = __commonJS({
|
|
|
958
958
|
codecOptions.chars = asciiString + codecOptions.chars;
|
|
959
959
|
}
|
|
960
960
|
this.decodeBuf = Buffer2.from(codecOptions.chars, "ucs2");
|
|
961
|
-
var encodeBuf = Buffer2.alloc(65536,
|
|
961
|
+
var encodeBuf = Buffer2.alloc(65536, iconv2.defaultCharSingleByte.charCodeAt(0));
|
|
962
962
|
for (var i = 0; i < codecOptions.chars.length; i++) {
|
|
963
963
|
encodeBuf[codecOptions.chars.charCodeAt(i)] = i;
|
|
964
964
|
}
|
|
@@ -1623,7 +1623,7 @@ var require_dbcs_codec = __commonJS({
|
|
|
1623
1623
|
UNASSIGNED_NODE[i] = UNASSIGNED;
|
|
1624
1624
|
}
|
|
1625
1625
|
var i;
|
|
1626
|
-
function DBCSCodec(codecOptions,
|
|
1626
|
+
function DBCSCodec(codecOptions, iconv2) {
|
|
1627
1627
|
this.encodingName = codecOptions.encodingName;
|
|
1628
1628
|
if (!codecOptions) {
|
|
1629
1629
|
throw new Error("DBCS codec is called without the data.");
|
|
@@ -1672,7 +1672,7 @@ var require_dbcs_codec = __commonJS({
|
|
|
1672
1672
|
}
|
|
1673
1673
|
}
|
|
1674
1674
|
}
|
|
1675
|
-
this.defaultCharUnicode =
|
|
1675
|
+
this.defaultCharUnicode = iconv2.defaultCharUnicode;
|
|
1676
1676
|
this.encodeTable = [];
|
|
1677
1677
|
this.encodeTableSeq = [];
|
|
1678
1678
|
var skipEncodeChars = {};
|
|
@@ -1696,7 +1696,7 @@ var require_dbcs_codec = __commonJS({
|
|
|
1696
1696
|
}
|
|
1697
1697
|
}
|
|
1698
1698
|
}
|
|
1699
|
-
this.defCharSB = this.encodeTable[0][
|
|
1699
|
+
this.defCharSB = this.encodeTable[0][iconv2.defaultCharSingleByte.charCodeAt(0)];
|
|
1700
1700
|
if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]["?"];
|
|
1701
1701
|
if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0);
|
|
1702
1702
|
}
|
|
@@ -3816,9 +3816,6 @@ var require_lib = __commonJS({
|
|
|
3816
3816
|
}
|
|
3817
3817
|
});
|
|
3818
3818
|
|
|
3819
|
-
// src/tools/gbk_edit.ts
|
|
3820
|
-
import fs3 from "fs/promises";
|
|
3821
|
-
|
|
3822
3819
|
// node_modules/zod/v4/classic/external.js
|
|
3823
3820
|
var external_exports = {};
|
|
3824
3821
|
__export(external_exports, {
|
|
@@ -16241,11 +16238,10 @@ function tool(input) {
|
|
|
16241
16238
|
}
|
|
16242
16239
|
tool.schema = external_exports;
|
|
16243
16240
|
|
|
16244
|
-
// src/tools/gbk_edit.ts
|
|
16245
|
-
var import_iconv_lite2 = __toESM(require_lib(), 1);
|
|
16246
|
-
|
|
16247
16241
|
// src/lib/gbk-file.ts
|
|
16248
16242
|
var import_iconv_lite = __toESM(require_lib(), 1);
|
|
16243
|
+
import crypto from "crypto";
|
|
16244
|
+
import { createReadStream } from "fs";
|
|
16249
16245
|
import fs2 from "fs/promises";
|
|
16250
16246
|
import path2 from "path";
|
|
16251
16247
|
|
|
@@ -16308,6 +16304,7 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16308
16304
|
}
|
|
16309
16305
|
|
|
16310
16306
|
// src/lib/gbk-file.ts
|
|
16307
|
+
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16311
16308
|
function assertEncodingSupported(encoding) {
|
|
16312
16309
|
if (encoding !== "gbk" && encoding !== "gb18030") {
|
|
16313
16310
|
throw createGbkError("GBK_INVALID_ENCODING", `\u4E0D\u652F\u6301\u7684\u7F16\u7801: ${encoding}`);
|
|
@@ -16323,29 +16320,179 @@ function assertNotBinary(buffer) {
|
|
|
16323
16320
|
throw createGbkError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u6309 GBK \u6587\u672C\u5904\u7406");
|
|
16324
16321
|
}
|
|
16325
16322
|
}
|
|
16326
|
-
function
|
|
16327
|
-
|
|
16328
|
-
|
|
16323
|
+
function detectNewlineStyle(text) {
|
|
16324
|
+
const crlfCount = (text.match(/\r\n/g) ?? []).length;
|
|
16325
|
+
const lfCount = (text.match(/(^|[^\r])\n/g) ?? []).length;
|
|
16326
|
+
if (crlfCount > 0 && lfCount === 0) {
|
|
16327
|
+
return "crlf";
|
|
16328
|
+
}
|
|
16329
|
+
if (lfCount > 0 && crlfCount === 0) {
|
|
16330
|
+
return "lf";
|
|
16331
|
+
}
|
|
16332
|
+
if (crlfCount > 0 && lfCount > 0) {
|
|
16333
|
+
return "mixed";
|
|
16334
|
+
}
|
|
16335
|
+
return "none";
|
|
16336
|
+
}
|
|
16337
|
+
function applyLineRange(text, startLine, endLine) {
|
|
16338
|
+
if (startLine === void 0 && endLine === void 0) {
|
|
16339
|
+
return {
|
|
16340
|
+
selectedText: text,
|
|
16341
|
+
rangeStart: 0,
|
|
16342
|
+
rangeEnd: text.length
|
|
16343
|
+
};
|
|
16344
|
+
}
|
|
16329
16345
|
const lines = text.split(/\r?\n/);
|
|
16330
|
-
const
|
|
16331
|
-
|
|
16346
|
+
const actualStartLine = startLine ?? 1;
|
|
16347
|
+
const actualEndLine = endLine ?? lines.length;
|
|
16348
|
+
assertPositiveInteger(actualStartLine, "startLine");
|
|
16349
|
+
assertPositiveInteger(actualEndLine, "endLine");
|
|
16350
|
+
if (actualEndLine < actualStartLine) {
|
|
16351
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "endLine \u4E0D\u80FD\u5C0F\u4E8E startLine");
|
|
16352
|
+
}
|
|
16353
|
+
let cursor = 0;
|
|
16354
|
+
let rangeStart = 0;
|
|
16355
|
+
let rangeEnd = text.length;
|
|
16356
|
+
for (let lineNumber = 1; lineNumber <= lines.length; lineNumber += 1) {
|
|
16357
|
+
if (lineNumber === actualStartLine) {
|
|
16358
|
+
rangeStart = cursor;
|
|
16359
|
+
}
|
|
16360
|
+
cursor += lines[lineNumber - 1].length;
|
|
16361
|
+
if (lineNumber < lines.length) {
|
|
16362
|
+
const newlineLength = text.startsWith("\r\n", cursor) ? 2 : 1;
|
|
16363
|
+
cursor += newlineLength;
|
|
16364
|
+
}
|
|
16365
|
+
if (lineNumber === actualEndLine) {
|
|
16366
|
+
rangeEnd = cursor;
|
|
16367
|
+
break;
|
|
16368
|
+
}
|
|
16369
|
+
}
|
|
16370
|
+
return {
|
|
16371
|
+
selectedText: text.slice(rangeStart, rangeEnd),
|
|
16372
|
+
rangeStart,
|
|
16373
|
+
rangeEnd
|
|
16374
|
+
};
|
|
16375
|
+
}
|
|
16376
|
+
function applyAnchors(text, startAnchor, endAnchor) {
|
|
16377
|
+
if (!startAnchor && !endAnchor) {
|
|
16332
16378
|
return {
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
content: ""
|
|
16379
|
+
selectedText: text,
|
|
16380
|
+
rangeStart: 0,
|
|
16381
|
+
rangeEnd: text.length
|
|
16337
16382
|
};
|
|
16338
16383
|
}
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
|
|
16384
|
+
let rangeStart = 0;
|
|
16385
|
+
let rangeEnd = text.length;
|
|
16386
|
+
if (startAnchor) {
|
|
16387
|
+
const found = text.indexOf(startAnchor);
|
|
16388
|
+
if (found === -1) {
|
|
16389
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8D77\u59CB\u951A\u70B9: ${startAnchor}`);
|
|
16390
|
+
}
|
|
16391
|
+
rangeStart = found + startAnchor.length;
|
|
16392
|
+
}
|
|
16393
|
+
if (endAnchor) {
|
|
16394
|
+
const found = text.indexOf(endAnchor, rangeStart);
|
|
16395
|
+
if (found === -1) {
|
|
16396
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u7ED3\u675F\u951A\u70B9: ${endAnchor}`);
|
|
16397
|
+
}
|
|
16398
|
+
rangeEnd = found;
|
|
16399
|
+
}
|
|
16400
|
+
if (rangeEnd < rangeStart) {
|
|
16401
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "\u951A\u70B9\u8303\u56F4\u65E0\u6548");
|
|
16402
|
+
}
|
|
16403
|
+
return {
|
|
16404
|
+
selectedText: text.slice(rangeStart, rangeEnd),
|
|
16405
|
+
rangeStart,
|
|
16406
|
+
rangeEnd
|
|
16407
|
+
};
|
|
16408
|
+
}
|
|
16409
|
+
function resolveEditScope(text, input) {
|
|
16410
|
+
const anchored = applyAnchors(text, input.startAnchor, input.endAnchor);
|
|
16411
|
+
const lineRanged = applyLineRange(anchored.selectedText, input.startLine, input.endLine);
|
|
16342
16412
|
return {
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
content
|
|
16413
|
+
selectedText: lineRanged.selectedText,
|
|
16414
|
+
rangeStart: anchored.rangeStart + lineRanged.rangeStart,
|
|
16415
|
+
rangeEnd: anchored.rangeStart + lineRanged.rangeEnd
|
|
16347
16416
|
};
|
|
16348
16417
|
}
|
|
16418
|
+
function normalizeNewlines(text) {
|
|
16419
|
+
return text.replace(/\r\n/g, "\n");
|
|
16420
|
+
}
|
|
16421
|
+
function trimRightSpaces(text) {
|
|
16422
|
+
return text.replace(/[ \t]+$/g, "");
|
|
16423
|
+
}
|
|
16424
|
+
function splitNormalizedLines(text) {
|
|
16425
|
+
return normalizeNewlines(text).split("\n");
|
|
16426
|
+
}
|
|
16427
|
+
function trimTrailingEmptyLines(lines) {
|
|
16428
|
+
const result = [...lines];
|
|
16429
|
+
while (result.length > 0 && trimRightSpaces(result[result.length - 1]) === "") {
|
|
16430
|
+
result.pop();
|
|
16431
|
+
}
|
|
16432
|
+
return result;
|
|
16433
|
+
}
|
|
16434
|
+
function getNearestContext(content, oldString) {
|
|
16435
|
+
const lines = content.split(/\r?\n/);
|
|
16436
|
+
const oldLines = normalizeNewlines(oldString).split("\n").filter(Boolean);
|
|
16437
|
+
const firstToken = oldLines[0] || oldString.trim();
|
|
16438
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
16439
|
+
if (lines[index].includes(firstToken)) {
|
|
16440
|
+
return lines.slice(index, index + 4).join("\n");
|
|
16441
|
+
}
|
|
16442
|
+
}
|
|
16443
|
+
return lines.slice(0, 4).join("\n");
|
|
16444
|
+
}
|
|
16445
|
+
function buildNoMatchMessage(content, oldString) {
|
|
16446
|
+
return [
|
|
16447
|
+
"\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\u3002",
|
|
16448
|
+
"oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\uFF0C\u6216\u4EC5\u5728\u6362\u884C/\u5C3E\u968F\u7A7A\u884C\u4E0A\u5B58\u5728\u8F7B\u5FAE\u5DEE\u5F02\u3002",
|
|
16449
|
+
"\u6700\u63A5\u8FD1\u7684\u4E0A\u4E0B\u6587\uFF1A",
|
|
16450
|
+
getNearestContext(content, oldString)
|
|
16451
|
+
].join("\n");
|
|
16452
|
+
}
|
|
16453
|
+
function tryLooseBlockReplace(content, oldString, newString) {
|
|
16454
|
+
const normalizedContent = normalizeNewlines(content);
|
|
16455
|
+
const contentLines = splitNormalizedLines(content);
|
|
16456
|
+
const oldLines = trimTrailingEmptyLines(splitNormalizedLines(oldString));
|
|
16457
|
+
const newLines = splitNormalizedLines(newString);
|
|
16458
|
+
if (oldLines.length === 0) {
|
|
16459
|
+
return null;
|
|
16460
|
+
}
|
|
16461
|
+
for (let start = 0; start < contentLines.length; start += 1) {
|
|
16462
|
+
let contentIndex = start;
|
|
16463
|
+
let oldIndex = 0;
|
|
16464
|
+
while (oldIndex < oldLines.length && contentIndex < contentLines.length) {
|
|
16465
|
+
const expected = trimRightSpaces(oldLines[oldIndex]);
|
|
16466
|
+
const actual = trimRightSpaces(contentLines[contentIndex]);
|
|
16467
|
+
if (expected === actual) {
|
|
16468
|
+
oldIndex += 1;
|
|
16469
|
+
contentIndex += 1;
|
|
16470
|
+
continue;
|
|
16471
|
+
}
|
|
16472
|
+
if (actual === "") {
|
|
16473
|
+
contentIndex += 1;
|
|
16474
|
+
continue;
|
|
16475
|
+
}
|
|
16476
|
+
if (expected === "") {
|
|
16477
|
+
oldIndex += 1;
|
|
16478
|
+
continue;
|
|
16479
|
+
}
|
|
16480
|
+
break;
|
|
16481
|
+
}
|
|
16482
|
+
if (oldIndex === oldLines.length) {
|
|
16483
|
+
const replacedNormalized = [
|
|
16484
|
+
...contentLines.slice(0, start),
|
|
16485
|
+
...newLines,
|
|
16486
|
+
...contentLines.slice(contentIndex)
|
|
16487
|
+
].join("\n");
|
|
16488
|
+
return {
|
|
16489
|
+
occurrencesBefore: 1,
|
|
16490
|
+
content: detectNewlineStyle(content) === "crlf" ? replacedNormalized.replace(/\n/g, "\r\n") : replacedNormalized
|
|
16491
|
+
};
|
|
16492
|
+
}
|
|
16493
|
+
}
|
|
16494
|
+
return null;
|
|
16495
|
+
}
|
|
16349
16496
|
function countOccurrences(text, target) {
|
|
16350
16497
|
if (target.length === 0) {
|
|
16351
16498
|
throw createGbkError("GBK_EMPTY_OLD_STRING", "oldString \u4E0D\u80FD\u4E3A\u7A7A");
|
|
@@ -16366,10 +16513,9 @@ async function readBufferAsText(buffer, encoding) {
|
|
|
16366
16513
|
assertNotBinary(buffer);
|
|
16367
16514
|
return import_iconv_lite.default.decode(buffer, encoding);
|
|
16368
16515
|
}
|
|
16369
|
-
async function
|
|
16516
|
+
async function resolveReadableGbkFile(input) {
|
|
16370
16517
|
const encoding = input.encoding ?? "gbk";
|
|
16371
|
-
|
|
16372
|
-
const limit = input.limit ?? 2e3;
|
|
16518
|
+
assertEncodingSupported(encoding);
|
|
16373
16519
|
const { candidatePath } = await assertPathAllowed(input.filePath, input.context, input.allowExternal ?? false);
|
|
16374
16520
|
let stat;
|
|
16375
16521
|
try {
|
|
@@ -16380,21 +16526,185 @@ async function readGbkFile(input) {
|
|
|
16380
16526
|
if (stat.isDirectory()) {
|
|
16381
16527
|
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\u5F55: ${candidatePath}`);
|
|
16382
16528
|
}
|
|
16529
|
+
return {
|
|
16530
|
+
filePath: candidatePath,
|
|
16531
|
+
encoding,
|
|
16532
|
+
stat
|
|
16533
|
+
};
|
|
16534
|
+
}
|
|
16535
|
+
async function readWholeGbkTextFile(input) {
|
|
16383
16536
|
try {
|
|
16384
|
-
const buffer = await fs2.readFile(
|
|
16385
|
-
const
|
|
16537
|
+
const buffer = await fs2.readFile(input.filePath);
|
|
16538
|
+
const content = await readBufferAsText(buffer, input.encoding);
|
|
16386
16539
|
return {
|
|
16387
|
-
filePath:
|
|
16388
|
-
encoding,
|
|
16389
|
-
|
|
16540
|
+
filePath: input.filePath,
|
|
16541
|
+
encoding: input.encoding,
|
|
16542
|
+
content,
|
|
16543
|
+
bytesRead: buffer.byteLength
|
|
16390
16544
|
};
|
|
16391
16545
|
} catch (error45) {
|
|
16392
16546
|
if (error45 instanceof Error && "code" in error45) {
|
|
16393
16547
|
throw error45;
|
|
16394
16548
|
}
|
|
16395
|
-
throw createGbkError("GBK_IO_ERROR", `\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25: ${
|
|
16549
|
+
throw createGbkError("GBK_IO_ERROR", `\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25: ${input.filePath}`, error45);
|
|
16396
16550
|
}
|
|
16397
16551
|
}
|
|
16552
|
+
async function visitDecodedTextChunks(input, visitor) {
|
|
16553
|
+
const decoder = import_iconv_lite.default.getDecoder(input.encoding);
|
|
16554
|
+
const stream = createReadStream(input.filePath);
|
|
16555
|
+
try {
|
|
16556
|
+
for await (const chunk of stream) {
|
|
16557
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
16558
|
+
assertNotBinary(buffer);
|
|
16559
|
+
const text = decoder.write(buffer);
|
|
16560
|
+
if (text.length > 0) {
|
|
16561
|
+
await visitor(text);
|
|
16562
|
+
}
|
|
16563
|
+
}
|
|
16564
|
+
const trailingText = decoder.end();
|
|
16565
|
+
if (trailingText && trailingText.length > 0) {
|
|
16566
|
+
await visitor(trailingText);
|
|
16567
|
+
}
|
|
16568
|
+
} catch (error45) {
|
|
16569
|
+
if (error45 instanceof Error && "code" in error45) {
|
|
16570
|
+
throw error45;
|
|
16571
|
+
}
|
|
16572
|
+
throw createGbkError("GBK_IO_ERROR", `\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25: ${input.filePath}`, error45);
|
|
16573
|
+
} finally {
|
|
16574
|
+
stream.destroy();
|
|
16575
|
+
}
|
|
16576
|
+
}
|
|
16577
|
+
async function writeAll(handle, buffer) {
|
|
16578
|
+
let offset = 0;
|
|
16579
|
+
while (offset < buffer.length) {
|
|
16580
|
+
const { bytesWritten } = await handle.write(buffer, offset, buffer.length - offset);
|
|
16581
|
+
offset += bytesWritten;
|
|
16582
|
+
}
|
|
16583
|
+
}
|
|
16584
|
+
async function writeEncodedText(handle, encoding, text) {
|
|
16585
|
+
if (text.length === 0) {
|
|
16586
|
+
return 0;
|
|
16587
|
+
}
|
|
16588
|
+
const buffer = import_iconv_lite.default.encode(text, encoding);
|
|
16589
|
+
await writeAll(handle, buffer);
|
|
16590
|
+
return buffer.byteLength;
|
|
16591
|
+
}
|
|
16592
|
+
async function replaceLargeGbkFileText(input) {
|
|
16593
|
+
const tempPath = path2.join(
|
|
16594
|
+
path2.dirname(input.filePath),
|
|
16595
|
+
`${path2.basename(input.filePath)}.opencode-gbk-${crypto.randomUUID()}.tmp`
|
|
16596
|
+
);
|
|
16597
|
+
const handle = await fs2.open(tempPath, "w");
|
|
16598
|
+
const carryLength = Math.max(input.oldString.length - 1, 0);
|
|
16599
|
+
let carry = "";
|
|
16600
|
+
let occurrencesBefore = 0;
|
|
16601
|
+
let bytesWritten = 0;
|
|
16602
|
+
const flushText = async (text, flush = false) => {
|
|
16603
|
+
const combined = carry + text;
|
|
16604
|
+
const splitAt = flush ? combined.length : Math.max(0, combined.length - carryLength);
|
|
16605
|
+
const processable = combined.slice(0, splitAt);
|
|
16606
|
+
carry = combined.slice(splitAt);
|
|
16607
|
+
if (processable.length === 0) {
|
|
16608
|
+
return;
|
|
16609
|
+
}
|
|
16610
|
+
const matchCount = countOccurrences(processable, input.oldString);
|
|
16611
|
+
const seenBefore = occurrencesBefore;
|
|
16612
|
+
occurrencesBefore += matchCount;
|
|
16613
|
+
let output = processable;
|
|
16614
|
+
if (input.replaceAll) {
|
|
16615
|
+
if (matchCount > 0) {
|
|
16616
|
+
output = processable.split(input.oldString).join(input.newString);
|
|
16617
|
+
}
|
|
16618
|
+
} else if (seenBefore === 0 && matchCount > 0) {
|
|
16619
|
+
output = processable.replace(input.oldString, input.newString);
|
|
16620
|
+
}
|
|
16621
|
+
bytesWritten += await writeEncodedText(handle, input.encoding, output);
|
|
16622
|
+
};
|
|
16623
|
+
try {
|
|
16624
|
+
await visitDecodedTextChunks(input, async (text) => {
|
|
16625
|
+
await flushText(text);
|
|
16626
|
+
});
|
|
16627
|
+
await flushText("", true);
|
|
16628
|
+
if (occurrencesBefore === 0) {
|
|
16629
|
+
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\u5BB9: ${input.oldString}`);
|
|
16630
|
+
}
|
|
16631
|
+
if (!input.replaceAll && occurrencesBefore > 1) {
|
|
16632
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\u9879: ${input.oldString}`);
|
|
16633
|
+
}
|
|
16634
|
+
await handle.close();
|
|
16635
|
+
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
16636
|
+
await fs2.chmod(tempPath, mode);
|
|
16637
|
+
await fs2.rename(tempPath, input.filePath);
|
|
16638
|
+
return {
|
|
16639
|
+
filePath: input.filePath,
|
|
16640
|
+
encoding: input.encoding,
|
|
16641
|
+
replacements: input.replaceAll ? occurrencesBefore : 1,
|
|
16642
|
+
occurrencesBefore,
|
|
16643
|
+
bytesRead: input.stat.size,
|
|
16644
|
+
bytesWritten
|
|
16645
|
+
};
|
|
16646
|
+
} catch (error45) {
|
|
16647
|
+
await handle.close().catch(() => void 0);
|
|
16648
|
+
await fs2.rm(tempPath, { force: true }).catch(() => void 0);
|
|
16649
|
+
throw error45;
|
|
16650
|
+
}
|
|
16651
|
+
}
|
|
16652
|
+
async function replaceGbkFileText(input) {
|
|
16653
|
+
if (input.oldString.length === 0) {
|
|
16654
|
+
throw createGbkError("GBK_EMPTY_OLD_STRING", "oldString \u4E0D\u80FD\u4E3A\u7A7A");
|
|
16655
|
+
}
|
|
16656
|
+
const replaceAll = input.replaceAll ?? false;
|
|
16657
|
+
const resolved = await resolveReadableGbkFile(input);
|
|
16658
|
+
const hasScopedRange = input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0;
|
|
16659
|
+
if (resolved.stat.size >= STREAMING_FILE_SIZE_THRESHOLD_BYTES && !hasScopedRange) {
|
|
16660
|
+
return await replaceLargeGbkFileText({
|
|
16661
|
+
...resolved,
|
|
16662
|
+
oldString: input.oldString,
|
|
16663
|
+
newString: input.newString,
|
|
16664
|
+
replaceAll
|
|
16665
|
+
});
|
|
16666
|
+
}
|
|
16667
|
+
const current = await readWholeGbkTextFile(resolved);
|
|
16668
|
+
const scope = resolveEditScope(current.content, input);
|
|
16669
|
+
const occurrencesBefore = countOccurrences(scope.selectedText, input.oldString);
|
|
16670
|
+
if (!replaceAll && occurrencesBefore === 0) {
|
|
16671
|
+
const loose = tryLooseBlockReplace(scope.selectedText, input.oldString, input.newString);
|
|
16672
|
+
if (loose !== null) {
|
|
16673
|
+
const outputText2 = `${current.content.slice(0, scope.rangeStart)}${loose.content}${current.content.slice(scope.rangeEnd)}`;
|
|
16674
|
+
const buffer2 = import_iconv_lite.default.encode(outputText2, current.encoding);
|
|
16675
|
+
await fs2.writeFile(current.filePath, buffer2);
|
|
16676
|
+
return {
|
|
16677
|
+
filePath: current.filePath,
|
|
16678
|
+
encoding: current.encoding,
|
|
16679
|
+
replacements: 1,
|
|
16680
|
+
occurrencesBefore: loose.occurrencesBefore,
|
|
16681
|
+
bytesRead: current.bytesRead,
|
|
16682
|
+
bytesWritten: buffer2.byteLength
|
|
16683
|
+
};
|
|
16684
|
+
}
|
|
16685
|
+
}
|
|
16686
|
+
if (replaceAll) {
|
|
16687
|
+
if (occurrencesBefore === 0) {
|
|
16688
|
+
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, input.oldString));
|
|
16689
|
+
}
|
|
16690
|
+
} else if (occurrencesBefore === 0) {
|
|
16691
|
+
throw createGbkError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, input.oldString));
|
|
16692
|
+
} else if (occurrencesBefore > 1) {
|
|
16693
|
+
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\u9879: ${input.oldString}`);
|
|
16694
|
+
}
|
|
16695
|
+
const replaced = replaceAll ? scope.selectedText.split(input.oldString).join(input.newString) : scope.selectedText.replace(input.oldString, input.newString);
|
|
16696
|
+
const outputText = `${current.content.slice(0, scope.rangeStart)}${replaced}${current.content.slice(scope.rangeEnd)}`;
|
|
16697
|
+
const buffer = import_iconv_lite.default.encode(outputText, current.encoding);
|
|
16698
|
+
await fs2.writeFile(current.filePath, buffer);
|
|
16699
|
+
return {
|
|
16700
|
+
filePath: current.filePath,
|
|
16701
|
+
encoding: current.encoding,
|
|
16702
|
+
replacements: replaceAll ? occurrencesBefore : 1,
|
|
16703
|
+
occurrencesBefore,
|
|
16704
|
+
bytesRead: current.bytesRead,
|
|
16705
|
+
bytesWritten: buffer.byteLength
|
|
16706
|
+
};
|
|
16707
|
+
}
|
|
16398
16708
|
|
|
16399
16709
|
// src/tools/gbk_edit.ts
|
|
16400
16710
|
var gbk_edit_default = tool({
|
|
@@ -16404,43 +16714,16 @@ var gbk_edit_default = tool({
|
|
|
16404
16714
|
oldString: tool.schema.string().describe("Text to replace"),
|
|
16405
16715
|
newString: tool.schema.string().describe("Replacement text"),
|
|
16406
16716
|
replaceAll: tool.schema.boolean().optional().describe("Replace all occurrences"),
|
|
16717
|
+
startLine: tool.schema.number().int().positive().optional().describe("Restrict edit to 1-based start line"),
|
|
16718
|
+
endLine: tool.schema.number().int().positive().optional().describe("Restrict edit to 1-based end line"),
|
|
16719
|
+
startAnchor: tool.schema.string().optional().describe("Restrict edit to content after this anchor"),
|
|
16720
|
+
endAnchor: tool.schema.string().optional().describe("Restrict edit to content before this anchor"),
|
|
16407
16721
|
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding"),
|
|
16408
16722
|
allowExternal: tool.schema.boolean().optional().describe("Allow paths outside workspace root")
|
|
16409
16723
|
},
|
|
16410
16724
|
async execute(args, context) {
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
}
|
|
16414
|
-
const encoding = args.encoding ?? "gbk";
|
|
16415
|
-
const replaceAll = args.replaceAll ?? false;
|
|
16416
|
-
const { candidatePath } = await assertPathAllowed(args.filePath, context, args.allowExternal ?? false);
|
|
16417
|
-
const current = await readGbkFile({
|
|
16418
|
-
filePath: candidatePath,
|
|
16419
|
-
encoding,
|
|
16420
|
-
context,
|
|
16421
|
-
allowExternal: args.allowExternal
|
|
16422
|
-
});
|
|
16423
|
-
const sourceText = current.content.split("\n").map((line) => line.replace(/^\d+: /, "")).join("\n");
|
|
16424
|
-
const occurrencesBefore = countOccurrences(sourceText, args.oldString);
|
|
16425
|
-
if (replaceAll) {
|
|
16426
|
-
if (occurrencesBefore === 0) {
|
|
16427
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\u5BB9: ${args.oldString}`);
|
|
16428
|
-
}
|
|
16429
|
-
} else if (occurrencesBefore === 0) {
|
|
16430
|
-
throw createGbkError("GBK_NO_MATCH", `\u672A\u627E\u5230\u8981\u66FF\u6362\u7684\u5185\u5BB9: ${args.oldString}`);
|
|
16431
|
-
} else if (occurrencesBefore > 1) {
|
|
16432
|
-
throw createGbkError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\u9879: ${args.oldString}`);
|
|
16433
|
-
}
|
|
16434
|
-
const replaced = replaceAll ? sourceText.split(args.oldString).join(args.newString) : sourceText.replace(args.oldString, args.newString);
|
|
16435
|
-
const buffer = import_iconv_lite2.default.encode(replaced, encoding);
|
|
16436
|
-
await fs3.writeFile(candidatePath, buffer);
|
|
16437
|
-
return JSON.stringify({
|
|
16438
|
-
filePath: candidatePath,
|
|
16439
|
-
encoding,
|
|
16440
|
-
replacements: replaceAll ? occurrencesBefore : 1,
|
|
16441
|
-
occurrencesBefore,
|
|
16442
|
-
bytesWritten: buffer.byteLength
|
|
16443
|
-
}, null, 2);
|
|
16725
|
+
const result = await replaceGbkFileText({ ...args, context });
|
|
16726
|
+
return JSON.stringify(result, null, 2);
|
|
16444
16727
|
}
|
|
16445
16728
|
});
|
|
16446
16729
|
export {
|