opencode-gbk-tools 0.1.28 → 0.1.29
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 +4 -3
- package/dist/plugin/index.js +264 -83
- package/dist/plugins/opencode-gbk-tools.js +264 -83
- package/dist/release-manifest.json +2 -2
- package/package.json +1 -1
package/dist/plugin/index.js
CHANGED
|
@@ -3910,6 +3910,139 @@ function estimateSessionTokens(messages) {
|
|
|
3910
3910
|
return Math.ceil(totalChars / 4);
|
|
3911
3911
|
}
|
|
3912
3912
|
|
|
3913
|
+
// src/lib/encoding-memory.ts
|
|
3914
|
+
import fs from "fs/promises";
|
|
3915
|
+
import os from "os";
|
|
3916
|
+
import path from "path";
|
|
3917
|
+
var ENCODING_MEMORY_VERSION = 1;
|
|
3918
|
+
var ENCODING_MEMORY_FILE_NAME = "encoding-memory.json";
|
|
3919
|
+
var CONFIG_DIR_ENV = "OPENCODE_GBK_TOOLS_CONFIG_DIR";
|
|
3920
|
+
var memoryCache = null;
|
|
3921
|
+
var loadingPromise = null;
|
|
3922
|
+
function resolveConfigDirectory() {
|
|
3923
|
+
const override = process.env[CONFIG_DIR_ENV];
|
|
3924
|
+
if (typeof override === "string" && override.trim().length > 0) {
|
|
3925
|
+
return path.resolve(override);
|
|
3926
|
+
}
|
|
3927
|
+
if (process.platform === "win32") {
|
|
3928
|
+
return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "opencode-gbk-tools");
|
|
3929
|
+
}
|
|
3930
|
+
if (process.platform === "darwin") {
|
|
3931
|
+
return path.join(os.homedir(), "Library", "Application Support", "opencode-gbk-tools");
|
|
3932
|
+
}
|
|
3933
|
+
return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"), "opencode-gbk-tools");
|
|
3934
|
+
}
|
|
3935
|
+
function normalizeFilePath(filePath) {
|
|
3936
|
+
const resolved = path.normalize(path.resolve(filePath));
|
|
3937
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
3938
|
+
}
|
|
3939
|
+
function toStoredFilePath(filePath) {
|
|
3940
|
+
return path.normalize(path.resolve(filePath));
|
|
3941
|
+
}
|
|
3942
|
+
function isRememberedEntry(value) {
|
|
3943
|
+
if (!value || typeof value !== "object") {
|
|
3944
|
+
return false;
|
|
3945
|
+
}
|
|
3946
|
+
const entry = value;
|
|
3947
|
+
return typeof entry.filePath === "string" && isRememberedGbkEncoding(entry.encoding) && typeof entry.mtimeMs === "number" && Number.isFinite(entry.mtimeMs) && typeof entry.size === "number" && Number.isFinite(entry.size) && typeof entry.lastConfirmedAt === "number" && Number.isFinite(entry.lastConfirmedAt);
|
|
3948
|
+
}
|
|
3949
|
+
async function readEncodingMemoryMap() {
|
|
3950
|
+
if (memoryCache) {
|
|
3951
|
+
return memoryCache;
|
|
3952
|
+
}
|
|
3953
|
+
if (loadingPromise) {
|
|
3954
|
+
return loadingPromise;
|
|
3955
|
+
}
|
|
3956
|
+
loadingPromise = (async () => {
|
|
3957
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
3958
|
+
try {
|
|
3959
|
+
const raw = await fs.readFile(getEncodingMemoryFilePath(), "utf8");
|
|
3960
|
+
const parsed = JSON.parse(raw);
|
|
3961
|
+
const entries = Array.isArray(parsed.entries) ? parsed.entries : [];
|
|
3962
|
+
for (const entry of entries) {
|
|
3963
|
+
if (isRememberedEntry(entry)) {
|
|
3964
|
+
map2.set(normalizeFilePath(entry.filePath), entry);
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
} catch (error45) {
|
|
3968
|
+
if (!(error45 instanceof Error && "code" in error45 && error45.code === "ENOENT")) {
|
|
3969
|
+
throw error45;
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
memoryCache = map2;
|
|
3973
|
+
loadingPromise = null;
|
|
3974
|
+
return map2;
|
|
3975
|
+
})();
|
|
3976
|
+
return loadingPromise;
|
|
3977
|
+
}
|
|
3978
|
+
async function persistEncodingMemoryMap(map2) {
|
|
3979
|
+
const entries = [...map2.values()].sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
3980
|
+
const payload = {
|
|
3981
|
+
version: ENCODING_MEMORY_VERSION,
|
|
3982
|
+
entries
|
|
3983
|
+
};
|
|
3984
|
+
const filePath = getEncodingMemoryFilePath();
|
|
3985
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
3986
|
+
await fs.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
3987
|
+
}
|
|
3988
|
+
async function statRegularFile(filePath) {
|
|
3989
|
+
try {
|
|
3990
|
+
const stat = await fs.stat(filePath);
|
|
3991
|
+
return stat.isFile() ? stat : null;
|
|
3992
|
+
} catch (error45) {
|
|
3993
|
+
if (error45 instanceof Error && "code" in error45 && error45.code === "ENOENT") {
|
|
3994
|
+
return null;
|
|
3995
|
+
}
|
|
3996
|
+
throw error45;
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
function isRememberedGbkEncoding(encoding) {
|
|
4000
|
+
return encoding === "gbk" || encoding === "gb18030";
|
|
4001
|
+
}
|
|
4002
|
+
function getEncodingMemoryFilePath() {
|
|
4003
|
+
return path.join(resolveConfigDirectory(), ENCODING_MEMORY_FILE_NAME);
|
|
4004
|
+
}
|
|
4005
|
+
async function rememberGbkEncoding(filePath, encoding) {
|
|
4006
|
+
const stat = await statRegularFile(filePath);
|
|
4007
|
+
if (!stat) {
|
|
4008
|
+
return null;
|
|
4009
|
+
}
|
|
4010
|
+
const map2 = await readEncodingMemoryMap();
|
|
4011
|
+
const entry = {
|
|
4012
|
+
filePath: toStoredFilePath(filePath),
|
|
4013
|
+
encoding,
|
|
4014
|
+
mtimeMs: stat.mtimeMs,
|
|
4015
|
+
size: Number(stat.size),
|
|
4016
|
+
lastConfirmedAt: Date.now()
|
|
4017
|
+
};
|
|
4018
|
+
map2.set(normalizeFilePath(filePath), entry);
|
|
4019
|
+
await persistEncodingMemoryMap(map2);
|
|
4020
|
+
return entry;
|
|
4021
|
+
}
|
|
4022
|
+
async function forgetRememberedEncoding(filePath) {
|
|
4023
|
+
const map2 = await readEncodingMemoryMap();
|
|
4024
|
+
const deleted = map2.delete(normalizeFilePath(filePath));
|
|
4025
|
+
if (deleted) {
|
|
4026
|
+
await persistEncodingMemoryMap(map2);
|
|
4027
|
+
}
|
|
4028
|
+
return deleted;
|
|
4029
|
+
}
|
|
4030
|
+
async function getRememberedGbkEncoding(filePath) {
|
|
4031
|
+
const map2 = await readEncodingMemoryMap();
|
|
4032
|
+
const key = normalizeFilePath(filePath);
|
|
4033
|
+
const entry = map2.get(key);
|
|
4034
|
+
if (!entry) {
|
|
4035
|
+
return null;
|
|
4036
|
+
}
|
|
4037
|
+
const stat = await statRegularFile(filePath);
|
|
4038
|
+
if (!stat || stat.mtimeMs !== entry.mtimeMs || Number(stat.size) !== entry.size) {
|
|
4039
|
+
map2.delete(key);
|
|
4040
|
+
await persistEncodingMemoryMap(map2);
|
|
4041
|
+
return null;
|
|
4042
|
+
}
|
|
4043
|
+
return entry;
|
|
4044
|
+
}
|
|
4045
|
+
|
|
3913
4046
|
// node_modules/zod/v4/classic/external.js
|
|
3914
4047
|
var external_exports = {};
|
|
3915
4048
|
__export(external_exports, {
|
|
@@ -4641,10 +4774,10 @@ function mergeDefs(...defs) {
|
|
|
4641
4774
|
function cloneDef(schema) {
|
|
4642
4775
|
return mergeDefs(schema._zod.def);
|
|
4643
4776
|
}
|
|
4644
|
-
function getElementAtPath(obj,
|
|
4645
|
-
if (!
|
|
4777
|
+
function getElementAtPath(obj, path5) {
|
|
4778
|
+
if (!path5)
|
|
4646
4779
|
return obj;
|
|
4647
|
-
return
|
|
4780
|
+
return path5.reduce((acc, key) => acc?.[key], obj);
|
|
4648
4781
|
}
|
|
4649
4782
|
function promiseAllObject(promisesObj) {
|
|
4650
4783
|
const keys = Object.keys(promisesObj);
|
|
@@ -5005,11 +5138,11 @@ function aborted(x, startIndex = 0) {
|
|
|
5005
5138
|
}
|
|
5006
5139
|
return false;
|
|
5007
5140
|
}
|
|
5008
|
-
function prefixIssues(
|
|
5141
|
+
function prefixIssues(path5, issues) {
|
|
5009
5142
|
return issues.map((iss) => {
|
|
5010
5143
|
var _a;
|
|
5011
5144
|
(_a = iss).path ?? (_a.path = []);
|
|
5012
|
-
iss.path.unshift(
|
|
5145
|
+
iss.path.unshift(path5);
|
|
5013
5146
|
return iss;
|
|
5014
5147
|
});
|
|
5015
5148
|
}
|
|
@@ -5177,7 +5310,7 @@ function treeifyError(error45, _mapper) {
|
|
|
5177
5310
|
return issue2.message;
|
|
5178
5311
|
};
|
|
5179
5312
|
const result = { errors: [] };
|
|
5180
|
-
const processError = (error46,
|
|
5313
|
+
const processError = (error46, path5 = []) => {
|
|
5181
5314
|
var _a, _b;
|
|
5182
5315
|
for (const issue2 of error46.issues) {
|
|
5183
5316
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -5187,7 +5320,7 @@ function treeifyError(error45, _mapper) {
|
|
|
5187
5320
|
} else if (issue2.code === "invalid_element") {
|
|
5188
5321
|
processError({ issues: issue2.issues }, issue2.path);
|
|
5189
5322
|
} else {
|
|
5190
|
-
const fullpath = [...
|
|
5323
|
+
const fullpath = [...path5, ...issue2.path];
|
|
5191
5324
|
if (fullpath.length === 0) {
|
|
5192
5325
|
result.errors.push(mapper(issue2));
|
|
5193
5326
|
continue;
|
|
@@ -5219,8 +5352,8 @@ function treeifyError(error45, _mapper) {
|
|
|
5219
5352
|
}
|
|
5220
5353
|
function toDotPath(_path) {
|
|
5221
5354
|
const segs = [];
|
|
5222
|
-
const
|
|
5223
|
-
for (const seg of
|
|
5355
|
+
const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5356
|
+
for (const seg of path5) {
|
|
5224
5357
|
if (typeof seg === "number")
|
|
5225
5358
|
segs.push(`[${seg}]`);
|
|
5226
5359
|
else if (typeof seg === "symbol")
|
|
@@ -16462,8 +16595,8 @@ function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_C
|
|
|
16462
16595
|
var import_iconv_lite = __toESM(require_lib(), 1);
|
|
16463
16596
|
import crypto from "crypto";
|
|
16464
16597
|
import { createReadStream } from "fs";
|
|
16465
|
-
import
|
|
16466
|
-
import
|
|
16598
|
+
import fs3 from "fs/promises";
|
|
16599
|
+
import path3 from "path";
|
|
16467
16600
|
|
|
16468
16601
|
// src/lib/errors.ts
|
|
16469
16602
|
var GbkToolError = class extends Error {
|
|
@@ -16482,26 +16615,26 @@ function createGbkError(code, message, cause) {
|
|
|
16482
16615
|
var createTextError = createGbkError;
|
|
16483
16616
|
|
|
16484
16617
|
// src/lib/path-sandbox.ts
|
|
16485
|
-
import
|
|
16486
|
-
import
|
|
16618
|
+
import fs2 from "fs/promises";
|
|
16619
|
+
import path2 from "path";
|
|
16487
16620
|
function resolveBaseDirectory(context) {
|
|
16488
16621
|
const value = context.directory ?? process.cwd();
|
|
16489
|
-
return
|
|
16622
|
+
return path2.isAbsolute(value) ? value : path2.resolve(process.cwd(), value);
|
|
16490
16623
|
}
|
|
16491
16624
|
function resolveWorkspaceRoot(context) {
|
|
16492
16625
|
const value = context.worktree ?? context.directory ?? process.cwd();
|
|
16493
|
-
return
|
|
16626
|
+
return path2.isAbsolute(value) ? value : path2.resolve(process.cwd(), value);
|
|
16494
16627
|
}
|
|
16495
16628
|
function resolveCandidatePath(filePath, context) {
|
|
16496
|
-
return
|
|
16629
|
+
return path2.resolve(resolveBaseDirectory(context), filePath);
|
|
16497
16630
|
}
|
|
16498
16631
|
async function resolveExistingAnchor(filePath) {
|
|
16499
16632
|
let current = filePath;
|
|
16500
16633
|
while (true) {
|
|
16501
16634
|
try {
|
|
16502
|
-
return await
|
|
16635
|
+
return await fs2.realpath(current);
|
|
16503
16636
|
} catch {
|
|
16504
|
-
const parent =
|
|
16637
|
+
const parent = path2.dirname(current);
|
|
16505
16638
|
if (parent === current) {
|
|
16506
16639
|
throw createGbkError("GBK_IO_ERROR", `\u65E0\u6CD5\u89E3\u6790\u8DEF\u5F84\u951A\u70B9: ${filePath}`);
|
|
16507
16640
|
}
|
|
@@ -16513,10 +16646,10 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16513
16646
|
const candidatePath = resolveCandidatePath(filePath, context);
|
|
16514
16647
|
const workspaceRoot = resolveWorkspaceRoot(context);
|
|
16515
16648
|
if (!allowExternal) {
|
|
16516
|
-
const realWorkspaceRoot = await
|
|
16649
|
+
const realWorkspaceRoot = await fs2.realpath(workspaceRoot);
|
|
16517
16650
|
const realCandidateAnchor = await resolveExistingAnchor(candidatePath);
|
|
16518
|
-
const relative =
|
|
16519
|
-
if (relative === "" || !relative.startsWith("..") && !
|
|
16651
|
+
const relative = path2.relative(realWorkspaceRoot, realCandidateAnchor);
|
|
16652
|
+
if (relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative)) {
|
|
16520
16653
|
return { candidatePath, workspaceRoot };
|
|
16521
16654
|
}
|
|
16522
16655
|
throw createGbkError("GBK_PATH_OUTSIDE_ROOT", `\u76EE\u6807\u8DEF\u5F84\u8D85\u51FA\u5DE5\u4F5C\u76EE\u5F55\u8303\u56F4: ${candidatePath}`);
|
|
@@ -16538,8 +16671,8 @@ function buildGbkLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
|
16538
16671
|
const afterLines = normalizeNewlines(afterText).split("\n");
|
|
16539
16672
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
16540
16673
|
const header = [
|
|
16541
|
-
`${ANSI_DIM}--- ${
|
|
16542
|
-
`${ANSI_DIM}+++ ${
|
|
16674
|
+
`${ANSI_DIM}--- ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`,
|
|
16675
|
+
`${ANSI_DIM}+++ ${path3.basename(filePath)} (${encoding})${ANSI_RESET}`
|
|
16543
16676
|
];
|
|
16544
16677
|
const body = [];
|
|
16545
16678
|
for (let index = 0; index < maxLines; index += 1) {
|
|
@@ -17033,7 +17166,7 @@ async function resolveReadableGbkFile(input) {
|
|
|
17033
17166
|
const { candidatePath } = await assertPathAllowed(input.filePath, input.context, input.allowExternal ?? false);
|
|
17034
17167
|
let stat;
|
|
17035
17168
|
try {
|
|
17036
|
-
stat = await
|
|
17169
|
+
stat = await fs3.stat(candidatePath);
|
|
17037
17170
|
} catch (error45) {
|
|
17038
17171
|
throw createGbkError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\u5728: ${candidatePath}`, error45);
|
|
17039
17172
|
}
|
|
@@ -17048,7 +17181,7 @@ async function resolveReadableGbkFile(input) {
|
|
|
17048
17181
|
}
|
|
17049
17182
|
async function readWholeGbkTextFile(input) {
|
|
17050
17183
|
try {
|
|
17051
|
-
const buffer = await
|
|
17184
|
+
const buffer = await fs3.readFile(input.filePath);
|
|
17052
17185
|
const content = await readBufferAsText(buffer, input.encoding);
|
|
17053
17186
|
return {
|
|
17054
17187
|
filePath: input.filePath,
|
|
@@ -17192,7 +17325,7 @@ async function appendEncodedText(filePath, encoding, text) {
|
|
|
17192
17325
|
return 0;
|
|
17193
17326
|
}
|
|
17194
17327
|
const buffer = import_iconv_lite.default.encode(text, encoding);
|
|
17195
|
-
await
|
|
17328
|
+
await fs3.appendFile(filePath, buffer);
|
|
17196
17329
|
return buffer.byteLength;
|
|
17197
17330
|
}
|
|
17198
17331
|
async function copyFileByteRangeToHandle(sourcePath, handle, start, endExclusive) {
|
|
@@ -17271,11 +17404,11 @@ async function replaceLargeGbkFileTextInLineRange(input) {
|
|
|
17271
17404
|
input.replaceAll,
|
|
17272
17405
|
lineIndex.newlineStyle
|
|
17273
17406
|
);
|
|
17274
|
-
const tempPath =
|
|
17275
|
-
|
|
17276
|
-
`${
|
|
17407
|
+
const tempPath = path3.join(
|
|
17408
|
+
path3.dirname(input.filePath),
|
|
17409
|
+
`${path3.basename(input.filePath)}.opencode-gbk-${crypto.randomUUID()}.tmp`
|
|
17277
17410
|
);
|
|
17278
|
-
const handle = await
|
|
17411
|
+
const handle = await fs3.open(tempPath, "w");
|
|
17279
17412
|
let bytesWritten = 0;
|
|
17280
17413
|
try {
|
|
17281
17414
|
bytesWritten += await copyFileByteRangeToHandle(input.filePath, handle, 0, rangeStart);
|
|
@@ -17283,8 +17416,8 @@ async function replaceLargeGbkFileTextInLineRange(input) {
|
|
|
17283
17416
|
bytesWritten += await copyFileByteRangeToHandle(input.filePath, handle, rangeEnd, toSafeNumber(input.stat.size));
|
|
17284
17417
|
await handle.close();
|
|
17285
17418
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
17286
|
-
await
|
|
17287
|
-
await
|
|
17419
|
+
await fs3.chmod(tempPath, mode);
|
|
17420
|
+
await fs3.rename(tempPath, input.filePath);
|
|
17288
17421
|
return {
|
|
17289
17422
|
mode: "replace",
|
|
17290
17423
|
filePath: input.filePath,
|
|
@@ -17296,18 +17429,18 @@ async function replaceLargeGbkFileTextInLineRange(input) {
|
|
|
17296
17429
|
};
|
|
17297
17430
|
} catch (error45) {
|
|
17298
17431
|
await handle.close().catch(() => void 0);
|
|
17299
|
-
await
|
|
17432
|
+
await fs3.rm(tempPath, { force: true }).catch(() => void 0);
|
|
17300
17433
|
throw error45;
|
|
17301
17434
|
}
|
|
17302
17435
|
}
|
|
17303
17436
|
async function replaceLargeGbkFileByAnchor(input) {
|
|
17304
17437
|
const lineIndex = await getGbkLineIndex(input);
|
|
17305
17438
|
const newlineStyle = lineIndex.newlineStyle;
|
|
17306
|
-
const tempPath =
|
|
17307
|
-
|
|
17308
|
-
`${
|
|
17439
|
+
const tempPath = path3.join(
|
|
17440
|
+
path3.dirname(input.filePath),
|
|
17441
|
+
`${path3.basename(input.filePath)}.opencode-gbk-${crypto.randomUUID()}.tmp`
|
|
17309
17442
|
);
|
|
17310
|
-
const handle = await
|
|
17443
|
+
const handle = await fs3.open(tempPath, "w");
|
|
17311
17444
|
const alignedContent = alignTextToNewlineStyle(input.content, newlineStyle);
|
|
17312
17445
|
const anchorVariants = buildFlexibleSearchVariants(input.anchor, newlineStyle);
|
|
17313
17446
|
const maxAnchorLength = anchorVariants.reduce((maxLength, candidate) => Math.max(maxLength, candidate.length), input.anchor.length);
|
|
@@ -17420,8 +17553,8 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17420
17553
|
await finalizeInserted();
|
|
17421
17554
|
await handle.close();
|
|
17422
17555
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
17423
|
-
await
|
|
17424
|
-
await
|
|
17556
|
+
await fs3.chmod(tempPath, mode);
|
|
17557
|
+
await fs3.rename(tempPath, input.filePath);
|
|
17425
17558
|
invalidateGbkLineIndex(input.filePath);
|
|
17426
17559
|
return {
|
|
17427
17560
|
mode: input.mode,
|
|
@@ -17437,18 +17570,18 @@ async function replaceLargeGbkFileByAnchor(input) {
|
|
|
17437
17570
|
};
|
|
17438
17571
|
} catch (error45) {
|
|
17439
17572
|
await handle.close().catch(() => void 0);
|
|
17440
|
-
await
|
|
17573
|
+
await fs3.rm(tempPath, { force: true }).catch(() => void 0);
|
|
17441
17574
|
throw error45;
|
|
17442
17575
|
}
|
|
17443
17576
|
}
|
|
17444
17577
|
async function replaceLargeGbkFileText(input) {
|
|
17445
17578
|
const lineIndex = await getGbkLineIndex(input);
|
|
17446
17579
|
const newlineStyle = lineIndex.newlineStyle;
|
|
17447
|
-
const tempPath =
|
|
17448
|
-
|
|
17449
|
-
`${
|
|
17580
|
+
const tempPath = path3.join(
|
|
17581
|
+
path3.dirname(input.filePath),
|
|
17582
|
+
`${path3.basename(input.filePath)}.opencode-gbk-${crypto.randomUUID()}.tmp`
|
|
17450
17583
|
);
|
|
17451
|
-
const handle = await
|
|
17584
|
+
const handle = await fs3.open(tempPath, "w");
|
|
17452
17585
|
const carryLength = Math.max(input.oldString.length - 1, 0);
|
|
17453
17586
|
const alignedNewString = alignTextToNewlineStyle(input.newString, newlineStyle);
|
|
17454
17587
|
let carry = "";
|
|
@@ -17507,8 +17640,8 @@ async function replaceLargeGbkFileText(input) {
|
|
|
17507
17640
|
}
|
|
17508
17641
|
await handle.close();
|
|
17509
17642
|
const mode = typeof input.stat.mode === "bigint" ? Number(input.stat.mode) : input.stat.mode;
|
|
17510
|
-
await
|
|
17511
|
-
await
|
|
17643
|
+
await fs3.chmod(tempPath, mode);
|
|
17644
|
+
await fs3.rename(tempPath, input.filePath);
|
|
17512
17645
|
invalidateGbkLineIndex(input.filePath);
|
|
17513
17646
|
return {
|
|
17514
17647
|
filePath: input.filePath,
|
|
@@ -17520,7 +17653,7 @@ async function replaceLargeGbkFileText(input) {
|
|
|
17520
17653
|
};
|
|
17521
17654
|
} catch (error45) {
|
|
17522
17655
|
await handle.close().catch(() => void 0);
|
|
17523
|
-
await
|
|
17656
|
+
await fs3.rm(tempPath, { force: true }).catch(() => void 0);
|
|
17524
17657
|
throw error45;
|
|
17525
17658
|
}
|
|
17526
17659
|
}
|
|
@@ -17648,7 +17781,7 @@ async function replaceGbkFileText(input) {
|
|
|
17648
17781
|
};
|
|
17649
17782
|
}
|
|
17650
17783
|
const buffer2 = import_iconv_lite.default.encode(insertResult.outputText, current2.encoding);
|
|
17651
|
-
await
|
|
17784
|
+
await fs3.writeFile(current2.filePath, buffer2);
|
|
17652
17785
|
return {
|
|
17653
17786
|
mode,
|
|
17654
17787
|
filePath: current2.filePath,
|
|
@@ -17708,7 +17841,7 @@ async function replaceGbkFileText(input) {
|
|
|
17708
17841
|
if (loose !== null) {
|
|
17709
17842
|
const outputText2 = `${current.content.slice(0, scope.rangeStart)}${loose.content}${current.content.slice(scope.rangeEnd)}`;
|
|
17710
17843
|
const buffer2 = import_iconv_lite.default.encode(outputText2, current.encoding);
|
|
17711
|
-
await
|
|
17844
|
+
await fs3.writeFile(current.filePath, buffer2);
|
|
17712
17845
|
invalidateGbkLineIndex(current.filePath);
|
|
17713
17846
|
return {
|
|
17714
17847
|
mode: "replace",
|
|
@@ -17736,7 +17869,7 @@ async function replaceGbkFileText(input) {
|
|
|
17736
17869
|
const replaced = replaceAll ? scope.selectedText.split(effectiveOldString).join(alignedNewString) : scope.selectedText.replace(effectiveOldString, alignedNewString);
|
|
17737
17870
|
const outputText = `${current.content.slice(0, scope.rangeStart)}${replaced}${current.content.slice(scope.rangeEnd)}`;
|
|
17738
17871
|
const buffer = import_iconv_lite.default.encode(outputText, current.encoding);
|
|
17739
|
-
await
|
|
17872
|
+
await fs3.writeFile(current.filePath, buffer);
|
|
17740
17873
|
invalidateGbkLineIndex(current.filePath);
|
|
17741
17874
|
return {
|
|
17742
17875
|
mode: "replace",
|
|
@@ -17821,11 +17954,11 @@ async function writeGbkFile(input) {
|
|
|
17821
17954
|
const overwrite = input.overwrite ?? false;
|
|
17822
17955
|
const append = input.append ?? false;
|
|
17823
17956
|
const { candidatePath } = await assertPathAllowed(input.filePath, input.context, input.allowExternal ?? false);
|
|
17824
|
-
const parent =
|
|
17957
|
+
const parent = path3.dirname(candidatePath);
|
|
17825
17958
|
assertEncodingSupported(encoding);
|
|
17826
17959
|
if (append) {
|
|
17827
17960
|
try {
|
|
17828
|
-
const parentStat = await
|
|
17961
|
+
const parentStat = await fs3.stat(parent);
|
|
17829
17962
|
if (!parentStat.isDirectory()) {
|
|
17830
17963
|
throw createGbkError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
17831
17964
|
}
|
|
@@ -17834,14 +17967,14 @@ async function writeGbkFile(input) {
|
|
|
17834
17967
|
if (!createDirectories) {
|
|
17835
17968
|
throw createGbkError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
17836
17969
|
}
|
|
17837
|
-
await
|
|
17970
|
+
await fs3.mkdir(parent, { recursive: true });
|
|
17838
17971
|
} else if (error45 instanceof Error && "code" in error45) {
|
|
17839
17972
|
throw error45;
|
|
17840
17973
|
}
|
|
17841
17974
|
}
|
|
17842
17975
|
let existed = false;
|
|
17843
17976
|
try {
|
|
17844
|
-
await
|
|
17977
|
+
await fs3.stat(candidatePath);
|
|
17845
17978
|
existed = true;
|
|
17846
17979
|
} catch (error45) {
|
|
17847
17980
|
if (!(error45 instanceof Error && "code" in error45 && error45.code === "ENOENT")) {
|
|
@@ -17860,7 +17993,7 @@ async function writeGbkFile(input) {
|
|
|
17860
17993
|
};
|
|
17861
17994
|
}
|
|
17862
17995
|
try {
|
|
17863
|
-
const stat = await
|
|
17996
|
+
const stat = await fs3.stat(candidatePath);
|
|
17864
17997
|
if (stat.isDirectory()) {
|
|
17865
17998
|
throw createGbkError("GBK_IS_DIRECTORY", `\u76EE\u6807\u8DEF\u5F84\u662F\u76EE\u5F55: ${candidatePath}`);
|
|
17866
17999
|
}
|
|
@@ -17877,7 +18010,7 @@ async function writeGbkFile(input) {
|
|
|
17877
18010
|
}
|
|
17878
18011
|
}
|
|
17879
18012
|
try {
|
|
17880
|
-
const parentStat = await
|
|
18013
|
+
const parentStat = await fs3.stat(parent);
|
|
17881
18014
|
if (!parentStat.isDirectory()) {
|
|
17882
18015
|
throw createGbkError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
17883
18016
|
}
|
|
@@ -17886,15 +18019,15 @@ async function writeGbkFile(input) {
|
|
|
17886
18019
|
if (!createDirectories) {
|
|
17887
18020
|
throw createGbkError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
17888
18021
|
}
|
|
17889
|
-
await
|
|
18022
|
+
await fs3.mkdir(parent, { recursive: true });
|
|
17890
18023
|
} else if (error45 instanceof Error && "code" in error45) {
|
|
17891
18024
|
throw error45;
|
|
17892
18025
|
}
|
|
17893
18026
|
}
|
|
17894
18027
|
try {
|
|
17895
|
-
const existed = await
|
|
18028
|
+
const existed = await fs3.stat(candidatePath).then(() => true).catch(() => false);
|
|
17896
18029
|
const buffer = import_iconv_lite.default.encode(input.content, encoding);
|
|
17897
|
-
await
|
|
18030
|
+
await fs3.writeFile(candidatePath, buffer);
|
|
17898
18031
|
invalidateGbkLineIndex(candidatePath);
|
|
17899
18032
|
return {
|
|
17900
18033
|
filePath: candidatePath,
|
|
@@ -18115,14 +18248,16 @@ var TEXT_TOOL_SYSTEM_MARKER = "[opencode-gbk-tools:text-rules]";
|
|
|
18115
18248
|
var TEXT_TOOL_SYSTEM_PROMPT = [
|
|
18116
18249
|
TEXT_TOOL_SYSTEM_MARKER,
|
|
18117
18250
|
"\u6587\u672C\u6587\u4EF6\u5904\u7406\u89C4\u5219\uFF1A",
|
|
18118
|
-
"- \
|
|
18119
|
-
"-
|
|
18251
|
+
"- \u666E\u901A UTF-8 / UTF-8 BOM / UTF-16 \u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 OpenCode \u5185\u7F6E read\u3001write\u3001edit\u3002",
|
|
18252
|
+
"- \u9047\u5230 GBK / GB18030 \u6587\u4EF6\u3001\u4E2D\u6587\u4E71\u7801\u3001\u975E UTF-8 \u65E7\u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 gbk_read\u3001gbk_write\u3001gbk_edit\u3001gbk_search\u3002",
|
|
18120
18253
|
"- \u65B0\u5EFA .txt \u6587\u4EF6\u5728 encoding=auto \u4E0B\u9ED8\u8BA4\u4F7F\u7528 GBK\uFF1B\u5176\u4ED6\u65B0\u6587\u4EF6\u8BF7\u663E\u5F0F\u6307\u5B9A encoding\u3002",
|
|
18254
|
+
"- \u65E0\u6CD5\u786E\u5B9A\u7F16\u7801\u65F6\uFF0C\u5148\u5C1D\u8BD5\u5185\u7F6E read\uFF1B\u82E5\u51FA\u73B0\u4E2D\u6587\u4E71\u7801\u3001\u66FF\u6362\u5931\u8D25\u6216\u7F16\u7801\u98CE\u9669\uFF0C\u518D\u5207\u6362\u5230 gbk_*\u3002",
|
|
18255
|
+
"- \u5DF2\u786E\u8BA4\u662F GBK/GB18030 \u7684\u6587\u4EF6\u4F1A\u88AB\u63D2\u4EF6\u6301\u4E45\u8BB0\u5FC6\uFF1B\u518D\u6B21\u64CD\u4F5C\u540C\u4E00\u8DEF\u5F84\u65F6\uFF0C\u4F18\u5148\u7EE7\u7EED\u6309 GBK \u5904\u7406\u3002",
|
|
18121
18256
|
"- \u5982\u679C\u610F\u56FE\u662F\u2018\u5728\u67D0\u6807\u7B7E\u524D\u540E\u63D2\u5165\u5185\u5BB9\u2019\uFF0C\u4F18\u5148\u4F7F\u7528 mode=insertAfter \u6216 mode=insertBefore\uFF0C\u5E76\u4F20 anchor/content\u3002",
|
|
18122
18257
|
"- \u53EA\u6709\u5728\u660E\u786E\u505A\u7CBE\u786E\u66FF\u6362\u65F6\uFF0C\u624D\u4F7F\u7528 oldString/newString\u3002",
|
|
18123
|
-
"- anchor\u3001startAnchor\u3001endAnchor\u3001oldString \u82E5\u76F4\u63A5\u590D\u5236\u81EA\u8BFB\u53D6\u7ED3\u679C\uFF0C\u53EF\u4FDD\u7559 LF \u6362\u884C\
|
|
18124
|
-
'- \u82E5\u8BFB\u53D6\u7ED3\u679C\u5E26\u6709 "N: " \u884C\u53F7\u524D\u7F00\uFF0Cgbk_edit \u4F1A\u5C3D\u91CF\u81EA\u52A8\u5265\u79BB\u8FD9\u4E9B\u524D\u7F00\u540E\u518D\u5339\u914D\u3002',
|
|
18125
|
-
"-
|
|
18258
|
+
"- anchor\u3001startAnchor\u3001endAnchor\u3001oldString \u82E5\u76F4\u63A5\u590D\u5236\u81EA\u8BFB\u53D6\u7ED3\u679C\uFF0C\u53EF\u4FDD\u7559 LF \u6362\u884C\uFF1Bgbk_edit / text_edit \u4F1A\u5C3D\u91CF\u6309\u6587\u4EF6\u6362\u884C\u98CE\u683C\u81EA\u52A8\u5BF9\u9F50\u3002",
|
|
18259
|
+
'- \u82E5\u8BFB\u53D6\u7ED3\u679C\u5E26\u6709 "N: " \u884C\u53F7\u524D\u7F00\uFF0Cgbk_edit / text_edit \u4F1A\u5C3D\u91CF\u81EA\u52A8\u5265\u79BB\u8FD9\u4E9B\u524D\u7F00\u540E\u518D\u5339\u914D\u3002',
|
|
18260
|
+
"- gbk-engine \u662F\u5F3A\u5236 GBK \u4E13\u5C5E\u6A21\u5F0F\uFF1A\u53EA\u5141\u8BB8 gbk_*\uFF0C\u4E0D\u8D70\u5185\u7F6E\u8BFB\u5199\u7F16\u8F91\u5DE5\u5177\u3002"
|
|
18126
18261
|
].join("\n");
|
|
18127
18262
|
function appendTextToolSystemPrompt(system) {
|
|
18128
18263
|
if (system.some((item) => item.includes(TEXT_TOOL_SYSTEM_MARKER))) {
|
|
@@ -18141,8 +18276,8 @@ ${TEXT_TOOL_SYSTEM_PROMPT}`;
|
|
|
18141
18276
|
var import_iconv_lite2 = __toESM(require_lib(), 1);
|
|
18142
18277
|
import crypto2 from "crypto";
|
|
18143
18278
|
import { createReadStream as createReadStream2 } from "fs";
|
|
18144
|
-
import
|
|
18145
|
-
import
|
|
18279
|
+
import fs4 from "fs/promises";
|
|
18280
|
+
import path4 from "path";
|
|
18146
18281
|
var TEXT_STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
18147
18282
|
var TEXT_DETECTION_SAMPLE_BYTES = 64 * 1024;
|
|
18148
18283
|
var UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
|
|
@@ -18178,7 +18313,7 @@ function resolveExplicitTextEncoding(value, fallback) {
|
|
|
18178
18313
|
return requested === "auto" ? fallback : requested;
|
|
18179
18314
|
}
|
|
18180
18315
|
function shouldDefaultNewTextFileToGbk(filePath) {
|
|
18181
|
-
return
|
|
18316
|
+
return path4.extname(filePath).toLowerCase() === ".txt";
|
|
18182
18317
|
}
|
|
18183
18318
|
function getBomPrefix(encoding, hasBom) {
|
|
18184
18319
|
if (!hasBom) {
|
|
@@ -18474,8 +18609,8 @@ function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
|
|
|
18474
18609
|
const afterLines = normalizeNewlines2(afterText).split("\n");
|
|
18475
18610
|
const maxLines = Math.max(beforeLines.length, afterLines.length);
|
|
18476
18611
|
const header = [
|
|
18477
|
-
`${ANSI_DIM2}--- ${
|
|
18478
|
-
`${ANSI_DIM2}+++ ${
|
|
18612
|
+
`${ANSI_DIM2}--- ${path4.basename(filePath)} (${encoding})${ANSI_RESET2}`,
|
|
18613
|
+
`${ANSI_DIM2}+++ ${path4.basename(filePath)} (${encoding})${ANSI_RESET2}`
|
|
18479
18614
|
];
|
|
18480
18615
|
const body = [];
|
|
18481
18616
|
for (let index = 0; index < maxLines; index += 1) {
|
|
@@ -18591,7 +18726,7 @@ async function resolveReadableTextFile(input) {
|
|
|
18591
18726
|
const { candidatePath } = await assertPathAllowed(input.filePath, input.context, input.allowExternal ?? false);
|
|
18592
18727
|
let stat;
|
|
18593
18728
|
try {
|
|
18594
|
-
stat = await
|
|
18729
|
+
stat = await fs4.stat(candidatePath);
|
|
18595
18730
|
} catch (error45) {
|
|
18596
18731
|
throw createTextError("GBK_FILE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\u5728: ${candidatePath}`, error45);
|
|
18597
18732
|
}
|
|
@@ -18601,7 +18736,7 @@ async function resolveReadableTextFile(input) {
|
|
|
18601
18736
|
return { filePath: candidatePath, stat };
|
|
18602
18737
|
}
|
|
18603
18738
|
async function readDetectionBuffer(filePath, sampleSize = TEXT_DETECTION_SAMPLE_BYTES) {
|
|
18604
|
-
const handle = await
|
|
18739
|
+
const handle = await fs4.open(filePath, "r");
|
|
18605
18740
|
try {
|
|
18606
18741
|
const buffer = Buffer.alloc(sampleSize);
|
|
18607
18742
|
const { bytesRead } = await handle.read(buffer, 0, sampleSize, 0);
|
|
@@ -18764,8 +18899,8 @@ async function visitDecodedTextChunks2(resolved, visitor) {
|
|
|
18764
18899
|
}
|
|
18765
18900
|
}
|
|
18766
18901
|
async function writeLargeTextFile(filePath, encoding, hasBom, producer) {
|
|
18767
|
-
const tempPath =
|
|
18768
|
-
const handle = await
|
|
18902
|
+
const tempPath = path4.join(path4.dirname(filePath), `${path4.basename(filePath)}.opencode-text-${crypto2.randomUUID()}.tmp`);
|
|
18903
|
+
const handle = await fs4.open(tempPath, "w");
|
|
18769
18904
|
try {
|
|
18770
18905
|
if (hasBom) {
|
|
18771
18906
|
const bom = getBomPrefix(encoding, hasBom);
|
|
@@ -18775,11 +18910,11 @@ async function writeLargeTextFile(filePath, encoding, hasBom, producer) {
|
|
|
18775
18910
|
}
|
|
18776
18911
|
const bytesWritten = await producer(handle);
|
|
18777
18912
|
await handle.close();
|
|
18778
|
-
await
|
|
18913
|
+
await fs4.rename(tempPath, filePath);
|
|
18779
18914
|
return bytesWritten + getBomPrefix(encoding, hasBom).length;
|
|
18780
18915
|
} catch (error45) {
|
|
18781
18916
|
await handle.close().catch(() => void 0);
|
|
18782
|
-
await
|
|
18917
|
+
await fs4.rm(tempPath, { force: true }).catch(() => void 0);
|
|
18783
18918
|
throw error45;
|
|
18784
18919
|
}
|
|
18785
18920
|
}
|
|
@@ -18874,7 +19009,7 @@ async function replaceLargeTextFileText(input) {
|
|
|
18874
19009
|
async function readWholeTextFile(input) {
|
|
18875
19010
|
const resolved = await resolveReadableTextFile(input);
|
|
18876
19011
|
try {
|
|
18877
|
-
const buffer = await
|
|
19012
|
+
const buffer = await fs4.readFile(resolved.filePath);
|
|
18878
19013
|
assertLikelyTextBuffer(buffer);
|
|
18879
19014
|
const detected = detectTextEncodingFromBuffer(buffer, input.encoding ?? "auto");
|
|
18880
19015
|
const content = decodeText(buffer, detected.detectedEncoding);
|
|
@@ -19070,7 +19205,7 @@ function ensureLossless(input, encoding, hasBom = encoding === "utf8-bom") {
|
|
|
19070
19205
|
}
|
|
19071
19206
|
async function ensureParentDirectory(parent, createDirectories) {
|
|
19072
19207
|
try {
|
|
19073
|
-
const parentStat = await
|
|
19208
|
+
const parentStat = await fs4.stat(parent);
|
|
19074
19209
|
if (!parentStat.isDirectory()) {
|
|
19075
19210
|
throw createTextError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
19076
19211
|
}
|
|
@@ -19079,7 +19214,7 @@ async function ensureParentDirectory(parent, createDirectories) {
|
|
|
19079
19214
|
if (!createDirectories) {
|
|
19080
19215
|
throw createTextError("GBK_PARENT_DIRECTORY_MISSING", `\u7236\u76EE\u5F55\u4E0D\u5B58\u5728: ${parent}`);
|
|
19081
19216
|
}
|
|
19082
|
-
await
|
|
19217
|
+
await fs4.mkdir(parent, { recursive: true });
|
|
19083
19218
|
return;
|
|
19084
19219
|
}
|
|
19085
19220
|
throw error45;
|
|
@@ -19142,7 +19277,7 @@ async function writeTextFile(input) {
|
|
|
19142
19277
|
const overwrite = input.overwrite ?? false;
|
|
19143
19278
|
const append = input.append ?? false;
|
|
19144
19279
|
const { candidatePath } = await assertPathAllowed(input.filePath, input.context, input.allowExternal ?? false);
|
|
19145
|
-
const parent =
|
|
19280
|
+
const parent = path4.dirname(candidatePath);
|
|
19146
19281
|
await ensureParentDirectory(parent, createDirectories);
|
|
19147
19282
|
let existing = null;
|
|
19148
19283
|
try {
|
|
@@ -19171,7 +19306,7 @@ async function writeTextFile(input) {
|
|
|
19171
19306
|
const outputContent = existing && preserveNewlineStyle ? alignTextToNewlineStyle2(rawContent, existing.newlineStyle) : rawContent;
|
|
19172
19307
|
ensureLossless(outputContent, targetEncoding, targetHasBom);
|
|
19173
19308
|
const buffer = encodeText(outputContent, targetEncoding, targetHasBom);
|
|
19174
|
-
await
|
|
19309
|
+
await fs4.writeFile(candidatePath, buffer);
|
|
19175
19310
|
return {
|
|
19176
19311
|
filePath: candidatePath,
|
|
19177
19312
|
encoding: targetEncoding,
|
|
@@ -19235,7 +19370,7 @@ async function replaceTextFileText(input) {
|
|
|
19235
19370
|
const targetHasBom2 = normalizedInput.preserveEncoding === false ? targetEncoding2 === "utf8-bom" || targetEncoding2 === "utf16le" || targetEncoding2 === "utf16be" : loaded2.hasBom;
|
|
19236
19371
|
ensureLossless(insertResult.outputText, targetEncoding2, targetHasBom2);
|
|
19237
19372
|
const buffer2 = encodeText(insertResult.outputText, targetEncoding2, targetHasBom2);
|
|
19238
|
-
await
|
|
19373
|
+
await fs4.writeFile(loaded2.filePath, buffer2);
|
|
19239
19374
|
return {
|
|
19240
19375
|
mode,
|
|
19241
19376
|
filePath: loaded2.filePath,
|
|
@@ -19312,7 +19447,7 @@ async function replaceTextFileText(input) {
|
|
|
19312
19447
|
const outputText2 = `${loaded.content.slice(0, scope.rangeStart)}${loose.content}${loaded.content.slice(scope.rangeEnd)}`;
|
|
19313
19448
|
ensureLossless(outputText2, targetEncoding, targetHasBom);
|
|
19314
19449
|
const buffer2 = encodeText(outputText2, targetEncoding, targetHasBom);
|
|
19315
|
-
await
|
|
19450
|
+
await fs4.writeFile(loaded.filePath, buffer2);
|
|
19316
19451
|
return {
|
|
19317
19452
|
mode: "replace",
|
|
19318
19453
|
filePath: loaded.filePath,
|
|
@@ -19344,7 +19479,7 @@ async function replaceTextFileText(input) {
|
|
|
19344
19479
|
const outputText = `${loaded.content.slice(0, scope.rangeStart)}${replaced}${loaded.content.slice(scope.rangeEnd)}`;
|
|
19345
19480
|
ensureLossless(outputText, targetEncoding, targetHasBom);
|
|
19346
19481
|
const buffer = encodeText(outputText, targetEncoding, targetHasBom);
|
|
19347
|
-
await
|
|
19482
|
+
await fs4.writeFile(loaded.filePath, buffer);
|
|
19348
19483
|
return {
|
|
19349
19484
|
mode: "replace",
|
|
19350
19485
|
filePath: loaded.filePath,
|
|
@@ -19505,6 +19640,28 @@ var MANAGED_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
|
19505
19640
|
"text_write",
|
|
19506
19641
|
"text_edit"
|
|
19507
19642
|
]);
|
|
19643
|
+
var BUILTIN_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["read", "write", "edit"]);
|
|
19644
|
+
var REMEMBERABLE_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["text_read", "text_write", "text_edit"]);
|
|
19645
|
+
function getToolFilePath(args) {
|
|
19646
|
+
if (!args || typeof args !== "object") {
|
|
19647
|
+
return null;
|
|
19648
|
+
}
|
|
19649
|
+
const filePath = args.filePath;
|
|
19650
|
+
return typeof filePath === "string" ? filePath : null;
|
|
19651
|
+
}
|
|
19652
|
+
async function maybePersistRememberedEncoding(metadata) {
|
|
19653
|
+
const filePath = typeof metadata.filePath === "string" ? metadata.filePath : null;
|
|
19654
|
+
const encoding = metadata.encoding;
|
|
19655
|
+
if (!filePath) {
|
|
19656
|
+
return;
|
|
19657
|
+
}
|
|
19658
|
+
if (isRememberedGbkEncoding(encoding)) {
|
|
19659
|
+
await rememberGbkEncoding(filePath, encoding);
|
|
19660
|
+
metadata.rememberedEncoding = encoding;
|
|
19661
|
+
return;
|
|
19662
|
+
}
|
|
19663
|
+
await forgetRememberedEncoding(filePath);
|
|
19664
|
+
}
|
|
19508
19665
|
function truncateMetadataPreview(value, sessionID) {
|
|
19509
19666
|
const previewMaxChars = Math.max(800, Math.min(2e3, Math.floor(getMaxOutputChars(sessionID) / 2)));
|
|
19510
19667
|
if (value.length <= previewMaxChars) return value;
|
|
@@ -19581,6 +19738,25 @@ function createOpencodeGbkHooks(client, directory) {
|
|
|
19581
19738
|
await maybeAutoSummarizeSession(client, directory, input);
|
|
19582
19739
|
}
|
|
19583
19740
|
},
|
|
19741
|
+
async "tool.execute.before"(input, output) {
|
|
19742
|
+
const filePath = getToolFilePath(output.args);
|
|
19743
|
+
if (!filePath) {
|
|
19744
|
+
return;
|
|
19745
|
+
}
|
|
19746
|
+
const remembered = await getRememberedGbkEncoding(filePath);
|
|
19747
|
+
if (!remembered) {
|
|
19748
|
+
return;
|
|
19749
|
+
}
|
|
19750
|
+
if (REMEMBERABLE_TEXT_TOOL_IDS.has(input.tool)) {
|
|
19751
|
+
if (output.args && (output.args.encoding === void 0 || output.args.encoding === "auto")) {
|
|
19752
|
+
output.args.encoding = remembered.encoding;
|
|
19753
|
+
}
|
|
19754
|
+
return;
|
|
19755
|
+
}
|
|
19756
|
+
if (BUILTIN_TEXT_TOOL_IDS.has(input.tool)) {
|
|
19757
|
+
throw new Error(`\u6587\u4EF6\u5DF2\u8BB0\u5FC6\u4E3A ${remembered.encoding.toUpperCase()} \u7F16\u7801\uFF0C\u8BF7\u6539\u7528 gbk_read\u3001gbk_write\u3001gbk_edit \u6216 gbk_search\uFF1A${filePath}`);
|
|
19758
|
+
}
|
|
19759
|
+
},
|
|
19584
19760
|
async "tool.execute.after"(input, output) {
|
|
19585
19761
|
if (!MANAGED_TOOL_IDS.has(input.tool)) return;
|
|
19586
19762
|
const maxOutputChars = getMaxOutputChars(input.sessionID);
|
|
@@ -19596,6 +19772,11 @@ function createOpencodeGbkHooks(client, directory) {
|
|
|
19596
19772
|
if (typeof metadata.diffPreview === "string") {
|
|
19597
19773
|
metadata.diffPreview = truncateMetadataPreview(metadata.diffPreview, input.sessionID);
|
|
19598
19774
|
}
|
|
19775
|
+
try {
|
|
19776
|
+
await maybePersistRememberedEncoding(metadata);
|
|
19777
|
+
} catch {
|
|
19778
|
+
metadata.encodingMemoryWarning = "\u8BB0\u5FC6\u6587\u4EF6\u7F16\u7801\u5931\u8D25\uFF0C\u5DF2\u5FFD\u7565";
|
|
19779
|
+
}
|
|
19599
19780
|
metadata.maxOutputChars = maxOutputChars;
|
|
19600
19781
|
if (compactionCount > 0) {
|
|
19601
19782
|
metadata.sessionCompactions = compactionCount;
|