opencode-readseek 0.11.3 → 0.12.0

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 (4) hide show
  1. package/README.md +16 -16
  2. package/dist/index.js +297 -236
  3. package/dist/v2.js +15 -15
  4. package/package.json +3 -3
package/README.md CHANGED
@@ -42,17 +42,17 @@ macOS/Windows supplied by `@jarkkojs/readseek`. Set
42
42
 
43
43
  ## Tools
44
44
 
45
- - Read without inference: `readseek_show_content`, `readseek_show_structure`,
46
- `readseek_show_metadata`, `readseek_show_assets`.
47
- - Check: `readseek_check_syntax`, `readseek_check_rules`.
48
- - Explicit inference: `readseek_generate_caption`, `readseek_detect_objects`,
49
- `readseek_recognize_text`.
50
- - Find: `readseek_find_text`, `readseek_find_nodes`, `readseek_find_definitions`,
51
- `readseek_find_references`.
52
- - Mutate: `readseek_edit_text`, `readseek_rename_symbol`, `readseek_write_file`.
53
-
54
- Tool names mirror native verb-object commands, such as `show content`,
55
- `find nodes`, and `edit text`. Paths resolve against the project directory.
45
+ - Read without inference: `readseek_show`, `readseek_tree`,
46
+ `readseek_meta`, `readseek_assets`.
47
+ - Check: `readseek_syntax`, `readseek_check`.
48
+ - Explicit inference: `readseek_caption`, `readseek_objects`,
49
+ `readseek_ocr`.
50
+ - Find: `readseek_grep`, `readseek_search`, `readseek_def`,
51
+ `readseek_refs`.
52
+ - Mutate: `readseek_edit`, `readseek_rename`, `readseek_write`.
53
+
54
+ Tool names mirror native flat single-word commands, such as `show`,
55
+ `search`, and `edit`. Paths resolve against the project directory.
56
56
  Use `at` selectors (`line:N[:COLUMN]`, `hash:H[:COLUMN]`, `symbol:NAME`,
57
57
  `page:N`, `node:ID`, or `asset:ID`) where supported. Structure defaults to
58
58
  `depth: 1`. Use separate structure, metadata, and syntax tools rather than
@@ -63,20 +63,20 @@ lines, document sections, structure trees, metadata fields, and asset paths.
63
63
  Notices identify omitted ranges and how to continue. The unchanged native result
64
64
  is retained separately in `metadata.readseek`; image attachments are unchanged.
65
65
 
66
- `readseek_find_nodes` accepts `pattern`, `context` with `selector`, or `rule`.
67
- `readseek_find_references` requires exactly one of `name` or `at`; binding
66
+ `readseek_search` accepts `pattern`, `context` with `selector`, or `rule`.
67
+ `readseek_refs` requires exactly one of `name` or `at`; binding
68
68
  references and renames use line or hash cursors. KDL selection/check rules
69
69
  may be inline or `@path`; tool calls cannot supply standard input.
70
70
 
71
- `readseek_find_text` accepts exactly one of literal `text` or regex `pattern`.
71
+ `readseek_grep` accepts exactly one of literal `text` or regex `pattern`.
72
72
  The adapter also supports `literal`, `ignoreCase`, `glob`, `context`, `limit`,
73
- and per-file `summary`. Native `find text --text` searches literally.
73
+ and per-file `summary`. Native `grep` searches literally.
74
74
 
75
75
  Read fresh `LINE:HASH` anchors before editing. Each edit item contains exactly
76
76
  one nested `set_line`, `replace_lines`, `insert_after`, `replace_symbol`, or
77
77
  `replace` object. Edits and renames default to applying after a verified plan
78
78
  and edit permission; use `apply: false` to preview and `planHash` to require
79
- that plan when applying. `write_file` replaces complete text files.
79
+ that plan when applying. `write` replaces complete text files.
80
80
 
81
81
  Syntax and rule checks treat exit 1 as findings, not transport failure;
82
82
  exit 0 is clean and exit 2 is failure. Syntax checks do not typecheck.
package/dist/index.js CHANGED
@@ -16,22 +16,22 @@ var EDIT_VARIANTS = [
16
16
  ];
17
17
  var GIT_SCOPES = ["tracked", "untracked", "ignored", "all"];
18
18
  var TOOL_NAMES = [
19
- "show_content",
20
- "show_structure",
21
- "show_metadata",
22
- "show_assets",
23
- "check_syntax",
24
- "check_rules",
25
- "generate_caption",
26
- "detect_objects",
27
- "recognize_text",
28
- "find_nodes",
29
- "find_text",
30
- "find_definitions",
31
- "find_references",
32
- "edit_text",
33
- "rename_symbol",
34
- "write_file"
19
+ "show",
20
+ "tree",
21
+ "meta",
22
+ "assets",
23
+ "syntax",
24
+ "check",
25
+ "caption",
26
+ "objects",
27
+ "ocr",
28
+ "search",
29
+ "grep",
30
+ "def",
31
+ "refs",
32
+ "edit",
33
+ "rename",
34
+ "write"
35
35
  ];
36
36
  var PARAM_DESCRIPTIONS = {
37
37
  path: "Absolute or relative file path",
@@ -47,8 +47,8 @@ var PARAM_DESCRIPTIONS = {
47
47
  name: "Qualified or unqualified symbol name",
48
48
  refsName: "Identifier to find references for",
49
49
  gitScope: "In a Git repository, which files to search: tracked, untracked, ignored (untracked plus ignored), or all. Defaults to tracked plus untracked.",
50
- at: "Location selector: line:N[:COLUMN], hash:H[:COLUMN], symbol:NAME, page:N, node:ID, or asset:ID",
51
- assetAt: "Document selector: page:N, node:ID, or asset:ID",
50
+ at: "Location selector: N[:COLUMN], START-END, H[:COLUMN], NAME, line:N[:COLUMN], hash:H[:COLUMN], symbol:NAME, page:N, node:ID, or asset:ID",
51
+ assetAt: "Document selector: N, page:N, node:ID, or asset:ID",
52
52
  rule: "KDL node selection rule, @path, or '-' for standard input",
53
53
  rules: "KDL structural checks, @path, or '-' for standard input",
54
54
  stdinName: "File name hint when the target is '-'",
@@ -60,7 +60,7 @@ var PARAM_DESCRIPTIONS = {
60
60
  kind: "Restrict structure to this node kind",
61
61
  outline: "Show outline of document hierarchy or source symbols",
62
62
  noAnchors: "Omit source line anchors",
63
- text: "Literal native text query; adapter find_text also supports regex via pattern",
63
+ text: "Literal native text query; adapter grep also supports regex via pattern",
64
64
  edits: "Use set_line, replace_lines, insert_after, replace_symbol, or replace",
65
65
  editVariant: "Exactly one nested edit variant",
66
66
  setLine: 'Replace one line: {"set_line":{"anchor":"LINE:HASH","new_text":"..."}}',
@@ -97,22 +97,22 @@ var PARAM_DESCRIPTIONS = {
97
97
  scopeContext: "Context lines within each symbol"
98
98
  };
99
99
  var TOOL_DESCRIPTIONS = {
100
- show_content: "Read source, document content, or image descriptors without inference. Obtain fresh `LINE:HASH` anchors before edits; use at with a column for cursor context. Document results include typed nodes and cached asset paths.",
101
- show_structure: "Show parsed source or document hierarchy. Use shallow depth for file overviews.",
102
- show_metadata: "Show format, source identity, language, dimensions, or page count without decoding image content or inference.",
103
- show_assets: "Return selected document asset descriptors with usable cached paths. Adapters attach images from those paths.",
104
- check_syntax: "Check parser syntax diagnostics. Exit 0 is clean, 1 has findings, 2 is failure; this is not type checking.",
105
- check_rules: "Evaluate KDL structural assertions. Exit 0 is clean, 1 has findings, 2 is failure.",
106
- generate_caption: "Explicitly infer a caption using an installed model. Include text and objects to request OCR and detection too; never downloads models automatically.",
107
- detect_objects: "Explicitly infer object labels and bounding boxes using an installed model.",
108
- recognize_text: "Explicitly recognize text from pixels using an installed model; reading never silently invokes OCR.",
109
- find_nodes: "Find AST nodes by pattern or KDL selection rule. Returns edit-ready anchors. Use `find_text` for text and regex.",
110
- find_text: "Search text or regex and return edit-ready `LINE:HASH` anchors. Native CLI text is literal; adapters preserve regex, glob, context, summary, and symbol grouping.",
111
- find_definitions: "Find a symbol definition or declaration by qualified or unqualified name.",
112
- find_references: "Find identifier-name matches with name, or binding-scoped references with at. Use before renaming or deleting a symbol.",
113
- edit_text: "Edit existing files with fresh `LINE:HASH` anchors. Each edits item contains exactly one set_line, replace_lines, insert_after, replace_symbol, or replace object. Preview before applying a verified plan.",
114
- rename_symbol: "Rename a symbol at a line or hash cursor with binding-aware edits and stale-plan protection.",
115
- write_file: "Create or replace a complete text file and return `LINE:HASH` anchors. Use `edit_text` for small changes."
100
+ show: "Read source, document content, or image descriptors without inference. Obtain fresh `LINE:HASH` anchors before edits; use at with a column for cursor context. Document results include typed nodes and cached asset paths.",
101
+ tree: "Show parsed source or document hierarchy. Use shallow depth for file overviews.",
102
+ meta: "Show format, source identity, language, dimensions, or page count without decoding image content or inference.",
103
+ assets: "Return selected document asset descriptors with usable cached paths. Adapters attach images from those paths.",
104
+ syntax: "Check parser syntax diagnostics. Exit 0 is clean, 1 has findings, 2 is failure; this is not type checking.",
105
+ check: "Evaluate KDL structural assertions. Exit 0 is clean, 1 has findings, 2 is failure.",
106
+ caption: "Explicitly infer a caption using an installed model. Include text and objects to request OCR and detection too; never downloads models automatically.",
107
+ objects: "Explicitly infer object labels and bounding boxes using an installed model.",
108
+ ocr: "Explicitly recognize text from pixels using an installed model; reading never silently invokes OCR.",
109
+ search: "Find AST nodes by pattern or KDL selection rule. Returns edit-ready anchors. Use `grep` for text and regex.",
110
+ grep: "Search text or regex and return edit-ready `LINE:HASH` anchors. Native CLI text is literal; adapters preserve regex, glob, context, summary, and symbol grouping.",
111
+ def: "Find a symbol definition or declaration by qualified or unqualified name.",
112
+ refs: "Find identifier-name matches with name, or binding-scoped references with at. Use before renaming or deleting a symbol.",
113
+ edit: "Edit existing files with fresh `LINE:HASH` anchors. Each edits item contains exactly one set_line, replace_lines, insert_after, replace_symbol, or replace object. Preview before applying a verified plan.",
114
+ rename: "Rename a symbol at a line or hash cursor with binding-aware edits and stale-plan protection.",
115
+ write: "Create or replace a complete text file and return `LINE:HASH` anchors. Use `edit` for small changes."
116
116
  };
117
117
  function rewriteBacktickedToolNames(text, aliases = {}) {
118
118
  return TOOL_NAMES.reduce((rewritten, toolName) => rewritten.replaceAll(`\`${toolName}\``, `\`${aliases[toolName] ?? toolName}\``), text);
@@ -205,48 +205,48 @@ function tool(name, title, properties, required) {
205
205
  return { name, title, description: TOOL_DESCRIPTIONS[name], inputSchema: { type: "object", properties, required, additionalProperties: false } };
206
206
  }
207
207
  var TOOL_CONTRACTS = [
208
- tool("show_content", "Show content", { ...path, ...at, ...lang, ...stdin, ...noAnchors, end: integer(PARAM_DESCRIPTIONS.end), limit: integer(PARAM_DESCRIPTIONS.limit) }, ["path"]),
209
- tool("show_structure", "Show structure", { ...path, ...at, ...lang, ...stdin, depth: integer(PARAM_DESCRIPTIONS.depth, 0), kind: string(PARAM_DESCRIPTIONS.kind), outline: { type: "boolean", description: PARAM_DESCRIPTIONS.outline } }, ["path"]),
210
- tool("show_metadata", "Show metadata", { ...path, ...lang, ...stdin }, ["path"]),
211
- tool("show_assets", "Show assets", { ...path, at: string(PARAM_DESCRIPTIONS.assetAt), ...stdin }, ["path"]),
212
- tool("check_syntax", "Check syntax", { ...path, ...lang, ...stdin }, ["path"]),
213
- tool("check_rules", "Check rules", { path: string(PARAM_DESCRIPTIONS.searchPath), ...gitScopeSchema, rules: string(PARAM_DESCRIPTIONS.rules) }, ["rules"]),
214
- tool("generate_caption", "Generate caption", { ...path, ...at, ...stdin, ...level, include: { type: "array", items: { type: "string", enum: ["text", "objects"] }, minItems: 1, uniqueItems: true, description: PARAM_DESCRIPTIONS.include } }, ["path"]),
215
- tool("detect_objects", "Detect objects", { ...path, ...at, ...stdin, ...level }, ["path"]),
216
- tool("recognize_text", "Recognize text", { ...path, ...at, ...stdin, ...level }, ["path"]),
217
- tool("find_nodes", "Find nodes", { ...path, ...lang, ...stdin, ...limit, ...gitScopeSchema, ...noAnchors, pattern: string(PARAM_DESCRIPTIONS.pattern), context: string(PARAM_DESCRIPTIONS.patternContext), selector: string(PARAM_DESCRIPTIONS.selector), rule: string(PARAM_DESCRIPTIONS.rule) }, []),
218
- tool("find_text", "Find text", { ...path, ...limit, ...gitScopeSchema, text: string(PARAM_DESCRIPTIONS.text), pattern: string(PARAM_DESCRIPTIONS.grepPattern), glob: string(PARAM_DESCRIPTIONS.glob), ignoreCase: { type: "boolean", description: PARAM_DESCRIPTIONS.ignoreCase }, literal: { type: "boolean", description: PARAM_DESCRIPTIONS.literal }, context: integer(PARAM_DESCRIPTIONS.context, 0), summary: { type: "boolean", description: PARAM_DESCRIPTIONS.summary }, scope: { type: "string", enum: ["symbol"], description: PARAM_DESCRIPTIONS.grepScope }, scopeContext: integer(PARAM_DESCRIPTIONS.scopeContext, 0) }, []),
219
- tool("find_definitions", "Find definitions", { ...path, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.name) }, ["name"]),
220
- tool("find_references", "Find references", { ...path, ...at, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.refsName) }, []),
221
- tool("edit_text", "Hash-verified edit", { ...path, ...lang, ...gitScopeSchema, ...apply, edits: { type: "array", minItems: 1, items: editItemSchema, description: PARAM_DESCRIPTIONS.edits }, postEditVerify: { type: "boolean", description: PARAM_DESCRIPTIONS.postEditVerify } }, ["path", "edits"]),
222
- tool("rename_symbol", "Rename symbol", { ...path, ...at, ...lang, ...gitScopeSchema, ...apply, to: string(PARAM_DESCRIPTIONS.to), workspace: { type: "boolean", description: PARAM_DESCRIPTIONS.workspace } }, ["path", "at", "to"]),
223
- tool("write_file", "Write file", { ...path, content: string(PARAM_DESCRIPTIONS.content) }, ["path", "content"])
208
+ tool("show", "Show content", { ...path, ...at, ...lang, ...stdin, ...noAnchors, end: integer(PARAM_DESCRIPTIONS.end), limit: integer(PARAM_DESCRIPTIONS.limit) }, ["path"]),
209
+ tool("tree", "Show structure", { ...path, ...at, ...lang, ...stdin, depth: integer(PARAM_DESCRIPTIONS.depth, 0), kind: string(PARAM_DESCRIPTIONS.kind), outline: { type: "boolean", description: PARAM_DESCRIPTIONS.outline } }, ["path"]),
210
+ tool("meta", "Show metadata", { ...path, ...lang, ...stdin }, ["path"]),
211
+ tool("assets", "Show assets", { ...path, at: string(PARAM_DESCRIPTIONS.assetAt), ...stdin }, ["path"]),
212
+ tool("syntax", "Check syntax", { ...path, ...lang, ...stdin }, ["path"]),
213
+ tool("check", "Check rules", { path: string(PARAM_DESCRIPTIONS.searchPath), ...gitScopeSchema, rules: string(PARAM_DESCRIPTIONS.rules) }, ["rules"]),
214
+ tool("caption", "Generate caption", { ...path, ...at, ...stdin, ...level, include: { type: "array", items: { type: "string", enum: ["text", "objects"] }, minItems: 1, uniqueItems: true, description: PARAM_DESCRIPTIONS.include } }, ["path"]),
215
+ tool("objects", "Detect objects", { ...path, ...at, ...stdin, ...level }, ["path"]),
216
+ tool("ocr", "Recognize text", { ...path, ...at, ...stdin, ...level }, ["path"]),
217
+ tool("search", "Search AST nodes", { ...path, ...lang, ...stdin, ...limit, ...gitScopeSchema, ...noAnchors, pattern: string(PARAM_DESCRIPTIONS.pattern), context: string(PARAM_DESCRIPTIONS.patternContext), selector: string(PARAM_DESCRIPTIONS.selector), rule: string(PARAM_DESCRIPTIONS.rule) }, []),
218
+ tool("grep", "Search text", { ...path, ...limit, ...gitScopeSchema, text: string(PARAM_DESCRIPTIONS.text), pattern: string(PARAM_DESCRIPTIONS.grepPattern), glob: string(PARAM_DESCRIPTIONS.glob), ignoreCase: { type: "boolean", description: PARAM_DESCRIPTIONS.ignoreCase }, literal: { type: "boolean", description: PARAM_DESCRIPTIONS.literal }, context: integer(PARAM_DESCRIPTIONS.context, 0), summary: { type: "boolean", description: PARAM_DESCRIPTIONS.summary }, scope: { type: "string", enum: ["symbol"], description: PARAM_DESCRIPTIONS.grepScope }, scopeContext: integer(PARAM_DESCRIPTIONS.scopeContext, 0) }, []),
219
+ tool("def", "Find definitions", { ...path, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.name) }, ["name"]),
220
+ tool("refs", "Find references", { ...path, ...at, ...lang, ...gitScopeSchema, ...noAnchors, name: string(PARAM_DESCRIPTIONS.refsName) }, []),
221
+ tool("edit", "Hash-verified edit", { ...path, ...lang, ...gitScopeSchema, ...apply, edits: { type: "array", minItems: 1, items: editItemSchema, description: PARAM_DESCRIPTIONS.edits }, postEditVerify: { type: "boolean", description: PARAM_DESCRIPTIONS.postEditVerify } }, ["path", "edits"]),
222
+ tool("rename", "Rename symbol", { ...path, ...at, ...lang, ...gitScopeSchema, ...apply, to: string(PARAM_DESCRIPTIONS.to), workspace: { type: "boolean", description: PARAM_DESCRIPTIONS.workspace } }, ["path", "at", "to"]),
223
+ tool("write", "Write file", { ...path, content: string(PARAM_DESCRIPTIONS.content) }, ["path", "content"])
224
224
  ];
225
225
  // ../readseek-api/src/policy.ts
226
226
  var BUILTIN_FALLBACKS = {
227
- read: "show_content",
228
- edit: "edit_text",
229
- write: "write_file",
230
- grep: "find_text",
231
- apply_patch: "edit_text"
227
+ read: "show",
228
+ edit: "edit",
229
+ write: "write",
230
+ grep: "grep",
231
+ apply_patch: "edit"
232
232
  };
233
233
  var PREFERENCE_LEADS = {
234
- show_content: "Preferred for reading source with anchors.",
235
- edit_text: "Preferred for editing existing text files with fresh LINE:HASH anchors.",
236
- write_file: "Preferred for creating or replacing a complete text file; returns LINE:HASH anchors.",
237
- find_text: "Preferred text/regex search; returns edit-ready LINE:HASH anchors.",
238
- find_nodes: "Preferred for AST or structural code search with ast-grep-style patterns.",
239
- find_definitions: "Preferred for go-to-definition or declaration lookup by name.",
240
- find_references: "Preferred for finding identifier-name matches or binding-specific references before rename_symbol or delete.",
241
- rename_symbol: "Preferred for renaming a symbol with binding-aware, verified edits.",
242
- show_assets: "Preferred for materializing selected document assets with usable cached paths."
234
+ show: "Preferred for reading source with anchors.",
235
+ edit: "Preferred for editing existing text files with fresh LINE:HASH anchors.",
236
+ write: "Preferred for creating or replacing a complete text file; returns LINE:HASH anchors.",
237
+ grep: "Preferred text/regex search; returns edit-ready LINE:HASH anchors.",
238
+ search: "Preferred for AST or structural code search with ast-grep-style patterns.",
239
+ def: "Preferred for go-to-definition or declaration lookup by name.",
240
+ refs: "Preferred for finding identifier-name matches or binding-specific references before `rename` or delete.",
241
+ rename: "Preferred for renaming a symbol with binding-aware, verified edits.",
242
+ assets: "Preferred for materializing selected document assets with usable cached paths."
243
243
  };
244
244
  var FALLBACK_TEMPLATES = {
245
- read: "Prefer `show_content` with fresh LINE:HASH anchors.",
246
- edit: "Prefer `edit_text` with fresh LINE:HASH anchors.",
247
- write: "Prefer `write_file` so the result returns LINE:HASH anchors.",
248
- grep: "Prefer `find_text` for text/regex search with edit-ready anchors.",
249
- apply_patch: "Prefer `edit_text` for existing text files."
245
+ read: "Prefer `show` with fresh LINE:HASH anchors.",
246
+ edit: "Prefer `edit` with fresh LINE:HASH anchors.",
247
+ write: "Prefer `write` so the result returns LINE:HASH anchors.",
248
+ grep: "Prefer `grep` for text/regex search with edit-ready anchors.",
249
+ apply_patch: "Prefer `edit` for existing text files."
250
250
  };
251
251
  function resolveToolName(name, aliases = {}) {
252
252
  return aliases[name] ?? name;
@@ -262,21 +262,21 @@ function renderFallbackToolDescription(builtIn, aliases = {}) {
262
262
  }
263
263
  function renderToolRoutingPolicy(options = {}) {
264
264
  const aliases = options.aliases ?? {};
265
- const show_content = resolveToolName("show_content", aliases);
266
- const edit_text = resolveToolName("edit_text", aliases);
267
- const write_file = resolveToolName("write_file", aliases);
268
- const find_text = resolveToolName("find_text", aliases);
269
- const find_nodes = resolveToolName("find_nodes", aliases);
270
- const find_definitions = resolveToolName("find_definitions", aliases);
271
- const find_references = resolveToolName("find_references", aliases);
272
- const rename_symbol = resolveToolName("rename_symbol", aliases);
273
- const show_assets = resolveToolName("show_assets", aliases);
265
+ const show = resolveToolName("show", aliases);
266
+ const edit = resolveToolName("edit", aliases);
267
+ const write = resolveToolName("write", aliases);
268
+ const grep = resolveToolName("grep", aliases);
269
+ const search = resolveToolName("search", aliases);
270
+ const def = resolveToolName("def", aliases);
271
+ const refs = resolveToolName("refs", aliases);
272
+ const rename = resolveToolName("rename", aliases);
273
+ const assets = resolveToolName("assets", aliases);
274
274
  const title = options.title ?? "ReadSeek tool policy:";
275
275
  const bullets = [];
276
276
  if (options.preferOverBuiltIns) {
277
277
  bullets.push("- Prefer ReadSeek tools over built-ins when they can do the job.");
278
278
  }
279
- bullets.push(`- Read with ${show_content} first; ${edit_text} needs fresh LINE:HASH anchors.`, `- Use ${find_text} for text/regex, ${find_nodes} for AST patterns, ${find_definitions}/${find_references} for targeted symbols, and shallow ${resolveToolName("show_structure", aliases)} structures only for file overviews.`, `- Use ${edit_text} for existing files, ${write_file} for whole-file creation or replacement, and ${rename_symbol} for symbol renames.`, `- Use ${resolveToolName("show_structure", aliases)} for document structure; run ${resolveToolName("check_syntax", aliases)} after source edits for a quick syntax check.`, `- Use ${show_assets} to materialize selected document assets and read their returned paths.`);
279
+ bullets.push(`- Read with ${show} first; ${edit} needs fresh LINE:HASH anchors.`, `- Use ${grep} for text/regex, ${search} for AST patterns, ${def}/${refs} for targeted symbols, and shallow ${resolveToolName("tree", aliases)} structures only for file overviews.`, `- Use ${edit} for existing files, ${write} for whole-file creation or replacement, and ${rename} for symbol renames.`, `- Use ${resolveToolName("tree", aliases)} for document structure; run ${resolveToolName("syntax", aliases)} after source edits for a quick syntax check.`, `- Use ${assets} to materialize selected document assets and read their returned paths.`);
280
280
  if (options.demoteBuiltIns && options.demoteBuiltIns.length > 0) {
281
281
  bullets.push(`- Do not use built-in ${options.demoteBuiltIns.join(", ")} when a ReadSeek tool can do the job.`);
282
282
  }
@@ -420,50 +420,111 @@ var SELECTOR_KINDS = ["line", "hash", "symbol", "page", "node", "asset"];
420
420
  function isSelectorKind(value) {
421
421
  return SELECTOR_KINDS.includes(value);
422
422
  }
423
+ function parsePositiveSelectorInt(raw, name) {
424
+ if (!/^-?\d+$/.test(raw))
425
+ throw new Error(`invalid ${name} \`${raw}\``);
426
+ const parsed = Number(raw);
427
+ if (!Number.isSafeInteger(parsed))
428
+ throw new Error(`invalid ${name} \`${raw}\``);
429
+ if (parsed < 1)
430
+ throw new Error(`${name} must be greater than zero`);
431
+ return parsed;
432
+ }
433
+ function parseLineSelector(value, explicitKind) {
434
+ const parts = value.split(":");
435
+ if (parts.length > 2)
436
+ throw new Error("selector has too many components");
437
+ const head = parts[0];
438
+ if (parts.length === 2) {
439
+ if (head.slice(1).includes("-"))
440
+ throw new Error("line range cannot include a column");
441
+ const line = parsePositiveSelectorInt(head, "line");
442
+ const column = parsePositiveSelectorInt(parts[1], "column");
443
+ return { kind: "line", value: String(line), column, explicitKind };
444
+ }
445
+ const dash = head.indexOf("-", 1);
446
+ if (dash > 0) {
447
+ const start = parsePositiveSelectorInt(head.slice(0, dash), "line");
448
+ const endLine = parsePositiveSelectorInt(head.slice(dash + 1), "end line");
449
+ if (endLine < start)
450
+ throw new Error(`end line ${endLine} precedes start line ${start}`);
451
+ return { kind: "line", value: String(start), endLine, explicitKind };
452
+ }
453
+ const line = parsePositiveSelectorInt(head, "line");
454
+ return { kind: "line", value: String(line), explicitKind };
455
+ }
456
+ function parseHashSelector(value, explicitKind) {
457
+ const parts = value.split(":");
458
+ if (parts.length > 2)
459
+ throw new Error("selector has too many components");
460
+ const head = parts[0];
461
+ if (!/^[0-9a-fA-F]{6}$/.test(head))
462
+ throw new Error(`invalid line hash \`${head}\``);
463
+ if (parts.length === 2) {
464
+ const column = parsePositiveSelectorInt(parts[1], "column");
465
+ return { kind: "hash", value: head, column, explicitKind };
466
+ }
467
+ return { kind: "hash", value: head, explicitKind };
468
+ }
469
+ function isDocumentSelector(parsed) {
470
+ return ["page", "node", "asset"].includes(parsed.kind) || parsed.kind === "line" && !parsed.explicitKind && parsed.column === undefined && parsed.endLine === undefined;
471
+ }
472
+ function isBindingSelector(parsed) {
473
+ if (parsed.endLine !== undefined)
474
+ return false;
475
+ if (parsed.kind === "line" || parsed.kind === "hash")
476
+ return true;
477
+ return parsed.kind === "symbol" && !parsed.explicitKind && /^[0-9a-fA-F]{6}$/.test(parsed.value);
478
+ }
423
479
  function parseSelector(text) {
480
+ if (text.length === 0)
481
+ throw new Error("selector must not be empty");
424
482
  const separator = text.indexOf(":");
425
- if (separator < 0) {
426
- throw new Error("selector must start with line:, hash:, symbol:, page:, node:, or asset:");
427
- }
428
- const kind = text.slice(0, separator);
429
- const value = text.slice(separator + 1);
430
- if (value.length === 0)
431
- throw new Error(`${kind} selector must not be empty`);
432
- if (!isSelectorKind(kind)) {
483
+ const hasSingleColon = separator >= 0 && text[separator + 1] !== ":";
484
+ if (hasSingleColon) {
485
+ const kind = text.slice(0, separator);
486
+ const value = text.slice(separator + 1);
487
+ if (isSelectorKind(kind)) {
488
+ if (value.length === 0)
489
+ throw new Error(`${kind} selector must not be empty`);
490
+ if (kind === "line")
491
+ return parseLineSelector(value, true);
492
+ if (kind === "hash")
493
+ return parseHashSelector(value, true);
494
+ if (kind === "page") {
495
+ if (value.includes(":"))
496
+ throw new Error("page selector has too many components");
497
+ parsePositiveSelectorInt(value, "page");
498
+ }
499
+ return { kind, value, explicitKind: true };
500
+ }
501
+ if (/^\d+$/.test(kind))
502
+ return parseLineSelector(text, false);
503
+ if (/^[0-9a-fA-F]{6}$/.test(kind) && /^\d+$/.test(value))
504
+ return parseHashSelector(text, false);
433
505
  throw new Error(`unknown selector kind \`${kind}\`; expected line, hash, symbol, page, node, or asset`);
434
506
  }
435
- if (kind === "line" || kind === "hash") {
436
- const parts = value.split(":");
437
- if (parts.length > 2)
438
- throw new Error("selector has too many components");
439
- if (parts.length === 2) {
440
- const column = Number(parts[1]);
441
- if (!Number.isSafeInteger(column))
442
- throw new Error(`invalid column \`${parts[1]}\``);
443
- if (column < 1)
444
- throw new Error("column must be greater than zero");
445
- return { kind, value: parts[0], column };
507
+ if (/^[0-9-]/.test(text)) {
508
+ if (/^[0-9a-fA-F]{6}$/.test(text) && /[a-fA-F]/.test(text)) {
509
+ return parseHashSelector(text, false);
446
510
  }
511
+ return parseLineSelector(text, false);
447
512
  }
448
- if (kind === "page") {
449
- if (value.includes(":"))
450
- throw new Error("page selector has too many components");
451
- const page = Number(value);
452
- if (!Number.isSafeInteger(page))
453
- throw new Error(`invalid page \`${value}\``);
454
- if (page < 1)
455
- throw new Error("page must be greater than zero");
513
+ if (/^[0-9a-fA-F]{6}$/.test(text) && /\d/.test(text)) {
514
+ return parseHashSelector(text, false);
456
515
  }
457
- return { kind, value };
516
+ if (/\s/.test(text))
517
+ throw new Error(`invalid selector \`${text}\``);
518
+ return { kind: "symbol", value: text, explicitKind: false };
458
519
  }
459
- function start(verb, object, input) {
520
+ function start(command, input) {
460
521
  if (!input.path)
461
- throw new Error(`${verb} ${object} requires a path`);
522
+ throw new Error(`${command} requires a path`);
462
523
  if (input.stdinName !== undefined && input.path !== "-")
463
524
  throw new Error("stdinName requires '-' as the target");
464
525
  const args = [];
465
526
  pushOptionalString(args, "--readseek-dir", input.readseekDir);
466
- args.push(verb, object, input.path);
527
+ args.push(command, input.path);
467
528
  pushOptionalString(args, "--stdin-name", input.stdinName);
468
529
  return args;
469
530
  }
@@ -489,12 +550,12 @@ function anchors(args, input) {
489
550
  if (input.noAnchors)
490
551
  args.push("--no-anchors");
491
552
  }
492
- function buildShowContentArgs(input) {
553
+ function buildShowArgs(input) {
493
554
  if (input.end !== undefined)
494
555
  validatePositiveInteger(input.end, "end");
495
556
  if (input.end !== undefined && input.limit !== undefined)
496
557
  throw new Error("cannot combine end with limit");
497
- const args = start("show", "content", input);
558
+ const args = start("show", input);
498
559
  at2(args, input.at);
499
560
  pushOptionalNumber(args, "--end", input.end);
500
561
  limit2(args, input.limit);
@@ -502,10 +563,10 @@ function buildShowContentArgs(input) {
502
563
  anchors(args, input);
503
564
  return finish(args);
504
565
  }
505
- function buildShowStructureArgs(input) {
566
+ function buildTreeArgs(input) {
506
567
  if (input.depth !== undefined && (!Number.isSafeInteger(input.depth) || input.depth < 0))
507
568
  throw new Error("depth must be a non-negative integer");
508
- const args = start("show", "structure", input);
569
+ const args = start("tree", input);
509
570
  at2(args, input.at);
510
571
  pushOptionalNumber(args, "--depth", input.depth);
511
572
  pushOptionalString(args, "--kind", input.kind);
@@ -514,35 +575,35 @@ function buildShowStructureArgs(input) {
514
575
  args.push("--outline");
515
576
  return finish(args);
516
577
  }
517
- function buildShowMetadataArgs(input) {
518
- const args = start("show", "metadata", input);
578
+ function buildMetaArgs(input) {
579
+ const args = start("meta", input);
519
580
  language(args, input);
520
581
  return finish(args);
521
582
  }
522
- function buildShowAssetsArgs(input) {
523
- if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
583
+ function buildAssetsArgs(input) {
584
+ if (input.at !== undefined && !isDocumentSelector(parseSelector(input.at)))
524
585
  throw new Error("assets requires a page, node, or asset selector");
525
- const args = start("show", "assets", input);
586
+ const args = start("assets", input);
526
587
  at2(args, input.at);
527
588
  return finish(args);
528
589
  }
529
- function buildCheckSyntaxArgs(input) {
530
- const args = start("check", "syntax", input);
590
+ function buildSyntaxArgs(input) {
591
+ const args = start("syntax", input);
531
592
  language(args, input);
532
593
  return finish(args);
533
594
  }
534
- function visionArgs(verb, object, input) {
595
+ function visionArgs(command, input) {
535
596
  if (input.level !== undefined && !VISION_LEVELS.includes(input.level))
536
597
  throw new Error("invalid vision level");
537
- if (input.at !== undefined && !["page", "node", "asset"].includes(parseSelector(input.at).kind))
598
+ if (input.at !== undefined && !isDocumentSelector(parseSelector(input.at)))
538
599
  throw new Error("vision requires a document selector");
539
- const args = start(verb, object, input);
600
+ const args = start(command, input);
540
601
  at2(args, input.at);
541
602
  pushOptionalString(args, "--level", input.level);
542
603
  return args;
543
604
  }
544
- function buildGenerateCaptionArgs(input) {
545
- const args = visionArgs("generate", "caption", input);
605
+ function buildCaptionArgs(input) {
606
+ const args = visionArgs("caption", input);
546
607
  if (input.include !== undefined) {
547
608
  if (input.include.length === 0 || input.include.some((task) => task !== "text" && task !== "objects"))
548
609
  throw new Error("include requires text or objects");
@@ -550,13 +611,13 @@ function buildGenerateCaptionArgs(input) {
550
611
  }
551
612
  return finish(args);
552
613
  }
553
- function buildDetectObjectsArgs(input) {
554
- return finish(visionArgs("detect", "objects", input));
614
+ function buildObjectsArgs(input) {
615
+ return finish(visionArgs("objects", input));
555
616
  }
556
- function buildRecognizeTextArgs(input) {
557
- return finish(visionArgs("recognize", "text", input));
617
+ function buildOcrArgs(input) {
618
+ return finish(visionArgs("ocr", input));
558
619
  }
559
- function buildFindNodesArgs(input) {
620
+ function buildSearchArgs(input) {
560
621
  const hasPattern = Boolean(input.pattern);
561
622
  const hasRule = Boolean(input.rule);
562
623
  const hasContext = Boolean(input.context);
@@ -564,7 +625,7 @@ function buildFindNodesArgs(input) {
564
625
  if (hasPattern || hasContext || input.selector)
565
626
  throw new Error("rule cannot be combined with pattern, context, or selector");
566
627
  } else if (!hasPattern && !hasContext) {
567
- throw new Error("find nodes requires pattern, context, or rule");
628
+ throw new Error("search requires pattern, context, or rule");
568
629
  }
569
630
  if (hasContext && !input.selector) {
570
631
  throw new Error("context requires selector");
@@ -572,7 +633,7 @@ function buildFindNodesArgs(input) {
572
633
  if (hasPattern && hasContext) {
573
634
  throw new Error("pattern and context cannot be combined");
574
635
  }
575
- const args = start("find", "nodes", input);
636
+ const args = start("search", input);
576
637
  pushOptionalString(args, "--pattern", input.pattern);
577
638
  pushOptionalString(args, "--context", input.context);
578
639
  pushOptionalString(args, "--selector", input.selector);
@@ -583,28 +644,28 @@ function buildFindNodesArgs(input) {
583
644
  anchors(args, input);
584
645
  return finish(args);
585
646
  }
586
- function buildFindTextArgs(input) {
587
- const args = start("find", "text", input);
647
+ function buildGrepArgs(input) {
648
+ const args = start("grep", input);
588
649
  args.push("--text", input.text);
589
650
  limit2(args, input.limit);
590
651
  appendGitScopeArgs(args, input);
591
652
  return finish(args);
592
653
  }
593
- function buildFindDefinitionsArgs(input) {
594
- const args = start("find", "definitions", input);
654
+ function buildDefArgs(input) {
655
+ const args = start("def", input);
595
656
  args.push("--name", input.name);
596
657
  language(args, input);
597
658
  appendGitScopeArgs(args, input);
598
659
  anchors(args, input);
599
660
  return finish(args);
600
661
  }
601
- function buildFindReferencesArgs(input) {
662
+ function buildRefsArgs(input) {
602
663
  const validated = validateReferencesSelection(input);
603
664
  if (!validated.ok)
604
665
  throw new Error(validated.error);
605
- if (input.at !== undefined && !["line", "hash"].includes(parseSelector(input.at).kind))
666
+ if (input.at !== undefined && !isBindingSelector(parseSelector(input.at)))
606
667
  throw new Error("references requires a line or hash selector");
607
- const args = start("find", "references", input);
668
+ const args = start("refs", input);
608
669
  pushOptionalString(args, "--name", input.name);
609
670
  at2(args, input.at);
610
671
  language(args, input);
@@ -612,14 +673,14 @@ function buildFindReferencesArgs(input) {
612
673
  anchors(args, input);
613
674
  return finish(args);
614
675
  }
615
- function buildCheckRulesArgs(input) {
616
- const args = start("check", "rules", input);
676
+ function buildCheckArgs(input) {
677
+ const args = start("check", input);
617
678
  args.push("--rules", input.rules);
618
679
  appendGitScopeArgs(args, input);
619
680
  return finish(args);
620
681
  }
621
- function buildEditTextArgs(input) {
622
- const args = start("edit", "text", input);
682
+ function buildEditArgs(input) {
683
+ const args = start("edit", input);
623
684
  appendApplyAndPlanHash(args, input);
624
685
  language(args, input);
625
686
  appendGitScopeArgs(args, input);
@@ -627,10 +688,10 @@ function buildEditTextArgs(input) {
627
688
  args.push("--edits", "-");
628
689
  return finish(args);
629
690
  }
630
- function buildRenameSymbolArgs(input) {
631
- if (!["line", "hash"].includes(parseSelector(input.at).kind))
691
+ function buildRenameArgs(input) {
692
+ if (!isBindingSelector(parseSelector(input.at)))
632
693
  throw new Error("rename requires a line or hash selector");
633
- const args = start("rename", "symbol", input);
694
+ const args = start("rename", input);
634
695
  at2(args, input.at);
635
696
  args.push("--to", input.to);
636
697
  if (input.workspace !== undefined)
@@ -1016,7 +1077,7 @@ function serializeEditPlan(edits) {
1016
1077
  }
1017
1078
  // ../readseek-api/src/show-presentation.ts
1018
1079
  function isShowTool(name) {
1019
- return name === "show_content" || name === "show_structure" || name === "show_metadata" || name === "show_assets";
1080
+ return name === "show" || name === "tree" || name === "meta" || name === "assets";
1020
1081
  }
1021
1082
  function record(value) {
1022
1083
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -1131,7 +1192,7 @@ function presentShowResult(tool, value, options = {}) {
1131
1192
  const path = inline(options.path || output.source || output.file || content.file || structure.file || metadata.file || cursor.file) || "(unknown path)";
1132
1193
  const summary = [];
1133
1194
  const result = { summary: "", body: "", notices: [], metadata: {} };
1134
- if (tool === "show_metadata") {
1195
+ if (tool === "meta") {
1135
1196
  const data = Object.keys(metadata).length > 0 ? metadata : output;
1136
1197
  if (text(data.format || data.language || data.type))
1137
1198
  summary.push(inline(data.format || data.language || data.type));
@@ -1140,7 +1201,7 @@ function presentShowResult(tool, value, options = {}) {
1140
1201
  summary.push(plural(result.metadata.pages, "page"));
1141
1202
  }
1142
1203
  result.body = fields(data) || "No metadata available.";
1143
- } else if (tool === "show_assets") {
1204
+ } else if (tool === "assets") {
1144
1205
  const assets = records(output.assets);
1145
1206
  result.metadata.assets = assets.length;
1146
1207
  summary.push(plural(assets.length, "asset"));
@@ -1154,7 +1215,7 @@ function presentShowResult(tool, value, options = {}) {
1154
1215
  summary.push(plural(nodes.length, "node"));
1155
1216
  if (result.metadata.pages !== undefined)
1156
1217
  summary.push(plural(result.metadata.pages, "page"));
1157
- const sections = [text(output.title) ? safe(text(output.title)) : "", documentNodes(nodes, tool === "show_content")];
1218
+ const sections = [text(output.title) ? safe(text(output.title)) : "", documentNodes(nodes, tool === "show")];
1158
1219
  if (assets.length > 0) {
1159
1220
  result.metadata.assets = assets.length;
1160
1221
  sections.push(`Assets
@@ -1163,7 +1224,7 @@ ${assetList(assets)}`);
1163
1224
  result.body = sections.filter(Boolean).join(`
1164
1225
 
1165
1226
  `) || "No content in this selection.";
1166
- } else if (tool === "show_structure") {
1227
+ } else if (tool === "tree") {
1167
1228
  const symbols = records(structure.symbols);
1168
1229
  result.metadata.symbols = symbols.length;
1169
1230
  summary.push(plural(symbols.length, "symbol"));
@@ -1217,7 +1278,7 @@ ${assetList(assets)}`);
1217
1278
  const description = Object.keys(content).length > 0 ? content : output;
1218
1279
  result.body = fields(description) || "No content in this selection.";
1219
1280
  }
1220
- if (tool === "show_structure")
1281
+ if (tool === "tree")
1221
1282
  result.notices.push("Structure is limited to the requested depth, kind, and outline. Use a deeper depth or focus with at to inspect further.");
1222
1283
  if (text(output.warning))
1223
1284
  result.notices.push(safe(text(output.warning)));
@@ -1672,7 +1733,7 @@ function acceptsReadSeekExitCode(args, exitCode) {
1672
1733
  index++;
1673
1734
  continue;
1674
1735
  }
1675
- return arg === "find" || arg === "check";
1736
+ return arg === "grep" || arg === "search" || arg === "def" || arg === "refs" || arg === "syntax" || arg === "check";
1676
1737
  }
1677
1738
  return false;
1678
1739
  }
@@ -1873,12 +1934,12 @@ function resolveImagePolicy(options) {
1873
1934
  throw new Error('opencode-readseek imageMode must be "on", "auto", or "off"');
1874
1935
  }
1875
1936
  function contentArgs(filePath, options = {}) {
1876
- return buildShowContentArgs({ path: filePath, ...options, at: options.at ?? (options.end === undefined ? undefined : "line:1") });
1937
+ return buildShowArgs({ path: filePath, ...options, at: options.at ?? (options.end === undefined ? undefined : "line:1") });
1877
1938
  }
1878
1939
  function requireContent(envelope) {
1879
1940
  const value = record2(envelope).content;
1880
1941
  if (value === undefined || value === null || typeof value !== "object") {
1881
- throw new Error("show content returned no source content");
1942
+ throw new Error("show returned no source content");
1882
1943
  }
1883
1944
  return value;
1884
1945
  }
@@ -1954,7 +2015,7 @@ async function ensureReadSeekCache(context) {
1954
2015
  if (error.code !== "ENOENT")
1955
2016
  throw error;
1956
2017
  }
1957
- readSeekCacheInit ??= runReadSeekRaw(context, ["--readseek-dir", cacheDir, "initialize", "index"], { cancelable: false }).then(() => cacheDir).finally(() => {
2018
+ readSeekCacheInit ??= runReadSeekRaw(context, ["--readseek-dir", cacheDir, "init"], { cancelable: false }).then(() => cacheDir).finally(() => {
1958
2019
  readSeekCacheInit = undefined;
1959
2020
  });
1960
2021
  return readSeekCacheInit;
@@ -2372,31 +2433,31 @@ import { pathToFileURL } from "node:url";
2372
2433
  import { tool as tool2 } from "@opencode-ai/plugin";
2373
2434
  function initialTitle(kind, args) {
2374
2435
  switch (kind) {
2375
- case "show_structure":
2376
- case "show_metadata":
2377
- case "check_syntax":
2378
- case "check_rules":
2379
- case "generate_caption":
2380
- case "detect_objects":
2381
- case "recognize_text":
2382
- return `${kind.replaceAll("_", " ")} ${args.path}`;
2383
- case "show_content":
2436
+ case "tree":
2437
+ case "meta":
2438
+ case "syntax":
2439
+ case "check":
2440
+ case "caption":
2441
+ case "objects":
2442
+ case "ocr":
2443
+ return `${kind} ${args.path}`;
2444
+ case "show":
2384
2445
  return `Show content ${args.path}`;
2385
- case "show_assets":
2446
+ case "assets":
2386
2447
  return `Show assets ${args.path}`;
2387
- case "find_nodes":
2448
+ case "search":
2388
2449
  return `Find nodes ${args.pattern ?? args.context ?? args.rule}`;
2389
- case "find_text":
2450
+ case "grep":
2390
2451
  return `Find text ${args.pattern ?? args.text}`;
2391
- case "find_definitions":
2452
+ case "def":
2392
2453
  return `Find definition ${args.name}`;
2393
- case "find_references":
2454
+ case "refs":
2394
2455
  return `Find references to ${args.name ?? args.at}`;
2395
- case "rename_symbol":
2456
+ case "rename":
2396
2457
  return `Rename ${args.path}:${args.at} to ${args.to}`;
2397
- case "edit_text":
2458
+ case "edit":
2398
2459
  return `Edit ${args.path}`;
2399
- case "write_file":
2460
+ case "write":
2400
2461
  return `Write ${args.path}`;
2401
2462
  }
2402
2463
  }
@@ -2407,18 +2468,18 @@ function resultPresentation(kind, args, value) {
2407
2468
  return { title: presentation.summary, metadata: presentation.metadata };
2408
2469
  }
2409
2470
  switch (kind) {
2410
- case "check_syntax": {
2471
+ case "syntax": {
2411
2472
  const diagnostics = record2(output.diagnostics ?? output);
2412
2473
  const errors = typeof diagnostics.error_count === "number" ? diagnostics.error_count : 0;
2413
2474
  const missing = typeof diagnostics.missing_count === "number" ? diagnostics.missing_count : 0;
2414
2475
  return { title: `Syntax ${args.path} (${errors} errors, ${missing} missing)`, metadata: { error_count: errors, missing_count: missing } };
2415
2476
  }
2416
- case "find_nodes": {
2477
+ case "search": {
2417
2478
  const results = items(output.results);
2418
2479
  const matches = results.reduce((total, result) => total + items(record2(result).matches).length, 0);
2419
2480
  return { title: `Found ${matches} matches`, metadata: { results: results.length, matches } };
2420
2481
  }
2421
- case "find_text": {
2482
+ case "grep": {
2422
2483
  const results = items(output.results);
2423
2484
  const matches = results.reduce((total, result) => {
2424
2485
  const entry = record2(result);
@@ -2426,15 +2487,15 @@ function resultPresentation(kind, args, value) {
2426
2487
  }, 0);
2427
2488
  return { title: `Found ${matches} matches`, metadata: { results: results.length, matches } };
2428
2489
  }
2429
- case "find_definitions": {
2490
+ case "def": {
2430
2491
  const locations = items(output.locations).length;
2431
2492
  return { title: `Found ${locations} definitions`, metadata: { locations } };
2432
2493
  }
2433
- case "find_references": {
2494
+ case "refs": {
2434
2495
  const references = items(output.references).length;
2435
2496
  return { title: `Found ${references} references`, metadata: { references } };
2436
2497
  }
2437
- case "rename_symbol": {
2498
+ case "rename": {
2438
2499
  const oldName = output.old_name;
2439
2500
  const newName = output.new_name;
2440
2501
  const otherOutputs = items(output.others).map(record2);
@@ -2444,10 +2505,10 @@ function resultPresentation(kind, args, value) {
2444
2505
  const title = typeof oldName === "string" && typeof newName === "string" ? `${output.applied === true ? "Renamed" : "Plan"} ${oldName} -> ${newName}` : initialTitle(kind, args);
2445
2506
  return { title, metadata: { edits, conflicts, others } };
2446
2507
  }
2447
- case "edit_text":
2448
- case "write_file": {
2508
+ case "edit":
2509
+ case "write": {
2449
2510
  const preview = typeof output.preview_error === "string" ? " (preview unavailable)" : "";
2450
- return { title: `${kind === "edit_text" ? "Edited" : "Wrote"} ${args.path}${preview}`, metadata: {} };
2511
+ return { title: `${kind === "edit" ? "Edited" : "Wrote"} ${args.path}${preview}`, metadata: {} };
2451
2512
  }
2452
2513
  }
2453
2514
  return { title: initialTitle(kind, args), metadata: {} };
@@ -2493,7 +2554,7 @@ function readseekTool(description, args, kind, execute, imagePolicy) {
2493
2554
  function createReadSeekTools(imagePolicy) {
2494
2555
  return {
2495
2556
  ...createAccessTools(imagePolicy),
2496
- readseek_find_text: readseekTool(openCodeToolDescription("find_text"), {
2557
+ readseek_grep: readseekTool(openCodeToolDescription("grep"), {
2497
2558
  pattern: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.grepPattern),
2498
2559
  text: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.text),
2499
2560
  summary: tool3.schema.boolean().optional().describe(PARAM_DESCRIPTIONS.summary),
@@ -2503,7 +2564,7 @@ function createReadSeekTools(imagePolicy) {
2503
2564
  ignoreCase: tool3.schema.boolean().optional().describe(PARAM_DESCRIPTIONS.ignoreCase),
2504
2565
  context: tool3.schema.number().int().nonnegative().optional().describe(PARAM_DESCRIPTIONS.context),
2505
2566
  limit: tool3.schema.number().int().positive().optional().describe(PARAM_DESCRIPTIONS.matchLimit)
2506
- }, "find_text", async (input, context) => {
2567
+ }, "grep", async (input, context) => {
2507
2568
  const target = resolvePath(context.directory, input.path ?? ".");
2508
2569
  if (input.pattern === undefined === (input.text === undefined)) {
2509
2570
  throw new Error("exactly one of pattern or text is required");
@@ -2511,7 +2572,7 @@ function createReadSeekTools(imagePolicy) {
2511
2572
  const pattern = input.pattern ?? input.text;
2512
2573
  await authorizeSearch(context, target, pattern);
2513
2574
  if (input.text !== undefined && !input.glob && !input.ignoreCase && !input.context && !input.summary) {
2514
- return runReadSeek(context, buildFindTextArgs({ path: target, text: pattern, limit: input.limit }));
2575
+ return runReadSeek(context, buildGrepArgs({ path: target, text: pattern, limit: input.limit }));
2515
2576
  }
2516
2577
  let expression;
2517
2578
  try {
@@ -2593,7 +2654,7 @@ function createReadSeekTools(imagePolicy) {
2593
2654
  }
2594
2655
  return { results, truncated };
2595
2656
  }),
2596
- readseek_find_nodes: readseekTool(openCodeToolDescription("find_nodes"), {
2657
+ readseek_search: readseekTool(openCodeToolDescription("search"), {
2597
2658
  pattern: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.pattern),
2598
2659
  context: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.patternContext),
2599
2660
  selector: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.selector),
@@ -2602,9 +2663,9 @@ function createReadSeekTools(imagePolicy) {
2602
2663
  path: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.projectSearchPath),
2603
2664
  language: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.language),
2604
2665
  gitScope: tool3.schema.enum(GIT_SCOPES).optional().describe(PARAM_DESCRIPTIONS.gitScope)
2605
- }, "find_nodes", async (input, context) => {
2666
+ }, "search", async (input, context) => {
2606
2667
  const target = resolvePath(context.directory, input.path ?? ".");
2607
- const args = buildFindNodesArgs({
2668
+ const args = buildSearchArgs({
2608
2669
  path: target,
2609
2670
  pattern: input.pattern,
2610
2671
  context: input.context,
@@ -2622,14 +2683,14 @@ function createReadSeekTools(imagePolicy) {
2622
2683
  throw new Error("rule stdin is unavailable in OpenCode tools; use inline KDL or @path");
2623
2684
  return runReadSeek(context, args);
2624
2685
  }),
2625
- readseek_find_definitions: readseekTool(openCodeToolDescription("find_definitions"), {
2686
+ readseek_def: readseekTool(openCodeToolDescription("def"), {
2626
2687
  name: tool3.schema.string().describe(PARAM_DESCRIPTIONS.name),
2627
2688
  path: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.projectSearchPath),
2628
2689
  language: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.language),
2629
2690
  gitScope: tool3.schema.enum(GIT_SCOPES).optional().describe(PARAM_DESCRIPTIONS.gitScope)
2630
- }, "find_definitions", async (input, context) => {
2691
+ }, "def", async (input, context) => {
2631
2692
  const target = resolvePath(context.directory, input.path ?? ".");
2632
- const args = buildFindDefinitionsArgs({
2693
+ const args = buildDefArgs({
2633
2694
  path: target,
2634
2695
  name: input.name,
2635
2696
  language: input.language,
@@ -2638,16 +2699,16 @@ function createReadSeekTools(imagePolicy) {
2638
2699
  await authorizeSearch(context, target, input.name);
2639
2700
  return runReadSeek(context, args);
2640
2701
  }),
2641
- readseek_find_references: readseekTool(openCodeToolDescription("find_references"), {
2702
+ readseek_refs: readseekTool(openCodeToolDescription("refs"), {
2642
2703
  name: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.refsName),
2643
2704
  path: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.projectSearchPath),
2644
2705
  language: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.language),
2645
2706
  at: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.at),
2646
2707
  gitScope: tool3.schema.enum(GIT_SCOPES).optional().describe(PARAM_DESCRIPTIONS.gitScope)
2647
- }, "find_references", async (input, context) => {
2708
+ }, "refs", async (input, context) => {
2648
2709
  const target = resolvePath(context.directory, input.path ?? ".");
2649
2710
  const name = input.name;
2650
- const args = buildFindReferencesArgs({
2711
+ const args = buildRefsArgs({
2651
2712
  path: target,
2652
2713
  name,
2653
2714
  at: input.at,
@@ -2657,7 +2718,7 @@ function createReadSeekTools(imagePolicy) {
2657
2718
  await authorizeSearch(context, target, name ?? "*");
2658
2719
  return runReadSeek(context, args);
2659
2720
  }),
2660
- readseek_rename_symbol: readseekTool(openCodeToolDescription("rename_symbol"), {
2721
+ readseek_rename: readseekTool(openCodeToolDescription("rename"), {
2661
2722
  path: tool3.schema.string().describe(PARAM_DESCRIPTIONS.projectPath),
2662
2723
  at: tool3.schema.string().describe(PARAM_DESCRIPTIONS.at),
2663
2724
  to: tool3.schema.string().min(1).describe(PARAM_DESCRIPTIONS.to),
@@ -2666,7 +2727,7 @@ function createReadSeekTools(imagePolicy) {
2666
2727
  planHash: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.planHash),
2667
2728
  language: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.language),
2668
2729
  gitScope: tool3.schema.enum(GIT_SCOPES).optional().describe(PARAM_DESCRIPTIONS.gitScope)
2669
- }, "rename_symbol", async (input, context) => {
2730
+ }, "rename", async (input, context) => {
2670
2731
  const filePath = resolvePath(context.directory, input.path);
2671
2732
  await authorizeRead(context, filePath);
2672
2733
  if (input.workspace) {
@@ -2676,7 +2737,7 @@ function createReadSeekTools(imagePolicy) {
2676
2737
  throw new Error("readseek could not identify a binding at the rename cursor");
2677
2738
  await authorizeSearch(context, context.directory, name);
2678
2739
  }
2679
- const args = buildRenameSymbolArgs({
2740
+ const args = buildRenameArgs({
2680
2741
  path: filePath,
2681
2742
  to: input.to,
2682
2743
  at: input.at,
@@ -2696,7 +2757,7 @@ function createReadSeekTools(imagePolicy) {
2696
2757
  throw new Error("readseek rename plan did not include a plan hash");
2697
2758
  }
2698
2759
  await authorizeEdit(context, files);
2699
- return runReadSeek(context, buildRenameSymbolArgs({
2760
+ return runReadSeek(context, buildRenameArgs({
2700
2761
  path: filePath,
2701
2762
  to: input.to,
2702
2763
  at: input.at,
@@ -2710,7 +2771,7 @@ function createReadSeekTools(imagePolicy) {
2710
2771
  timeoutMs: DEFAULT_READSEEK_TIMEOUT_MS
2711
2772
  });
2712
2773
  }),
2713
- readseek_edit_text: readseekTool(openCodeToolDescription("edit_text"), {
2774
+ readseek_edit: readseekTool(openCodeToolDescription("edit"), {
2714
2775
  path: tool3.schema.string().describe(PARAM_DESCRIPTIONS.projectPath),
2715
2776
  edits: tool3.schema.array(tool3.schema.union([
2716
2777
  tool3.schema.object({
@@ -2750,7 +2811,7 @@ function createReadSeekTools(imagePolicy) {
2750
2811
  apply: tool3.schema.boolean().optional().describe(PARAM_DESCRIPTIONS.applyDefaultTrue),
2751
2812
  planHash: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.planHash),
2752
2813
  gitScope: tool3.schema.enum(GIT_SCOPES).optional().describe(PARAM_DESCRIPTIONS.gitScope)
2753
- }, "edit_text", async (input, context) => {
2814
+ }, "edit", async (input, context) => {
2754
2815
  const filePath = resolvePath(context.directory, input.path);
2755
2816
  validateEdits(input.edits);
2756
2817
  return withFileMutationQueue(filePath, async () => {
@@ -2759,7 +2820,7 @@ function createReadSeekTools(imagePolicy) {
2759
2820
  await rejectSymlinkMutation(filePath);
2760
2821
  const edits = input.edits;
2761
2822
  const request = serializeEditPlan(edits);
2762
- const baseArgs = buildEditTextArgs({
2823
+ const baseArgs = buildEditArgs({
2763
2824
  path: filePath,
2764
2825
  language: input.language,
2765
2826
  gitScope: input.gitScope,
@@ -2783,7 +2844,7 @@ function createReadSeekTools(imagePolicy) {
2783
2844
  }
2784
2845
  await authorizeEdit(context, [filePath], simpleDiff(filePath, before, after), false);
2785
2846
  context.abort.throwIfAborted();
2786
- const applied = record2(await runReadSeek(context, buildEditTextArgs({
2847
+ const applied = record2(await runReadSeek(context, buildEditArgs({
2787
2848
  path: filePath,
2788
2849
  language: input.language,
2789
2850
  gitScope: input.gitScope,
@@ -2801,10 +2862,10 @@ function createReadSeekTools(imagePolicy) {
2801
2862
  return postMutationPreview(context, previewArgs, filePath, true);
2802
2863
  });
2803
2864
  }),
2804
- readseek_write_file: readseekTool(openCodeToolDescription("write_file"), {
2865
+ readseek_write: readseekTool(openCodeToolDescription("write"), {
2805
2866
  path: tool3.schema.string().describe(PARAM_DESCRIPTIONS.projectPath),
2806
2867
  content: tool3.schema.string().describe(PARAM_DESCRIPTIONS.content)
2807
- }, "write_file", async (input, context) => {
2868
+ }, "write", async (input, context) => {
2808
2869
  const filePath = resolvePath(context.directory, input.path);
2809
2870
  await authorizeExternal(context, filePath);
2810
2871
  return withFileMutationQueue(filePath, async () => {
@@ -2828,37 +2889,37 @@ function createAccessTools(imagePolicy) {
2828
2889
  const languageSchema = { language: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.language) };
2829
2890
  const levelSchema = { level: tool3.schema.enum(VISION_LEVEL_VALUES).optional().describe(PARAM_DESCRIPTIONS.level) };
2830
2891
  const definitions = {
2831
- show_content: { build: buildShowContentArgs, args: { ...pathSchema, ...atSchema, ...languageSchema, end: tool3.schema.number().int().positive().optional(), limit: tool3.schema.number().int().positive().optional(), noAnchors: tool3.schema.boolean().optional() } },
2832
- show_structure: { build: buildShowStructureArgs, args: { ...pathSchema, ...atSchema, ...languageSchema, depth: tool3.schema.number().int().nonnegative().optional(), kind: tool3.schema.string().optional(), outline: tool3.schema.boolean().optional() } },
2833
- show_metadata: { build: buildShowMetadataArgs, args: { ...pathSchema, ...languageSchema } },
2834
- show_assets: { build: buildShowAssetsArgs, args: { ...pathSchema, ...atSchema } },
2835
- check_syntax: { build: buildCheckSyntaxArgs, args: { ...pathSchema, ...languageSchema } },
2836
- check_rules: { build: buildCheckRulesArgs, args: { path: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.projectSearchPath), rules: tool3.schema.string().min(1), gitScope: tool3.schema.enum(GIT_SCOPES).optional() } },
2837
- generate_caption: { build: buildGenerateCaptionArgs, args: { ...pathSchema, ...atSchema, ...levelSchema, include: tool3.schema.array(tool3.schema.enum(["text", "objects"])).min(1).optional() } },
2838
- detect_objects: { build: buildDetectObjectsArgs, args: { ...pathSchema, ...atSchema, ...levelSchema } },
2839
- recognize_text: { build: buildRecognizeTextArgs, args: { ...pathSchema, ...atSchema, ...levelSchema } }
2892
+ show: { build: buildShowArgs, args: { ...pathSchema, ...atSchema, ...languageSchema, end: tool3.schema.number().int().positive().optional(), limit: tool3.schema.number().int().positive().optional(), noAnchors: tool3.schema.boolean().optional() } },
2893
+ tree: { build: buildTreeArgs, args: { ...pathSchema, ...atSchema, ...languageSchema, depth: tool3.schema.number().int().nonnegative().optional(), kind: tool3.schema.string().optional(), outline: tool3.schema.boolean().optional() } },
2894
+ meta: { build: buildMetaArgs, args: { ...pathSchema, ...languageSchema } },
2895
+ assets: { build: buildAssetsArgs, args: { ...pathSchema, ...atSchema } },
2896
+ syntax: { build: buildSyntaxArgs, args: { ...pathSchema, ...languageSchema } },
2897
+ check: { build: buildCheckArgs, args: { path: tool3.schema.string().optional().describe(PARAM_DESCRIPTIONS.projectSearchPath), rules: tool3.schema.string().min(1), gitScope: tool3.schema.enum(GIT_SCOPES).optional() } },
2898
+ caption: { build: buildCaptionArgs, args: { ...pathSchema, ...atSchema, ...levelSchema, include: tool3.schema.array(tool3.schema.enum(["text", "objects"])).min(1).optional() } },
2899
+ objects: { build: buildObjectsArgs, args: { ...pathSchema, ...atSchema, ...levelSchema } },
2900
+ ocr: { build: buildOcrArgs, args: { ...pathSchema, ...atSchema, ...levelSchema } }
2840
2901
  };
2841
2902
  return Object.fromEntries(Object.entries(definitions).map(([name, definition]) => [
2842
2903
  `readseek_${name}`,
2843
2904
  readseekTool(openCodeToolDescription(name), definition.args, name, async (input, context) => {
2844
2905
  const filePath = resolvePath(context.directory, input.path ?? ".");
2845
- const buildInput = { ...input, path: filePath, ...name === "show_structure" ? { depth: input.depth ?? DEFAULT_STRUCTURE_DEPTH } : {} };
2906
+ const buildInput = { ...input, path: filePath, ...name === "tree" ? { depth: input.depth ?? DEFAULT_STRUCTURE_DEPTH } : {} };
2846
2907
  let args = definition.build(buildInput);
2847
2908
  await authorizeRead(context, filePath);
2848
- if (name === "check_rules") {
2909
+ if (name === "check") {
2849
2910
  if (input.rules === "-")
2850
2911
  throw new Error("rules stdin is unavailable in OpenCode tools; use inline KDL or @path");
2851
2912
  await authorizeSearch(context, filePath, input.rules);
2852
2913
  if (input.rules.startsWith("@"))
2853
2914
  await authorizeRead(context, resolvePath(context.directory, input.rules.slice(1)));
2854
2915
  }
2855
- const inference = ["generate_caption", "detect_objects", "recognize_text"].includes(name);
2856
- if (name === "show_content" || name === "show_assets" || inference) {
2916
+ const inference = ["caption", "objects", "ocr"].includes(name);
2917
+ if (name === "show" || name === "assets" || inference) {
2857
2918
  const readseekDir = await ensureReadSeekCache(context);
2858
2919
  args = definition.build({ ...buildInput, readseekDir });
2859
2920
  }
2860
2921
  return runReadSeek(context, args, { timeoutMs: inference ? DEFAULT_VISION_TIMEOUT_MS : DEFAULT_READSEEK_TIMEOUT_MS });
2861
- }, name === "show_content" || name === "show_assets" ? imagePolicy : undefined)
2922
+ }, name === "show" || name === "assets" ? imagePolicy : undefined)
2862
2923
  ]));
2863
2924
  }
2864
2925
 
@@ -2873,28 +2934,28 @@ var SKILL = {
2873
2934
 
2874
2935
  When ReadSeek tools are unavailable, use the readseek CLI for structural navigation and anchored edits if it is installed and available on PATH. Run \`readseek --help\` to inspect supported commands before invoking them. Get fresh anchors before editing; re-read after external file changes.
2875
2936
 
2876
- Commands use verb-object pairs, with the target path positional:
2937
+ Commands use flat single-word verbs, with target and primary query arguments positional:
2877
2938
 
2878
2939
  \`\`\`sh
2879
- readseek show content file.ts --at line:10 --limit 40 --kdl
2880
- readseek show structure file.ts --depth 1 --kdl
2881
- readseek show metadata paper.pdf --kdl
2882
- readseek show assets paper.pdf --at page:2 --kdl
2883
- readseek check syntax file.ts --kdl
2884
- readseek check rules . --rules @checks.kdl --kdl
2885
- readseek find nodes src --pattern 'console.log($$$ARGS)' --kdl
2886
- readseek find text src --text 'TODO' --kdl
2887
- readseek find definitions src --name main --kdl
2888
- readseek find references file.ts --at line:10:3 --kdl
2889
- readseek edit text file.ts --edits @edits.kdl --kdl
2890
- readseek rename symbol file.ts --at line:10:3 --to nextName --kdl
2940
+ readseek show file.ts --at line:10 --limit 40 --kdl
2941
+ readseek tree file.ts --depth 1 --kdl
2942
+ readseek meta paper.pdf --kdl
2943
+ readseek assets paper.pdf --at page:2 --kdl
2944
+ readseek syntax file.ts --kdl
2945
+ readseek check . @checks.kdl --kdl
2946
+ readseek search 'console.log($$$ARGS)' src --kdl
2947
+ readseek grep 'TODO' src --kdl
2948
+ readseek def main src --kdl
2949
+ readseek refs file.ts --at line:10:3 --kdl
2950
+ readseek edit file.ts @edits.kdl --kdl
2951
+ readseek rename file.ts --at line:10:3 nextName --kdl
2891
2952
  \`\`\`
2892
2953
 
2893
- Native \`find text\` is literal, not regex. Reference selection requires exactly one of \`--name\` or \`--at\`; rename requires a line or hash cursor. Preview mutations first, then use \`--apply --plan-hash HASH\` with the returned plan hash. Edit requests are KDL: for example, \`set_line anchor="10:HASH" new_text="replacement"\`.
2954
+ Native \`grep\` is literal, not regex. Reference selection requires either a symbol \`name\` or \`--at\`; rename requires a line or hash cursor. Preview mutations first, then use \`--apply --plan-hash HASH\` with the returned plan hash. Edit requests are KDL: for example, \`set_line anchor="10:HASH" new_text="replacement"\`.
2894
2955
 
2895
2956
  Syntax and rule checks return exit 0 when clean, 1 for findings, and 2 on failure. Exit 1 is not a transport failure. Syntax checks are parser checks, not type checking.
2896
2957
 
2897
- Content and assets return cached paths; assets auto-materialize. Read those paths directly. There is no extract command or asset destination option. Reading does not invoke inference. Request inference explicitly with \`generate caption\` (optionally \`--include text,objects\`), \`detect objects\`, or \`recognize text\`, using \`--level low|medium|high\` and an installed model; models are never downloaded automatically.
2958
+ Content and assets return cached paths; assets auto-materialize. Read those paths directly. There is no extract command or asset destination option. Reading does not invoke inference. Request inference explicitly with \`caption\` (optionally \`--include text,objects\`), \`objects\`, or \`ocr\`, using \`--level low|medium|high\` and an installed model; models are never downloaded automatically.
2898
2959
 
2899
2960
  This V2 plugin supplies guidance only; it does not register readseek_* tools. If the CLI is unavailable, use OpenCode's built-in tools instead.`
2900
2961
  };
@@ -2951,7 +3012,7 @@ var ReadSeekPlugin = async (_input, options) => {
2951
3012
  return;
2952
3013
  try {
2953
3014
  const result = output.metadata.readseek ?? JSON.parse(output.output);
2954
- if (input.tool === "readseek_rename_symbol") {
3015
+ if (input.tool === "readseek_rename") {
2955
3016
  anchors.planRename(input.sessionID, result);
2956
3017
  if (record2(result).applied === true) {
2957
3018
  for (const filePath of renameFiles(result))
package/dist/v2.js CHANGED
@@ -9,28 +9,28 @@ var SKILL = {
9
9
 
10
10
  When ReadSeek tools are unavailable, use the readseek CLI for structural navigation and anchored edits if it is installed and available on PATH. Run \`readseek --help\` to inspect supported commands before invoking them. Get fresh anchors before editing; re-read after external file changes.
11
11
 
12
- Commands use verb-object pairs, with the target path positional:
12
+ Commands use flat single-word verbs, with target and primary query arguments positional:
13
13
 
14
14
  \`\`\`sh
15
- readseek show content file.ts --at line:10 --limit 40 --kdl
16
- readseek show structure file.ts --depth 1 --kdl
17
- readseek show metadata paper.pdf --kdl
18
- readseek show assets paper.pdf --at page:2 --kdl
19
- readseek check syntax file.ts --kdl
20
- readseek check rules . --rules @checks.kdl --kdl
21
- readseek find nodes src --pattern 'console.log($$$ARGS)' --kdl
22
- readseek find text src --text 'TODO' --kdl
23
- readseek find definitions src --name main --kdl
24
- readseek find references file.ts --at line:10:3 --kdl
25
- readseek edit text file.ts --edits @edits.kdl --kdl
26
- readseek rename symbol file.ts --at line:10:3 --to nextName --kdl
15
+ readseek show file.ts --at line:10 --limit 40 --kdl
16
+ readseek tree file.ts --depth 1 --kdl
17
+ readseek meta paper.pdf --kdl
18
+ readseek assets paper.pdf --at page:2 --kdl
19
+ readseek syntax file.ts --kdl
20
+ readseek check . @checks.kdl --kdl
21
+ readseek search 'console.log($$$ARGS)' src --kdl
22
+ readseek grep 'TODO' src --kdl
23
+ readseek def main src --kdl
24
+ readseek refs file.ts --at line:10:3 --kdl
25
+ readseek edit file.ts @edits.kdl --kdl
26
+ readseek rename file.ts --at line:10:3 nextName --kdl
27
27
  \`\`\`
28
28
 
29
- Native \`find text\` is literal, not regex. Reference selection requires exactly one of \`--name\` or \`--at\`; rename requires a line or hash cursor. Preview mutations first, then use \`--apply --plan-hash HASH\` with the returned plan hash. Edit requests are KDL: for example, \`set_line anchor="10:HASH" new_text="replacement"\`.
29
+ Native \`grep\` is literal, not regex. Reference selection requires either a symbol \`name\` or \`--at\`; rename requires a line or hash cursor. Preview mutations first, then use \`--apply --plan-hash HASH\` with the returned plan hash. Edit requests are KDL: for example, \`set_line anchor="10:HASH" new_text="replacement"\`.
30
30
 
31
31
  Syntax and rule checks return exit 0 when clean, 1 for findings, and 2 on failure. Exit 1 is not a transport failure. Syntax checks are parser checks, not type checking.
32
32
 
33
- Content and assets return cached paths; assets auto-materialize. Read those paths directly. There is no extract command or asset destination option. Reading does not invoke inference. Request inference explicitly with \`generate caption\` (optionally \`--include text,objects\`), \`detect objects\`, or \`recognize text\`, using \`--level low|medium|high\` and an installed model; models are never downloaded automatically.
33
+ Content and assets return cached paths; assets auto-materialize. Read those paths directly. There is no extract command or asset destination option. Reading does not invoke inference. Request inference explicitly with \`caption\` (optionally \`--include text,objects\`), \`objects\`, or \`ocr\`, using \`--level low|medium|high\` and an installed model; models are never downloaded automatically.
34
34
 
35
35
  This V2 plugin supplies guidance only; it does not register readseek_* tools. If the CLI is unavailable, use OpenCode's built-in tools instead.`
36
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-readseek",
3
- "version": "0.11.3",
3
+ "version": "0.12.0",
4
4
  "description": "OpenCode plugin for anchored file operations and structural code navigation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,8 +33,8 @@
33
33
  "node": ">=20.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@jarkkojs/readseek": "^0.11.3",
37
- "@jarkkojs/readseek-api": "^0.11.3",
36
+ "@jarkkojs/readseek": "^0.12.0",
37
+ "@jarkkojs/readseek-api": "^0.12.0",
38
38
  "@opencode-ai/plugin": "^1.18.18"
39
39
  },
40
40
  "devDependencies": {