opencode-readseek 0.8.18 → 0.8.19

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.
Files changed (3) hide show
  1. package/README.md +48 -32
  2. package/index.ts +33 -34
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # opencode-readseek
2
2
 
3
- <img alt="Screenshot of OpenCode running opencode-readseek" src="screenshot.png" width="800">
3
+ <img alt="OpenCode running opencode-readseek" src="screenshot.png" width="800">
4
4
 
5
- `opencode-readseek` adds ReadSeek's anchored file tools, structural search, and
6
- symbol navigation to OpenCode.
5
+ `opencode-readseek` adds anchored file operations, structural search, symbol
6
+ navigation, and PDF tools to OpenCode.
7
7
 
8
- ## Installation
8
+ ## Install
9
9
 
10
- Add the plugin to `opencode.json`:
10
+ Add the package to `opencode.json`:
11
11
 
12
12
  ```json
13
13
  {
@@ -15,29 +15,34 @@ Add the plugin to `opencode.json`:
15
15
  }
16
16
  ```
17
17
 
18
- OpenCode installs the package and its platform-specific `@jarkkojs/readseek`
19
- binary dependency with Bun.
18
+ OpenCode installs the package and its platform-specific
19
+ `@jarkkojs/readseek` dependency with Bun.
20
20
 
21
21
  ## Tools
22
22
 
23
- - `readseek_read`: reads anchored text; PDFs select one page by default.
24
- - `readseek_edit`: applies hash-verified edits to existing text files.
25
- - `readseek_write`: creates or replaces complete files.
26
- - `readseek_grep`: searches text or regular expressions and returns anchors.
27
- - `readseek_map`, `readseek_search`: map symbols and search AST patterns.
28
- - `readseek_def`, `readseek_refs`, `readseek_hover`: navigate symbols.
29
- - `readseek_rename`: applies verified renames by default. Set `apply: false` for a
30
- dry run.
31
- - `readseek_check`: reports parse diagnostics.
32
- - `readseek_view`: indexes a PDF or narrows an existing index by page, node, kind,
33
- or depth.
34
-
35
- The plugin requests read, grep, external-directory, and edit permissions as needed.
36
- File changes invalidate remembered anchors. Compaction state retains fresh paths
37
- and pending rename plans. Text reads return at most 2,000 lines by default.
38
-
39
- OpenCode is instructed to prefer ReadSeek tools over built-in read/edit/write/grep
40
- and symbol navigation; built-ins remain available as fallbacks.
23
+ | Tool | Purpose |
24
+ | --- | --- |
25
+ | `readseek_read` | Read text with `LINE:HASH` anchors; read images or one PDF page |
26
+ | `readseek_edit` | Apply hash-verified edits to an existing text file |
27
+ | `readseek_write` | Create or replace a complete text file |
28
+ | `readseek_grep` | Search text or regex and return anchors |
29
+ | `readseek_map` | Show a source file's symbol outline |
30
+ | `readseek_search` | Search AST patterns |
31
+ | `readseek_def` | Find symbol definitions |
32
+ | `readseek_refs` | Find identifier usages, optionally scoped to a cursor binding |
33
+ | `readseek_hover` | Identify the token and enclosing symbol at a cursor |
34
+ | `readseek_rename` | Apply a binding-aware rename; set `apply: false` for a dry run |
35
+ | `readseek_check` | Report parser errors and missing syntax |
36
+ | `readseek_view` | View or narrow a structural PDF index |
37
+
38
+ The plugin requests read, grep, external-directory, and edit permissions as
39
+ needed. Mutations invalidate remembered anchors; compaction preserves fresh
40
+ paths and pending rename plans. Text reads return at most 2,000 lines by
41
+ default.
42
+
43
+ OpenCode is instructed to prefer ReadSeek over the built-in `read`, `edit`,
44
+ `write`, `grep`, and `apply_patch` tools when ReadSeek can do the job. Built-ins
45
+ remain available as fallbacks.
41
46
 
42
47
  ## Configuration
43
48
 
@@ -49,13 +54,24 @@ Pass options with OpenCode's plugin tuple syntax:
49
54
  }
50
55
  ```
51
56
 
52
- `imageMode` defaults to `"auto"`, exposing `none`, `all`, `ocr`, `caption`, and
53
- `objects`. `"on"` omits `none`; `"off"` skips images and PDFs. Omitting `image`
54
- also skips visual files.
57
+ `imageMode` accepts:
55
58
 
56
- ## Licensing
59
+ - `"auto"` (default): expose `none`, `all`, `ocr`, `caption`, and `objects`.
60
+ - `"on"`: expose local analysis modes and omit `none`.
61
+ - `"off"`: skip image and PDF reads.
57
62
 
58
- `opencode-readseek` is licensed under
59
- [Apache-2.0](https://github.com/jarkkojs/readseek/blob/main/LICENSE-APACHE-2.0).
63
+ Omitting `image` from a read also skips visual files.
64
+
65
+ ## Development
66
+
67
+ ```sh
68
+ bun install
69
+ bun test
70
+ bun run typecheck
71
+ ```
72
+
73
+ ## License
74
+
75
+ `opencode-readseek` is Apache-2.0; see [LICENSE](LICENSE).
60
76
  `@jarkkojs/readseek` is licensed separately under
61
- `Apache-2.0 AND LGPL-2.1-or-later`.
77
+ Apache-2.0 AND LGPL-2.1-or-later.
package/index.ts CHANGED
@@ -16,33 +16,32 @@ const MAX_DOCUMENT_OUTPUT_BYTES = 256 * 1024;
16
16
  const MAX_DOCUMENT_OUTPUT_LINES = 2000;
17
17
  const TOOL_POLICY = [
18
18
  "ReadSeek tool policy:",
19
- "- Prefer readseek_* tools over OpenCode built-ins whenever they can do the job.",
20
- "- Prefer readseek_read for text file reads; its LINE:HASH anchors are required by readseek_edit.",
21
- "- Prefer readseek_grep for text/regex search and readseek_search for syntax-aware code shapes.",
22
- "- Prefer readseek_map, readseek_def, readseek_refs, and readseek_hover for symbol navigation.",
23
- "- Prefer readseek_edit for existing text files, readseek_write for whole-file creation or replacement, and readseek_rename for symbol renames.",
24
- "- Do not use built-in read, edit, write, grep, or apply_patch when the corresponding ReadSeek tool can perform the change.",
25
- "- Use readseek_check after source edits for a quick syntax check.",
19
+ "- Prefer readseek_* tools over built-ins when they can do the job.",
20
+ "- Read with readseek_read first; readseek_edit needs fresh LINE:HASH anchors.",
21
+ "- Use readseek_grep for text/regex, readseek_search for AST patterns, and readseek_map/def/refs/hover for symbol navigation.",
22
+ "- Use readseek_edit for existing files, readseek_write for whole-file creation or replacement, and readseek_rename for symbol renames.",
23
+ "- Do not use built-in read, edit, write, grep, or apply_patch when a ReadSeek tool can do the job.",
24
+ "- Run readseek_check after source edits for a quick syntax check.",
26
25
  ].join("\n");
27
26
  const PREFERRED_TOOL_DESCRIPTIONS: Record<string, string> = {
28
- readseek_read: "Preferred file reader; returns LINE:HASH anchors required by readseek_edit.",
29
- readseek_edit: "Preferred tool for editing existing text files with verified LINE:HASH anchors.",
30
- readseek_write: "Preferred tool for creating or replacing a complete text file.",
31
- readseek_rename: "Preferred tool for renaming code symbols safely across their resolved bindings.",
27
+ readseek_read: "Preferred file reader; returns LINE:HASH anchors for durable references.",
28
+ readseek_edit: "Preferred tool for editing existing text files with fresh LINE:HASH anchors.",
29
+ readseek_write: "Preferred tool for creating or replacing a complete text file; returns LINE:HASH anchors.",
30
+ readseek_rename: "Preferred tool for renaming a symbol while preserving same-named bindings.",
32
31
  readseek_grep: "Preferred text/regex search; returns edit-ready LINE:HASH anchors.",
33
- readseek_search: "Preferred syntax-aware code search for AST shapes and call sites.",
34
- readseek_map: "Preferred structural outline of symbols in a source file.",
32
+ readseek_search: "Preferred AST search for code shapes and call sites.",
33
+ readseek_map: "Preferred symbol outline for a source file.",
35
34
  readseek_def: "Preferred symbol definition lookup.",
36
- readseek_refs: "Preferred identifier usage finder before rename or delete.",
35
+ readseek_refs: "Preferred identifier usage finder; use before rename or delete.",
37
36
  readseek_hover: "Preferred cursor token and enclosing-symbol inspector.",
38
37
  readseek_view: "Preferred PDF structure and content viewer.",
39
38
  readseek_check: "Preferred quick syntax check after source edits.",
40
39
  };
41
40
  const FALLBACK_TOOL_DESCRIPTIONS: Record<string, string> = {
42
- read: "Fallback only. Prefer readseek_read for text files so edits can use LINE:HASH anchors.",
43
- edit: "Fallback only. Prefer readseek_edit with anchors from readseek_read/readseek_grep/readseek_search.",
41
+ read: "Fallback only. Prefer readseek_read so edits can use LINE:HASH anchors.",
42
+ edit: "Fallback only. Prefer readseek_edit with fresh LINE:HASH anchors.",
44
43
  write: "Fallback only. Prefer readseek_write so the result returns LINE:HASH anchors.",
45
- grep: "Fallback only. Prefer readseek_grep for project text search with edit-ready anchors.",
44
+ grep: "Fallback only. Prefer readseek_grep for text/regex search with edit-ready anchors.",
46
45
  apply_patch: "Fallback only. Prefer readseek_edit for existing text files.",
47
46
  };
48
47
  const READSEEK_PLATFORM_PACKAGES: Record<string, string> = {
@@ -1017,8 +1016,8 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1017
1016
  tool: {
1018
1017
  readseek_read: readseekTool(
1019
1018
  imagePolicy === "off"
1020
- ? "Read text with LINE:HASH anchors for durable references. Images and PDFs are skipped."
1021
- : `Read text with LINE:HASH anchors for durable references. For images or PDFs, select a mode (${imageModes.join(", ")}) or omit image to skip.`,
1019
+ ? "Read text with LINE:HASH anchors. Image and PDF reads are disabled."
1020
+ : `Read text with LINE:HASH anchors. For an image or PDF, select image (${imageModes.join(", ")}); omit it to skip visual files.`,
1022
1021
  {
1023
1022
  path: tool.schema.string().describe("Path relative to the project directory"),
1024
1023
  offset: tool.schema.number().int().positive().optional().describe("One-based starting line"),
@@ -1029,7 +1028,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1029
1028
  ? {}
1030
1029
  : {
1031
1030
  image: tool.schema.enum(imageModes as [ImageMode, ...ImageMode[]]).optional()
1032
- .describe("Image or PDF processing mode"),
1031
+ .describe("Image/PDF processing mode")
1033
1032
  }),
1034
1033
  },
1035
1034
  "read",
@@ -1065,7 +1064,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1065
1064
  formatReadResult,
1066
1065
  ),
1067
1066
  readseek_view: readseekTool(
1068
- "View the structure or selected content of an indexed PDF. Start with the overview, then narrow by page or node.",
1067
+ "View PDF structure or selected content. Start with the overview, then narrow by page or node.",
1069
1068
  {
1070
1069
  path: tool.schema.string().describe("PDF path relative to the project directory"),
1071
1070
  node: tool.schema.string().min(1).optional().describe("Node ID to use as the view root"),
@@ -1090,7 +1089,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1090
1089
  (result) => ({ output: boundDocumentOutput(String(result)) }),
1091
1090
  ),
1092
1091
  readseek_map: readseekTool(
1093
- "List symbols and ranges in a source file. Use to inspect structure without reading the full file.",
1092
+ "Show a source file's symbol outline without reading the full file.",
1094
1093
  {
1095
1094
  path: tool.schema.string().describe("Path relative to the project directory"),
1096
1095
  language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
@@ -1105,7 +1104,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1105
1104
  },
1106
1105
  ),
1107
1106
  readseek_grep: readseekTool(
1108
- "Search text or regular expressions and return matching LINE:HASH anchors. Use literal for exact text.",
1107
+ "Search text or regex and return matching LINE:HASH anchors. Set literal for exact text.",
1109
1108
  {
1110
1109
  pattern: tool.schema.string().describe("Text or regular expression to search for"),
1111
1110
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
@@ -1167,9 +1166,9 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1167
1166
  },
1168
1167
  ),
1169
1168
  readseek_search: readseekTool(
1170
- "Search syntax-aware code shapes with an ast-grep pattern and return LINE:HASH anchors. Use for calls, imports, declarations, JSX, or control flow; use text search for plain text.",
1169
+ "Search AST patterns (ast-grep style) and return LINE:HASH anchors. Use for code structure; use readseek_grep for plain text.",
1171
1170
  {
1172
- pattern: tool.schema.string().describe("ast-grep pattern, such as console.log($$$ARGS)"),
1171
+ pattern: tool.schema.string().describe("AST pattern (ast-grep style), such as console.log($$$ARGS)"),
1173
1172
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
1174
1173
  language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
1175
1174
  cached: tool.schema.boolean().optional().describe("Search tracked or indexed files in a Git repository"),
@@ -1188,7 +1187,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1188
1187
  },
1189
1188
  ),
1190
1189
  readseek_def: readseekTool(
1191
- "Find symbol declarations by name and return LINE:HASH anchors. Use instead of text search to locate where a function, class, type, or other symbol is defined.",
1190
+ "Find symbol declarations by name and return LINE:HASH anchors. Prefer this to text search for definitions.",
1192
1191
  {
1193
1192
  name: tool.schema.string().describe("Symbol name"),
1194
1193
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
@@ -1208,7 +1207,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1208
1207
  },
1209
1208
  ),
1210
1209
  readseek_refs: readseekTool(
1211
- "Find identifier usages with enclosing symbols. Use before changing or deleting a symbol; add a cursor scope to exclude same-named bindings.",
1210
+ "Find identifier usages with enclosing symbols. Use before renaming or deleting a symbol; add cursor scope to exclude same-named bindings.",
1212
1211
  {
1213
1212
  name: tool.schema.string().describe("Identifier name"),
1214
1213
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
@@ -1238,7 +1237,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1238
1237
  },
1239
1238
  ),
1240
1239
  readseek_hover: readseekTool(
1241
- "Identify the token and enclosing symbol at a cursor. Use before definition lookup or rename, or to identify a line's enclosing symbol.",
1240
+ "Identify the token and enclosing symbol at a cursor. Use before definition lookup or rename.",
1242
1241
  {
1243
1242
  path: tool.schema.string().describe("Path relative to the project directory"),
1244
1243
  line: tool.schema.number().int().positive().describe("One-based cursor line"),
@@ -1256,11 +1255,11 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1256
1255
  },
1257
1256
  ),
1258
1257
  readseek_rename: readseekTool(
1259
- "Rename a symbol without changing same-named bindings. Applies verified edits atomically by default; set apply false for a dry-run plan.",
1258
+ "Rename the symbol at a cursor while preserving same-named bindings. Applies verified edits atomically by default; set apply to false for a dry-run plan.",
1260
1259
  {
1261
1260
  path: tool.schema.string().describe("Path relative to the project directory"),
1262
- line: tool.schema.number().int().positive().describe("One-based line of the symbol to rename"),
1263
- column: tool.schema.number().int().positive().optional().describe("One-based byte column for disambiguation"),
1261
+ line: tool.schema.number().int().positive().describe("One-based cursor line of the symbol to rename"),
1262
+ column: tool.schema.number().int().positive().optional().describe("One-based cursor byte column for disambiguation"),
1264
1263
  to: tool.schema.string().min(1).describe("New symbol name"),
1265
1264
  workspace: tool.schema.boolean().optional().describe("Include project-wide occurrences"),
1266
1265
  apply: tool.schema.boolean().optional().describe("Apply verified edits atomically; defaults to true"),
@@ -1291,7 +1290,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1291
1290
  },
1292
1291
  ),
1293
1292
  readseek_edit: readseekTool(
1294
- "Edit an existing text file using LINE:HASH anchors. Stale hashes are rejected before writing.",
1293
+ "Edit an existing text file with fresh LINE:HASH anchors. Stale hashes are rejected before writing.",
1295
1294
  {
1296
1295
  path: tool.schema.string().describe("Path relative to the project directory"),
1297
1296
  edits: tool.schema.array(tool.schema.union([
@@ -1308,7 +1307,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1308
1307
  tool.schema.object({
1309
1308
  insert_after: tool.schema.object({ anchor: tool.schema.string(), new_text: tool.schema.string() }).strict(),
1310
1309
  }).strict(),
1311
- ])).min(1).describe("Anchored edits to apply"),
1310
+ ])).min(1).describe("LINE:HASH-anchored edits to apply"),
1312
1311
  },
1313
1312
  "edit",
1314
1313
  async (input, context) => {
@@ -1359,7 +1358,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
1359
1358
  },
1360
1359
  ),
1361
1360
  readseek_check: readseekTool(
1362
- "Check a source file for parser errors and missing syntax. Use after edits for quick syntax validation, not as a compiler or linter.",
1361
+ "Run a quick syntax check on a source file. Reports parser errors and missing syntax; not a compiler or linter.",
1363
1362
  {
1364
1363
  path: tool.schema.string().describe("Path relative to the project directory"),
1365
1364
  language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-readseek",
3
- "version": "0.8.18",
4
- "description": "OpenCode plugin for readseek-backed structural code navigation",
3
+ "version": "0.8.19",
4
+ "description": "OpenCode plugin for anchored file operations and structural code navigation",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
7
7
  "exports": {
@@ -31,7 +31,7 @@
31
31
  "node": ">=20.0.0"
32
32
  },
33
33
  "dependencies": {
34
- "@jarkkojs/readseek": "^0.8.18",
34
+ "@jarkkojs/readseek": "^0.8.19",
35
35
  "@opencode-ai/plugin": "^1.17.20"
36
36
  },
37
37
  "devDependencies": {