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.
@@ -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: "Edit GBK encoded text files with exact replacement",
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("Text to replace"),
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: "Read GBK encoded text files",
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",
4
+ "packageVersion": "0.1.6",
5
5
  "artifacts": [
6
6
  {
7
7
  "relativePath": "tools/gbk_edit.js",
8
8
  "kind": "tool",
9
- "expectedHash": "6a8a26850a21e47a9ececc2b8606452491a654d5fc79ef908cfbcea9e6c5b7e3",
9
+ "expectedHash": "3d0eb2fab5e3eca869923c2a3cc00e58ed429a4be4dbed22d13e5a5343bd5acc",
10
10
  "hashAlgorithm": "sha256"
11
11
  },
12
12
  {
13
13
  "relativePath": "tools/gbk_read.js",
14
14
  "kind": "tool",
15
- "expectedHash": "c61e5ee95e05e96965c76e5dc2f18b3943bc3c2a76567b415839442358024d46",
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": "755b6278033400bdc08bb0d7dc491eabe5aa3a0157c6bef4304c7a5f2038c0dd",
33
+ "expectedHash": "3ff7de130d4fd3c318627efd56e2be08ec6ea5b9d37b3d6bf4a7122a9e0997b1",
28
34
  "hashAlgorithm": "sha256"
29
35
  }
30
36
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gbk-tools",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "GBK/GB18030 custom tools and agent for OpenCode",
5
5
  "type": "module",
6
6
  "license": "MIT",