opencode-readseek 0.6.2 → 0.6.4

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 (2) hide show
  1. package/index.ts +49 -32
  2. package/package.json +2 -2
package/index.ts CHANGED
@@ -8,8 +8,13 @@ import path from "node:path";
8
8
  import { tool, type Plugin, type PluginOptions, type ToolContext } from "@opencode-ai/plugin";
9
9
 
10
10
  const require = createRequire(import.meta.url);
11
- const readseekScript = require.resolve("@jarkkojs/readseek/bin/readseek.js");
12
11
  const MAX_OUTPUT_BYTES = 32 * 1024 * 1024;
12
+ const READSEEK_PLATFORM_PACKAGES: Record<string, string> = {
13
+ "darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
14
+ "linux-arm64": "@jarkkojs/readseek-linux-arm64",
15
+ "linux-x64": "@jarkkojs/readseek-linux-x64",
16
+ "win32-x64": "@jarkkojs/readseek-win32-x64",
17
+ };
13
18
 
14
19
  type RenamePlan = {
15
20
  summary: string;
@@ -146,9 +151,21 @@ function optionalFlag(args: string[], enabled: boolean | undefined, flag: string
146
151
  if (enabled) args.push(flag);
147
152
  }
148
153
 
154
+ function readSeekBinaryPath(): string {
155
+ const platform = `${process.platform}-${process.arch}`;
156
+ const platformPackage = READSEEK_PLATFORM_PACKAGES[platform];
157
+ if (!platformPackage) {
158
+ throw new Error(`@jarkkojs/readseek ships no binary for ${platform}`);
159
+ }
160
+
161
+ const readseekPackageDir = path.dirname(require.resolve("@jarkkojs/readseek/package.json"));
162
+ const packageJson = require.resolve(`${platformPackage}/package.json`, { paths: [readseekPackageDir] });
163
+ return path.join(path.dirname(packageJson), "bin", process.platform === "win32" ? "readseek.exe" : "readseek");
164
+ }
165
+
149
166
  async function runReadSeek(context: ToolContext, args: string[]): Promise<unknown> {
150
167
  context.abort.throwIfAborted();
151
- const child = Bun.spawn([process.execPath, readseekScript, ...args], {
168
+ const child = Bun.spawn([readSeekBinaryPath(), ...args], {
152
169
  cwd: context.directory,
153
170
  killSignal: "SIGKILL",
154
171
  maxBuffer: MAX_OUTPUT_BYTES,
@@ -338,8 +355,8 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
338
355
  tool: {
339
356
  readseek_read: readseekTool(
340
357
  imagePolicy === "off"
341
- ? "Read text with stable LINE:HASH anchors. Image and PDF files are skipped."
342
- : `Read text with stable LINE:HASH anchors. For images and PDFs, explicitly select image: ${imageModes.join(", ")}; omitting image skips the file.`,
358
+ ? "Read text with LINE:HASH anchors for durable references. Images and PDFs are skipped."
359
+ : `Read text with LINE:HASH anchors for durable references. For images or PDFs, select a mode (${imageModes.join(", ")}) or omit image to skip.`,
343
360
  {
344
361
  path: tool.schema.string().describe("Path relative to the project directory"),
345
362
  offset: tool.schema.number().int().positive().optional().describe("One-based starting line"),
@@ -348,7 +365,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
348
365
  ? {}
349
366
  : {
350
367
  image: tool.schema.enum(imageModes as [ImageMode, ...ImageMode[]]).optional()
351
- .describe(`Image/PDF mode: ${imageModes.join(", ")}. Must be selected explicitly.`),
368
+ .describe("Image or PDF processing mode"),
352
369
  }),
353
370
  },
354
371
  "read",
@@ -371,7 +388,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
371
388
  },
372
389
  ),
373
390
  readseek_map: readseekTool(
374
- "Build a structural symbol map for a source file.",
391
+ "List symbols and ranges in a source file. Use to inspect structure without reading the full file.",
375
392
  { path: tool.schema.string().describe("Path relative to the project directory") },
376
393
  "map",
377
394
  async (input, context) => {
@@ -381,14 +398,14 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
381
398
  },
382
399
  ),
383
400
  readseek_search: readseekTool(
384
- "Search source code using an ast-grep structural pattern. Results include LINE:HASH anchors.",
401
+ "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.",
385
402
  {
386
- pattern: tool.schema.string().describe("AST pattern"),
403
+ pattern: tool.schema.string().describe("ast-grep pattern, such as console.log($$$ARGS)"),
387
404
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
388
- language: tool.schema.string().optional().describe("ast-grep language"),
389
- cached: tool.schema.boolean().optional(),
390
- others: tool.schema.boolean().optional(),
391
- ignored: tool.schema.boolean().optional(),
405
+ language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
406
+ cached: tool.schema.boolean().optional().describe("Search tracked or indexed files in a Git repository"),
407
+ others: tool.schema.boolean().optional().describe("Search untracked files in a Git repository"),
408
+ ignored: tool.schema.boolean().optional().describe("Include ignored untracked files; requires others"),
392
409
  },
393
410
  "search",
394
411
  async (input, context) => {
@@ -402,14 +419,14 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
402
419
  },
403
420
  ),
404
421
  readseek_def: readseekTool(
405
- "Find structural definitions of a symbol. Results include LINE:HASH anchors.",
422
+ "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.",
406
423
  {
407
424
  name: tool.schema.string().describe("Symbol name"),
408
425
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
409
- language: tool.schema.string().optional(),
410
- cached: tool.schema.boolean().optional(),
411
- others: tool.schema.boolean().optional(),
412
- ignored: tool.schema.boolean().optional(),
426
+ language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
427
+ cached: tool.schema.boolean().optional().describe("Search tracked or indexed files in a Git repository"),
428
+ others: tool.schema.boolean().optional().describe("Search untracked files in a Git repository"),
429
+ ignored: tool.schema.boolean().optional().describe("Include ignored untracked files; requires others"),
413
430
  },
414
431
  "def",
415
432
  async (input, context) => {
@@ -422,17 +439,17 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
422
439
  },
423
440
  ),
424
441
  readseek_refs: readseekTool(
425
- "Find references to an identifier. Use scope with a cursor to identify a specific binding.",
442
+ "Find identifier usages with enclosing symbols. Use before changing or deleting a symbol; add a cursor scope to exclude same-named bindings.",
426
443
  {
427
444
  name: tool.schema.string().describe("Identifier name"),
428
445
  path: tool.schema.string().optional().describe("File or directory, defaulting to the project directory"),
429
- language: tool.schema.string().optional(),
430
- scope: tool.schema.boolean().optional(),
431
- line: tool.schema.number().int().positive().optional(),
432
- column: tool.schema.number().int().positive().optional(),
433
- cached: tool.schema.boolean().optional(),
434
- others: tool.schema.boolean().optional(),
435
- ignored: tool.schema.boolean().optional(),
446
+ language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
447
+ scope: tool.schema.boolean().optional().describe("Restrict results to the binding at the cursor"),
448
+ line: tool.schema.number().int().positive().optional().describe("Cursor line, required with scope"),
449
+ column: tool.schema.number().int().positive().optional().describe("Cursor byte column for disambiguation"),
450
+ cached: tool.schema.boolean().optional().describe("Search tracked or indexed files in a Git repository"),
451
+ others: tool.schema.boolean().optional().describe("Search untracked files in a Git repository"),
452
+ ignored: tool.schema.boolean().optional().describe("Include ignored untracked files; requires others"),
436
453
  },
437
454
  "refs",
438
455
  async (input, context) => {
@@ -452,12 +469,12 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
452
469
  },
453
470
  ),
454
471
  readseek_hover: readseekTool(
455
- "Identify the token and enclosing symbol at a source cursor.",
472
+ "Identify the token and enclosing symbol at a cursor. Use before definition lookup or rename, or to identify a line's enclosing symbol.",
456
473
  {
457
474
  path: tool.schema.string().describe("Path relative to the project directory"),
458
475
  line: tool.schema.number().int().positive().describe("One-based cursor line"),
459
476
  column: tool.schema.number().int().positive().optional().describe("One-based cursor byte column"),
460
- language: tool.schema.string().optional(),
477
+ language: tool.schema.string().optional().describe("Language override when auto-detection is ambiguous"),
461
478
  },
462
479
  "hover",
463
480
  async (input, context) => {
@@ -470,12 +487,12 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
470
487
  },
471
488
  ),
472
489
  readseek_rename: readseekTool(
473
- "Plan a binding-aware rename. This tool never writes files; apply the returned plan through OpenCode's normal edit tools.",
490
+ "Plan a symbol rename without changing same-named bindings. Never writes files; apply the returned edits with OpenCode's edit tools.",
474
491
  {
475
492
  path: tool.schema.string().describe("Path relative to the project directory"),
476
- line: tool.schema.number().int().positive().describe("One-based cursor line of the binding"),
477
- column: tool.schema.number().int().positive().optional().describe("One-based cursor byte column"),
478
- to: tool.schema.string().min(1).describe("New binding name"),
493
+ line: tool.schema.number().int().positive().describe("One-based line of the symbol to rename"),
494
+ column: tool.schema.number().int().positive().optional().describe("One-based byte column for disambiguation"),
495
+ to: tool.schema.string().min(1).describe("New symbol name"),
479
496
  workspace: tool.schema.boolean().optional().describe("Include project-wide occurrences"),
480
497
  },
481
498
  "rename",
@@ -496,7 +513,7 @@ export const ReadSeekPlugin: Plugin = async (_input, options) => {
496
513
  },
497
514
  ),
498
515
  readseek_check: readseekTool(
499
- "Check a source file for parser errors and missing syntax.",
516
+ "Check a source file for parser errors and missing syntax. Use after edits for quick syntax validation, not as a compiler or linter.",
500
517
  { path: tool.schema.string().describe("Path relative to the project directory") },
501
518
  "check",
502
519
  async (input, context) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-readseek",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "OpenCode plugin for readseek-backed structural code navigation",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -30,7 +30,7 @@
30
30
  "node": ">=20.0.0"
31
31
  },
32
32
  "dependencies": {
33
- "@jarkkojs/readseek": "^0.6.2",
33
+ "@jarkkojs/readseek": "^0.6.4",
34
34
  "@opencode-ai/plugin": "^1.17.20"
35
35
  },
36
36
  "devDependencies": {