opencode-gbk-tools 0.1.4 → 0.1.6
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 +22 -0
- package/dist/agents/gbk-engine.md +13 -1
- package/dist/opencode-tools/gbk_edit.js +14 -8
- package/dist/opencode-tools/gbk_read.js +12 -4
- package/dist/opencode-tools/gbk_search.js +16462 -0
- package/dist/plugin/index.js +104 -13
- package/dist/release-manifest.json +10 -4
- package/package.json +1 -1
package/dist/plugin/index.js
CHANGED
|
@@ -16811,6 +16811,22 @@ async function replaceLargeGbkFileText(input) {
|
|
|
16811
16811
|
throw error45;
|
|
16812
16812
|
}
|
|
16813
16813
|
}
|
|
16814
|
+
async function loadGbkTextFile(input) {
|
|
16815
|
+
const resolved = await resolveReadableGbkFile(input);
|
|
16816
|
+
if (resolved.stat.size < STREAMING_FILE_SIZE_THRESHOLD_BYTES) {
|
|
16817
|
+
return await readWholeGbkTextFile(resolved);
|
|
16818
|
+
}
|
|
16819
|
+
const chunks = [];
|
|
16820
|
+
await visitDecodedTextChunks(resolved, (text) => {
|
|
16821
|
+
chunks.push(text);
|
|
16822
|
+
});
|
|
16823
|
+
return {
|
|
16824
|
+
filePath: resolved.filePath,
|
|
16825
|
+
encoding: resolved.encoding,
|
|
16826
|
+
content: chunks.join(""),
|
|
16827
|
+
bytesRead: resolved.stat.size
|
|
16828
|
+
};
|
|
16829
|
+
}
|
|
16814
16830
|
async function readGbkFile(input) {
|
|
16815
16831
|
const offset = normalizeOptionalPositiveInteger(input.offset, "offset") ?? 1;
|
|
16816
16832
|
const limit = normalizeOptionalPositiveInteger(input.limit, "limit") ?? 2e3;
|
|
@@ -16911,6 +16927,39 @@ async function replaceGbkFileText(input) {
|
|
|
16911
16927
|
bytesWritten: buffer.byteLength
|
|
16912
16928
|
};
|
|
16913
16929
|
}
|
|
16930
|
+
async function searchGbkFile(input) {
|
|
16931
|
+
if (input.pattern.length === 0) {
|
|
16932
|
+
throw createGbkError("GBK_INVALID_ARGUMENT", "pattern \u4E0D\u80FD\u4E3A\u7A7A");
|
|
16933
|
+
}
|
|
16934
|
+
const contextLines = Math.max(0, input.contextLines ?? 3);
|
|
16935
|
+
const resolved = await resolveReadableGbkFile(input);
|
|
16936
|
+
const loaded = await loadGbkTextFile({
|
|
16937
|
+
filePath: resolved.filePath,
|
|
16938
|
+
encoding: resolved.encoding,
|
|
16939
|
+
allowExternal: input.allowExternal,
|
|
16940
|
+
context: input.context
|
|
16941
|
+
});
|
|
16942
|
+
const lines = loaded.content.split(/\r?\n/);
|
|
16943
|
+
const totalLines = lines.length;
|
|
16944
|
+
const matches = [];
|
|
16945
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
16946
|
+
if (lines[i].includes(input.pattern)) {
|
|
16947
|
+
matches.push({
|
|
16948
|
+
lineNumber: i + 1,
|
|
16949
|
+
line: lines[i],
|
|
16950
|
+
contextBefore: lines.slice(Math.max(0, i - contextLines), i),
|
|
16951
|
+
contextAfter: lines.slice(i + 1, Math.min(totalLines, i + 1 + contextLines))
|
|
16952
|
+
});
|
|
16953
|
+
}
|
|
16954
|
+
}
|
|
16955
|
+
return {
|
|
16956
|
+
filePath: resolved.filePath,
|
|
16957
|
+
encoding: resolved.encoding,
|
|
16958
|
+
totalLines,
|
|
16959
|
+
matchCount: matches.length,
|
|
16960
|
+
matches
|
|
16961
|
+
};
|
|
16962
|
+
}
|
|
16914
16963
|
async function writeGbkFile(input) {
|
|
16915
16964
|
const encoding = input.encoding ?? "gbk";
|
|
16916
16965
|
const createDirectories = input.createDirectories ?? true;
|
|
@@ -16971,17 +17020,23 @@ async function writeGbkFile(input) {
|
|
|
16971
17020
|
|
|
16972
17021
|
// src/tools/gbk_edit.ts
|
|
16973
17022
|
var gbk_edit_default = tool({
|
|
16974
|
-
description:
|
|
17023
|
+
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17024
|
+
|
|
17025
|
+
Reads the FULL file content regardless of file size \u2014 not limited by gbk_read's line window.
|
|
17026
|
+
Safe to use on files with more than 2000 lines.
|
|
17027
|
+
|
|
17028
|
+
For large files, use 'startLine'/'endLine' or 'startAnchor'/'endAnchor' to narrow the search scope
|
|
17029
|
+
and avoid false matches. Scoped edits also improve performance on very large files.`,
|
|
16975
17030
|
args: {
|
|
16976
17031
|
filePath: tool.schema.string().describe("Target file path"),
|
|
16977
|
-
oldString: tool.schema.string().describe("
|
|
17032
|
+
oldString: tool.schema.string().describe("Exact text to replace (must match file content, not gbk_read output with line numbers)"),
|
|
16978
17033
|
newString: tool.schema.string().describe("Replacement text"),
|
|
16979
|
-
replaceAll: tool.schema.boolean().optional().describe("Replace all occurrences"),
|
|
16980
|
-
startLine: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Restrict edit to 1-based start line"),
|
|
16981
|
-
endLine: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Restrict edit to 1-based end line"),
|
|
16982
|
-
startAnchor: tool.schema.string().optional().describe("Restrict edit to content after this anchor"),
|
|
16983
|
-
endAnchor: tool.schema.string().optional().describe("Restrict edit to content before this anchor"),
|
|
16984
|
-
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding"),
|
|
17034
|
+
replaceAll: tool.schema.boolean().optional().describe("Replace all occurrences (default: false, requires unique match)"),
|
|
17035
|
+
startLine: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Restrict edit scope to 1-based start line (inclusive)"),
|
|
17036
|
+
endLine: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Restrict edit scope to 1-based end line (inclusive)"),
|
|
17037
|
+
startAnchor: tool.schema.string().optional().describe("Restrict edit to content after this anchor string"),
|
|
17038
|
+
endAnchor: tool.schema.string().optional().describe("Restrict edit to content before this anchor string"),
|
|
17039
|
+
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding (default: gbk)"),
|
|
16985
17040
|
allowExternal: tool.schema.boolean().optional().describe("Allow paths outside workspace root")
|
|
16986
17041
|
},
|
|
16987
17042
|
async execute(args, context) {
|
|
@@ -16992,13 +17047,21 @@ var gbk_edit_default = tool({
|
|
|
16992
17047
|
|
|
16993
17048
|
// src/tools/gbk_read.ts
|
|
16994
17049
|
var gbk_read_default = tool({
|
|
16995
|
-
description:
|
|
17050
|
+
description: `Read GBK/GB18030 encoded text files with line numbers.
|
|
17051
|
+
|
|
17052
|
+
Returns up to 'limit' lines (default 2000) starting from 'offset'.
|
|
17053
|
+
When the file has more lines than the window, 'truncated' is true and 'totalLines' shows the full count.
|
|
17054
|
+
|
|
17055
|
+
IMPORTANT: If 'truncated' is true, the returned content is incomplete.
|
|
17056
|
+
DO NOT use the returned content as 'oldString' for gbk_edit on a truncated file.
|
|
17057
|
+
To edit content beyond the visible window, use gbk_edit with 'startLine'/'endLine' to target the exact range,
|
|
17058
|
+
or read the specific range first with 'offset' set to the desired line number.`,
|
|
16996
17059
|
args: {
|
|
16997
17060
|
filePath: tool.schema.string().describe("Target file path"),
|
|
16998
|
-
offset: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("1-based start line"),
|
|
16999
|
-
limit: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Number of lines to read"),
|
|
17061
|
+
offset: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("1-based start line (default: 1)"),
|
|
17062
|
+
limit: tool.schema.union([tool.schema.number().int().positive(), tool.schema.literal(-1)]).optional().describe("Number of lines to read (default: 2000). Use -1 to apply the default."),
|
|
17000
17063
|
tail: tool.schema.boolean().optional().describe("Read last N lines instead of offset-based window"),
|
|
17001
|
-
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding"),
|
|
17064
|
+
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding (default: gbk)"),
|
|
17002
17065
|
allowExternal: tool.schema.boolean().optional().describe("Allow paths outside workspace root")
|
|
17003
17066
|
},
|
|
17004
17067
|
async execute(args, context) {
|
|
@@ -17007,6 +17070,33 @@ var gbk_read_default = tool({
|
|
|
17007
17070
|
}
|
|
17008
17071
|
});
|
|
17009
17072
|
|
|
17073
|
+
// src/tools/gbk_search.ts
|
|
17074
|
+
var gbk_search_default = tool({
|
|
17075
|
+
description: `Search for exact text in GBK/GB18030 files. Returns matching line numbers and surrounding context.
|
|
17076
|
+
|
|
17077
|
+
Use this BEFORE gbk_edit when:
|
|
17078
|
+
- gbk_read returned truncated: true (file has more than the visible window of lines)
|
|
17079
|
+
- You need to verify the exact content and line number before constructing oldString for gbk_edit
|
|
17080
|
+
- You are unsure whether a string exists in the file
|
|
17081
|
+
|
|
17082
|
+
Workflow for large files:
|
|
17083
|
+
1. gbk_read \u2192 if truncated: true, use gbk_search to locate the target
|
|
17084
|
+
2. gbk_search \u2192 get exact lineNumber and contextAfter/contextBefore
|
|
17085
|
+
3. gbk_read(offset=<lineNumber>, limit=<N>) \u2192 get the exact block of text
|
|
17086
|
+
4. gbk_edit with the exact content as oldString`,
|
|
17087
|
+
args: {
|
|
17088
|
+
filePath: tool.schema.string().describe("Target file path"),
|
|
17089
|
+
pattern: tool.schema.string().describe("Exact string to search for (case-sensitive, plain text, not regex)"),
|
|
17090
|
+
contextLines: tool.schema.number().int().nonnegative().optional().describe("Number of context lines to return before and after each match (default: 3)"),
|
|
17091
|
+
encoding: tool.schema.enum(["gbk", "gb18030"]).optional().describe("Text encoding (default: gbk)"),
|
|
17092
|
+
allowExternal: tool.schema.boolean().optional().describe("Allow paths outside workspace root")
|
|
17093
|
+
},
|
|
17094
|
+
async execute(args, context) {
|
|
17095
|
+
const result = await searchGbkFile({ ...args, context });
|
|
17096
|
+
return JSON.stringify(result, null, 2);
|
|
17097
|
+
}
|
|
17098
|
+
});
|
|
17099
|
+
|
|
17010
17100
|
// src/tools/gbk_write.ts
|
|
17011
17101
|
var gbk_write_default = tool({
|
|
17012
17102
|
description: "Write GBK encoded text files",
|
|
@@ -17032,7 +17122,8 @@ var pluginModule = {
|
|
|
17032
17122
|
tool: {
|
|
17033
17123
|
gbk_read: gbk_read_default,
|
|
17034
17124
|
gbk_write: gbk_write_default,
|
|
17035
|
-
gbk_edit: gbk_edit_default
|
|
17125
|
+
gbk_edit: gbk_edit_default,
|
|
17126
|
+
gbk_search: gbk_search_default
|
|
17036
17127
|
}
|
|
17037
17128
|
};
|
|
17038
17129
|
}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"packageName": "opencode-gbk-tools",
|
|
4
|
-
"packageVersion": "0.1.
|
|
4
|
+
"packageVersion": "0.1.6",
|
|
5
5
|
"artifacts": [
|
|
6
6
|
{
|
|
7
7
|
"relativePath": "tools/gbk_edit.js",
|
|
8
8
|
"kind": "tool",
|
|
9
|
-
"expectedHash": "
|
|
9
|
+
"expectedHash": "3d0eb2fab5e3eca869923c2a3cc00e58ed429a4be4dbed22d13e5a5343bd5acc",
|
|
10
10
|
"hashAlgorithm": "sha256"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
"relativePath": "tools/gbk_read.js",
|
|
14
14
|
"kind": "tool",
|
|
15
|
-
"expectedHash": "
|
|
15
|
+
"expectedHash": "799c53835bfe7237c5bf1e4858a67d20fffe00f90958ef48b72877cb95c1c07f",
|
|
16
|
+
"hashAlgorithm": "sha256"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"relativePath": "tools/gbk_search.js",
|
|
20
|
+
"kind": "tool",
|
|
21
|
+
"expectedHash": "dc779c10156dacf1e88195d68445dcd25da0f279b30887559da2a8d5c32b1a02",
|
|
16
22
|
"hashAlgorithm": "sha256"
|
|
17
23
|
},
|
|
18
24
|
{
|
|
@@ -24,7 +30,7 @@
|
|
|
24
30
|
{
|
|
25
31
|
"relativePath": "agents/gbk-engine.md",
|
|
26
32
|
"kind": "agent",
|
|
27
|
-
"expectedHash": "
|
|
33
|
+
"expectedHash": "3ff7de130d4fd3c318627efd56e2be08ec6ea5b9d37b3d6bf4a7122a9e0997b1",
|
|
28
34
|
"hashAlgorithm": "sha256"
|
|
29
35
|
}
|
|
30
36
|
]
|