pi-readseek 0.8.18 → 0.8.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,37 +1,43 @@
1
1
  # pi-readseek
2
2
 
3
- `pi-readseek` adds ReadSeek's anchored file tools, structural search, and symbol
4
- navigation to Pi. Built-in tools remain unchanged unless `replacedTools` maps
5
- `read`, `edit`, `write`, or `grep` to the ReadSeek implementation.
3
+ `pi-readseek` adds ReadSeek's anchored file operations, structural search,
4
+ symbol navigation, and PDF tools to Pi. Built-ins remain available unless
5
+ `replacedTools` maps `read`, `edit`, `write`, or `grep` to a ReadSeek-backed
6
+ implementation.
6
7
 
7
- ## Installation
8
+ ## Install
8
9
 
9
10
  ```sh
10
11
  pi install npm:pi-readseek
11
12
  ```
12
13
 
13
- The extension depends on `@jarkkojs/readseek`, which installs the native binary on
14
+ The package depends on `@jarkkojs/readseek`, which supplies the native binary on
14
15
  supported platforms.
15
16
 
16
17
  ## Tools
17
18
 
18
- - `readSeek_read`: reads anchored text by range, symbol, or structural map; it can
19
- also read or analyze images and PDFs.
20
- - `readSeek_edit`: applies hash-verified edits to existing text files.
21
- - `readSeek_write`: creates or replaces complete files and returns anchors.
22
- - `readSeek_grep`: searches text and returns edit-ready anchors.
23
- - `readSeek_search`: searches code with structural AST patterns.
24
- - `readSeek_def`, `readSeek_refs`, `readSeek_hover`: navigate symbols.
25
- - `readSeek_rename`: applies binding-aware renames by default. Set `apply: false`
26
- for a dry run; workspace matches are name-based where binding support is unavailable.
27
- - `readSeek_check`: reports parser errors and missing syntax.
28
- - `readSeek_view`: indexes a PDF or narrows an existing index by page, node, kind,
29
- or depth.
19
+ | Tool | Purpose |
20
+ | --- | --- |
21
+ | `readSeek_read` | Read anchored text by range, symbol, or map; read images and PDFs |
22
+ | `readSeek_edit` | Apply hash-verified edits to an existing text file |
23
+ | `readSeek_write` | Create or replace a complete text file and return anchors |
24
+ | `readSeek_grep` | Search text or regex and return edit-ready anchors |
25
+ | `readSeek_search` | Search AST patterns |
26
+ | `readSeek_def` | Find symbol definitions |
27
+ | `readSeek_refs` | Find identifier usages, optionally scoped to a cursor binding |
28
+ | `readSeek_hover` | Identify the token and enclosing symbol at a cursor |
29
+ | `readSeek_rename` | Rename a cursor symbol; set `apply: false` to preview the plan |
30
+ | `readSeek_check` | Report parser errors and missing syntax |
31
+ | `readSeek_view` | View or narrow a structural PDF index |
32
+
33
+ The extension also tells Pi to get fresh anchors before editing and to run a
34
+ syntax check after source edits.
30
35
 
31
36
  ## Settings
32
37
 
33
- Add an optional `readseek` section to `~/.pi/agent/settings.json` (global) or
34
- `.pi/settings.json` (project). Project settings take precedence. Defaults:
38
+ Add a `readseek` object to `~/.pi/agent/settings.json` (global) or
39
+ `.pi/settings.json` (project). Project settings override matching global values.
40
+ Defaults:
35
41
 
36
42
  ```json
37
43
  {
@@ -54,24 +60,32 @@ Add an optional `readseek` section to `~/.pi/agent/settings.json` (global) or
54
60
  }
55
61
  ```
56
62
 
57
- - `replacedTools`: built-in tools backed by ReadSeek. Valid values are `"read"`,
58
- `"edit"`, `"write"`, and `"grep"`.
59
- - `imageMode`: controls standalone images and images embedded in PDFs. `"auto"`
60
- exposes `none`, `all`, `ocr`, `caption`, and `objects`. When the active model
61
- accepts images, `"auto"` silently passes prepared images to the model instead
62
- of running local analysis. `"on"` always runs the selected local analysis and
63
- omits `none`; `"off"` skips standalone and embedded images. PDF text is always
64
- read regardless of `imageMode`. Omitting `image` skips standalone images and,
65
- unless native vision is available in `"auto"` mode, PDF embedded images.
66
- - `syntaxValidation`: syntax-regression handling for `readSeek_edit`. `"warn"`
67
- writes with a warning, `"block"` aborts, and `"off"` disables the check.
68
- - `timeoutMs`: ReadSeek command timeout in milliseconds.
69
- - `grep.maxLines` and `grep.maxBytes`: output limits for `readSeek_grep`. Values
70
- above the defaults are clamped.
71
- - `display`: default display state (`"compact"` or `"expanded"`) per tool for `read`, `grep`, `edit`, and `write`.
63
+ - `replacedTools`: any of `"read"`, `"edit"`, `"write"`, and `"grep"`.
64
+ - `imageMode`: `"auto"` uses Pi's native image input when available, `"on"`
65
+ always runs local analysis, and `"off"` skips images while still reading PDF
66
+ text. Standalone images require `image`; values are `all`, `ocr`, `caption`, and
67
+ `objects`. In `"auto"`, `none` returns a prepared standalone image without local
68
+ analysis. Local analysis uses
69
+ [Qwen3-VL-2B-Instruct](../../docs/models/qwen3-vl-2b-instruct.md).
70
+ - `syntaxValidation`: `"warn"` (write and warn), `"block"` (abort), or `"off"`.
71
+ Validation triggers only when an edit increases parser error or missing-node
72
+ counts.
73
+ - `timeoutMs`: native command timeout in milliseconds.
74
+ - `grep.maxLines` and `grep.maxBytes`: output limits; larger values are clamped
75
+ to the defaults.
76
+ - `display`: initial `"compact"` or `"expanded"` state for `read`, `grep`,
77
+ `edit`, and `write` results.
78
+
79
+ ## Development
80
+
81
+ ```sh
82
+ npm install
83
+ npm test
84
+ npm run typecheck
85
+ ```
72
86
 
73
- ## Licensing
87
+ ## License
74
88
 
75
- `pi-readseek` is licensed under `Apache-2.0`; see [LICENSE](LICENSE).
89
+ `pi-readseek` is Apache-2.0; see [LICENSE](LICENSE).
76
90
  `@jarkkojs/readseek` is licensed separately under
77
- `Apache-2.0 AND LGPL-2.1-or-later`.
91
+ Apache-2.0 AND LGPL-2.1-or-later.
package/dist/index.ts CHANGED
@@ -15,7 +15,7 @@ var REPLACEABLE_TOOL_GUIDELINES = {
15
15
  "read.md": {
16
16
  readSeekName: "readSeek_read",
17
17
  builtInName: "read",
18
- benefit: "it provides LINE:HASH anchors for safe edits."
18
+ benefit: "it returns LINE:HASH anchors for safe edits."
19
19
  },
20
20
  "edit.md": {
21
21
  readSeekName: "readSeek_edit",
@@ -25,7 +25,7 @@ var REPLACEABLE_TOOL_GUIDELINES = {
25
25
  "grep.md": {
26
26
  readSeekName: "readSeek_grep",
27
27
  builtInName: "grep",
28
- benefit: "it returns edit-ready anchors."
28
+ benefit: "it returns LINE:HASH anchors."
29
29
  },
30
30
  "write.md": {
31
31
  readSeekName: "readSeek_write",
@@ -35,23 +35,22 @@ var REPLACEABLE_TOOL_GUIDELINES = {
35
35
  };
36
36
  var COMPACT_GUIDELINES = {
37
37
  "read.md": [
38
- "Use readSeek_read map or symbol mode to inspect large code files without reading them in full."
38
+ "Use readSeek_read with map or symbol to inspect large files without reading them in full."
39
39
  ],
40
40
  "edit.md": [
41
- "With readSeek_edit, prefer set_line, replace_lines, and insert_after; use replace only when anchors are impractical."
41
+ "Prefer set_line, replace_lines, and insert_after; use replace only when anchors are impractical."
42
42
  ],
43
43
  "grep.md": [
44
- "Use readSeek_grep summary mode for broad count/file discovery before narrowing."
44
+ "Use readSeek_grep with summary first for broad searches, then narrow by path, glob, or pattern."
45
45
  ],
46
46
  "write.md": [
47
- "Use anchored edits rather than readSeek_write for small changes or appends to existing files."
47
+ "Use anchored edits rather than readSeek_write for small changes or appends."
48
48
  ],
49
49
  "search.md": [
50
- "Use readSeek_search for syntax-aware code shapes; use readSeek_grep for plain text."
50
+ "Use readSeek_search for AST patterns; use readSeek_grep for plain text."
51
51
  ],
52
52
  "refs.md": [
53
- "Use readSeek_refs to find every usage of an identifier before renaming or deleting it.",
54
- "Use readSeek_refs with scope plus line/column to follow a specific binding instead of every same-named identifier."
53
+ "Use readSeek_refs before changing a symbol; add scope plus line/column to follow one binding."
55
54
  ]
56
55
  };
57
56
  function loadPrompt(promptUrl) {
@@ -3661,21 +3660,21 @@ function registerReadTool(pi, options = {}) {
3661
3660
  const imageModes = imageMode === "auto" ? ["none", "all", "ocr", "caption", "objects"] : ["all", "ocr", "caption", "objects"];
3662
3661
  const promptMetadata = defineToolPromptMetadata({
3663
3662
  promptUrl: new URL("../prompts/read.md", import.meta.url),
3664
- promptSnippet: "Read anchored text, symbols, maps, images, or PDFs",
3663
+ promptSnippet: imageMode === "off" ? "Read anchored text, symbols, maps, or PDF text" : "Read anchored text, symbols, maps, images, or PDFs",
3665
3664
  registeredName: name
3666
3665
  });
3667
3666
  const tool = registerReadSeekTool(pi, {
3668
3667
  name,
3669
3668
  label: "Read",
3670
- description: imageMode === "off" ? 'Read anchored text by range, map, or symbol; standalone images are skipped because imageMode is "off", while PDFs are read as text.' : promptMetadata.description,
3669
+ description: imageMode === "off" ? "Read anchored text by range, symbol, or map. Images are disabled; PDFs still return text." : promptMetadata.description,
3671
3670
  promptSnippet: promptMetadata.promptSnippet,
3672
3671
  promptGuidelines: [
3673
3672
  ...promptMetadata.promptGuidelines,
3674
- imageMode === "off" ? "The image parameter is unavailable; standalone images and PDF embedded images are skipped, while PDFs are read as text." : `For an image, explicitly choose image: ${imageModes.join(", ")}; omitting image skips standalone images. PDFs are always read as text, and image controls embedded images.${imageMode === "auto" ? " Native image-capable models bypass local analysis and receive standalone and PDF embedded images directly." : ""}`
3673
+ ...imageMode === "auto" ? ["Image-capable Pi models receive prepared images directly. For standalone images, image=none skips local analysis; other modes use ReadSeek when native vision is unavailable."] : []
3675
3674
  ],
3676
3675
  parameters: Type2.Object({
3677
3676
  path: filePathParam(),
3678
- offset: optionalIntOrString("Start line (1-indexed)"),
3677
+ offset: optionalIntOrString("One-based starting line"),
3679
3678
  limit: optionalIntOrString("Maximum lines to return"),
3680
3679
  page: optionalIntOrString("One-based PDF page; defaults to 1"),
3681
3680
  symbol: Type2.Optional(Type2.String({ description: "Symbol name to read" })),
@@ -3685,7 +3684,7 @@ function registerReadTool(pi, options = {}) {
3685
3684
  })),
3686
3685
  ...imageMode === "off" ? {} : {
3687
3686
  image: Type2.Optional(Type2.Union(imageModes.map((mode) => Type2.Literal(mode)), {
3688
- description: `Standalone image/PDF embedded-image mode: ${imageModes.join(", ")}. Must be selected explicitly for standalone images.`
3687
+ description: `Standalone/PDF-embedded image mode: ${imageModes.join(", ")}. Required for standalone images.${imageMode === "auto" ? " For standalone images, none skips local analysis." : ""}`
3689
3688
  }))
3690
3689
  }
3691
3690
  }),
@@ -4793,20 +4792,43 @@ function pendingPreviewLines(summary, preview, expanded) {
4793
4792
  const headerLine = summaryLine(preview.data.headerLabel, { hidden: !expanded });
4794
4793
  return { lines: [summary, headerLine], diffData: expanded ? diffData : undefined, headerLabel: preview.data.headerLabel };
4795
4794
  }
4796
- var hashlineEditItemSchema = Type3.Union([
4797
- Type3.Object({ set_line: Type3.Object({ anchor: Type3.String(), new_text: Type3.String() }) }, { additionalProperties: false }),
4798
- Type3.Object({ replace_lines: Type3.Object({ start_anchor: Type3.String(), end_anchor: Type3.String(), new_text: Type3.String() }) }, { additionalProperties: false }),
4799
- Type3.Object({ insert_after: Type3.Object({ anchor: Type3.String(), new_text: Type3.String() }) }, { additionalProperties: false }),
4800
- Type3.Object({ replace: Type3.Object({ old_text: Type3.String(), new_text: Type3.String(), all: Type3.Optional(Type3.Boolean()), fuzzy: Type3.Optional(Type3.Boolean()) }) }, { additionalProperties: false }),
4801
- Type3.Object({ replace_symbol: Type3.Object({ symbol: Type3.String(), new_body: Type3.String() }) }, { additionalProperties: false })
4802
- ]);
4795
+ var hashlineEditItemSchema = Type3.Object({
4796
+ set_line: Type3.Optional(Type3.Object({
4797
+ anchor: Type3.String({ description: "Fresh LINE:HASH anchor for the line to replace" }),
4798
+ new_text: Type3.String({ description: "Replacement text; use an empty string to delete the line" })
4799
+ }, { description: 'Replace one line: {"set_line":{"anchor":"LINE:HASH","new_text":"..."}}' })),
4800
+ replace_lines: Type3.Optional(Type3.Object({
4801
+ start_anchor: Type3.String({ description: "Fresh LINE:HASH anchor for the first line in the range" }),
4802
+ end_anchor: Type3.String({ description: "Fresh LINE:HASH anchor for the last line in the range" }),
4803
+ new_text: Type3.String({ description: "Replacement text; use an empty string to delete the range" })
4804
+ }, { description: 'Replace a range: {"replace_lines":{"start_anchor":"LINE:HASH","end_anchor":"LINE:HASH","new_text":"..."}}' })),
4805
+ insert_after: Type3.Optional(Type3.Object({
4806
+ anchor: Type3.String({ description: "Fresh LINE:HASH anchor for the line after which to insert" }),
4807
+ new_text: Type3.String({ description: "Text to insert after the anchored line" })
4808
+ }, { description: 'Insert text: {"insert_after":{"anchor":"LINE:HASH","new_text":"..."}}' })),
4809
+ replace: Type3.Optional(Type3.Object({
4810
+ old_text: Type3.String({ description: "Exact text to find" }),
4811
+ new_text: Type3.String({ description: "Replacement text" }),
4812
+ all: Type3.Optional(Type3.Boolean({ description: "Replace every exact match" })),
4813
+ fuzzy: Type3.Optional(Type3.Boolean({ description: "Allow unverified fuzzy matching when exact text is absent" }))
4814
+ }, { description: 'Replace text: {"replace":{"old_text":"...","new_text":"..."}}' })),
4815
+ replace_symbol: Type3.Optional(Type3.Object({
4816
+ symbol: Type3.String({ description: "Mapped symbol name" }),
4817
+ new_body: Type3.String({ description: "Complete replacement body for the symbol" })
4818
+ }, { description: 'Replace a symbol: {"replace_symbol":{"symbol":"name","new_body":"..."}}' }))
4819
+ }, {
4820
+ additionalProperties: false,
4821
+ minProperties: 1,
4822
+ maxProperties: 1,
4823
+ description: "Exactly one nested edit variant"
4824
+ });
4803
4825
  var hashlineEditSchema = Type3.Object({
4804
4826
  path: filePathParam(),
4805
4827
  edits: Type3.Optional(Type3.Array(hashlineEditItemSchema, {
4806
- description: "Edits: set_line, replace_lines, insert_after, replace_symbol, or replace"
4828
+ description: "Use set_line, replace_lines, insert_after, replace_symbol, or replace"
4807
4829
  })),
4808
4830
  postEditVerify: Type3.Optional(Type3.Boolean({
4809
- description: "Verify persisted content after write"
4831
+ description: "Read back and verify persisted content"
4810
4832
  }))
4811
4833
  }, { additionalProperties: true });
4812
4834
  function buildEditError(path2, code, message, hint, errorDetails) {
@@ -4860,7 +4882,12 @@ async function executeEdit(opts) {
4860
4882
  }
4861
4883
  for (let i = 0;i < edits.length; i++) {
4862
4884
  throwIfAborted(signal);
4863
- const e = edits[i];
4885
+ const edit = edits[i];
4886
+ if (!edit || typeof edit !== "object" || Array.isArray(edit)) {
4887
+ const message = `edits[${i}] must be an object containing exactly one edit variant.`;
4888
+ return buildEditError(absolutePath, "invalid-edit-variant", message);
4889
+ }
4890
+ const e = edit;
4864
4891
  if ((("old_text" in e) || ("new_text" in e)) && !("replace" in e)) {
4865
4892
  const message = `edits[${i}] has top-level 'old_text'/'new_text'. Use {replace: {old_text, new_text}} or {set_line}, {replace_lines}, {insert_after}.`;
4866
4893
  return buildEditError(absolutePath, "invalid-edit-variant", message);
@@ -4870,7 +4897,7 @@ async function executeEdit(opts) {
4870
4897
  return buildEditError(absolutePath, "invalid-edit-variant", message);
4871
4898
  }
4872
4899
  const variantCount = Number("set_line" in e) + Number("replace_lines" in e) + Number("insert_after" in e) + Number("replace" in e) + Number("replace_symbol" in e);
4873
- if (variantCount !== 1) {
4900
+ if (variantCount !== 1 || Object.keys(e).length !== 1) {
4874
4901
  const message = `edits[${i}] must contain exactly one of: 'set_line', 'replace_lines', 'insert_after', 'replace', 'replace_symbol'. Got: [${Object.keys(e).join(", ")}].`;
4875
4902
  return buildEditError(absolutePath, "invalid-edit-variant", message);
4876
4903
  }
@@ -5202,7 +5229,7 @@ function registerEditTool(pi, options = {}) {
5202
5229
  const name = options.name ?? "readSeek_edit";
5203
5230
  const promptMetadata = defineToolPromptMetadata({
5204
5231
  promptUrl: new URL("../prompts/edit.md", import.meta.url),
5205
- promptSnippet: "Safely edit with fresh LINE:HASH anchors",
5232
+ promptSnippet: "Edit existing files with fresh LINE:HASH anchors",
5206
5233
  registeredName: name,
5207
5234
  toolAliases: options.toolAliases
5208
5235
  });
@@ -5669,7 +5696,7 @@ function validateIgnoredRequiresOthers(tool, params) {
5669
5696
 
5670
5697
  // src/grep.ts
5671
5698
  var grepSchema = Type5.Object({
5672
- pattern: Type5.String({ description: "Regex pattern; use literal for exact text" }),
5699
+ pattern: Type5.String({ description: "Regex pattern; set literal for exact text" }),
5673
5700
  path: searchPathParam(),
5674
5701
  glob: Type5.Optional(Type5.String({ description: "File-name glob, such as *.ts" })),
5675
5702
  ignoreCase: Type5.Optional(Type5.Boolean({ description: "Ignore case" })),
@@ -6040,7 +6067,7 @@ function registerGrepTool(pi, options = {}) {
6040
6067
  const name = options.name ?? "readSeek_grep";
6041
6068
  const promptMetadata = defineToolPromptMetadata({
6042
6069
  promptUrl: new URL("../prompts/grep.md", import.meta.url),
6043
- promptSnippet: "Search plain text or regex with edit-ready anchors",
6070
+ promptSnippet: "Search text or regex with edit-ready LINE:HASH anchors",
6044
6071
  registeredName: name
6045
6072
  });
6046
6073
  const tool = registerReadSeekTool(pi, {
@@ -6186,7 +6213,7 @@ function mergeRanges(ranges) {
6186
6213
  }
6187
6214
  var SEARCH_PROMPT_METADATA = defineToolPromptMetadata({
6188
6215
  promptUrl: new URL("../prompts/search.md", import.meta.url),
6189
- promptSnippet: "Search syntax-aware code shapes with AST patterns"
6216
+ promptSnippet: "Search source code with AST patterns"
6190
6217
  });
6191
6218
  function linesFromSearchResult(result, ranges) {
6192
6219
  const lineMap = new Map;
@@ -6295,7 +6322,7 @@ function registerSearchTool(pi, options = {}) {
6295
6322
  promptSnippet: SEARCH_PROMPT_METADATA.promptSnippet,
6296
6323
  promptGuidelines: SEARCH_PROMPT_METADATA.promptGuidelines,
6297
6324
  parameters: Type6.Object({
6298
- pattern: Type6.String({ description: "ast-grep pattern, such as console.log($$$ARGS)" }),
6325
+ pattern: Type6.String({ description: "AST pattern (ast-grep style), such as console.log($$$ARGS)" }),
6299
6326
  lang: langParam(),
6300
6327
  path: searchPathParam(),
6301
6328
  ...readSeekGitSearchParams()
@@ -6349,7 +6376,7 @@ function buildRefsOutput(input) {
6349
6376
  // src/refs.ts
6350
6377
  var REFS_PROMPT_METADATA = defineToolPromptMetadata({
6351
6378
  promptUrl: new URL("../prompts/refs.md", import.meta.url),
6352
- promptSnippet: "Find usages of an identifier or cursor binding"
6379
+ promptSnippet: "Find identifier usages or a cursor binding"
6353
6380
  });
6354
6381
  function refsLine(reference) {
6355
6382
  return {
@@ -6431,8 +6458,8 @@ function registerRefsTool(pi, options = {}) {
6431
6458
  path: searchPathParam(),
6432
6459
  lang: langParam(),
6433
6460
  scope: Type7.Optional(Type7.Boolean({ description: "Restrict results to the binding at the cursor" })),
6434
- line: Type7.Optional(Type7.Number({ description: "Cursor line (1-indexed), required with scope" })),
6435
- column: Type7.Optional(Type7.Number({ description: "Cursor byte column (1-indexed) for disambiguation" })),
6461
+ line: Type7.Optional(Type7.Number({ description: "One-based cursor line; required with scope" })),
6462
+ column: Type7.Optional(Type7.Number({ description: "One-based cursor byte column for disambiguation" })),
6436
6463
  ...readSeekGitSearchParams()
6437
6464
  }),
6438
6465
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
@@ -6463,15 +6490,15 @@ import path5 from "node:path";
6463
6490
  import { Text as Text6 } from "@earendil-works/pi-tui";
6464
6491
  var RENAME_PROMPT_METADATA = defineToolPromptMetadata({
6465
6492
  promptUrl: new URL("../prompts/rename.md", import.meta.url),
6466
- promptSnippet: "Rename the symbol at a cursor without touching shadows"
6493
+ promptSnippet: "Rename a cursor symbol with verified edits"
6467
6494
  });
6468
6495
  var renameSchema = Type8.Object({
6469
6496
  path: filePathParam(),
6470
- line: Type8.Integer({ minimum: 1, description: "One-based line of the symbol to rename" }),
6471
- column: Type8.Optional(Type8.Integer({ minimum: 1, description: "One-based byte column for disambiguation" })),
6497
+ line: Type8.Integer({ minimum: 1, description: "One-based cursor line of the symbol to rename" }),
6498
+ column: Type8.Optional(Type8.Integer({ minimum: 1, description: "One-based cursor byte column for disambiguation" })),
6472
6499
  to: Type8.String({ description: "New symbol name" }),
6473
6500
  workspace: Type8.Optional(Type8.Boolean({ description: "Rename across the project" })),
6474
- apply: Type8.Optional(Type8.Boolean({ description: "Apply the verified edits; default true" }))
6501
+ apply: Type8.Optional(Type8.Boolean({ description: "Apply the verified edits; defaults to true" }))
6475
6502
  });
6476
6503
  async function executeRename(opts) {
6477
6504
  const { params, signal, cwd, onFileMutated } = opts;
@@ -6886,7 +6913,7 @@ function registerWriteTool(pi, options = {}) {
6886
6913
  const name = options.name ?? "readSeek_write";
6887
6914
  const promptMetadata = defineToolPromptMetadata({
6888
6915
  promptUrl: new URL("../prompts/write.md", import.meta.url),
6889
- promptSnippet: "Create or replace a complete file with edit anchors",
6916
+ promptSnippet: "Create or replace a complete file with LINE:HASH anchors",
6890
6917
  registeredName: name
6891
6918
  });
6892
6919
  const tool = registerReadSeekTool(pi, {
@@ -6897,7 +6924,7 @@ function registerWriteTool(pi, options = {}) {
6897
6924
  promptGuidelines: promptMetadata.promptGuidelines,
6898
6925
  parameters: Type10.Object({
6899
6926
  path: filePathParam(),
6900
- content: Type10.String({ description: "Complete file content" }),
6927
+ content: Type10.String({ description: "Complete text file content" }),
6901
6928
  map: mapParam()
6902
6929
  }),
6903
6930
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
@@ -7002,7 +7029,7 @@ import { Type as Type11 } from "@sinclair/typebox";
7002
7029
  import path6 from "node:path";
7003
7030
  var DEF_PROMPT_METADATA = defineToolPromptMetadata({
7004
7031
  promptUrl: new URL("../prompts/def.md", import.meta.url),
7005
- promptSnippet: "Find where a symbol is defined"
7032
+ promptSnippet: "Find symbol declarations by name"
7006
7033
  });
7007
7034
  async function executeDef(opts) {
7008
7035
  const { params, signal, cwd, onFileAnchored } = opts;
@@ -7107,7 +7134,7 @@ import { Text as Text9 } from "@earendil-works/pi-tui";
7107
7134
  import { Type as Type12 } from "@sinclair/typebox";
7108
7135
  var CHECK_PROMPT_METADATA = defineToolPromptMetadata({
7109
7136
  promptUrl: new URL("../prompts/check.md", import.meta.url),
7110
- promptSnippet: "Check a source file for parser errors and missing syntax"
7137
+ promptSnippet: "Run a quick syntax check on a source file"
7111
7138
  });
7112
7139
  async function executeCheck(opts) {
7113
7140
  const { params, signal, cwd } = opts;
@@ -7200,7 +7227,7 @@ var NODE_KINDS = [
7200
7227
  ];
7201
7228
  var VIEW_PROMPT_METADATA = defineToolPromptMetadata({
7202
7229
  promptUrl: new URL("../prompts/view.md", import.meta.url),
7203
- promptSnippet: "View the structure or selected content of an indexed PDF"
7230
+ promptSnippet: "View PDF structure or selected content"
7204
7231
  });
7205
7232
  async function executeView(opts) {
7206
7233
  const { params, signal, cwd } = opts;
@@ -7262,11 +7289,11 @@ function registerViewTool(pi) {
7262
7289
  parameters: Type13.Object({
7263
7290
  path: filePathParam(),
7264
7291
  node: Type13.Optional(Type13.String({ description: "Node ID to use as the view root" })),
7265
- page: optionalIntOrString("One-based source page"),
7292
+ page: optionalIntOrString("One-based PDF page"),
7266
7293
  kind: Type13.Optional(Type13.Union(NODE_KINDS.map((kind) => Type13.Literal(kind)), {
7267
7294
  description: "Node kind filter"
7268
7295
  })),
7269
- depth: optionalIntOrString("Maximum depth below the selected roots"),
7296
+ depth: optionalIntOrString("Maximum depth below selected roots"),
7270
7297
  outline: Type13.Optional(Type13.Boolean({ description: "Return outline nodes only" }))
7271
7298
  }),
7272
7299
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
@@ -7341,10 +7368,9 @@ function formatSettingsWarning(warning) {
7341
7368
  function editingPolicy(readName, editName, writeName) {
7342
7369
  return [
7343
7370
  "ReadSeek editing policy:",
7344
- `- Prefer ${readName} when preparing to edit existing text; its LINE:HASH anchors are required by ${editName}.`,
7345
- `- Prefer ${editName} for existing text files, ${writeName} for whole-file creation or replacement, and readSeek_rename for symbol renames.`,
7346
- "- Do not use Pi's built-in edit or write when the corresponding ReadSeek tool is available.",
7347
- "- Use readSeek_check after source edits for a quick syntax check."
7371
+ `- Read first with ${readName} when preparing to edit; ${editName} needs fresh LINE:HASH anchors.`,
7372
+ `- Use ${editName} for existing files, ${writeName} for whole-file creation or replacement, and readSeek_rename for symbol renames.`,
7373
+ "- Run readSeek_check after source edits for a quick syntax check."
7348
7374
  ].join(`
7349
7375
  `);
7350
7376
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-readseek",
3
- "version": "0.8.18",
4
- "description": "Pi extension for readseek-backed hash-anchored read/edit/grep, structural code maps, structural search, and file exploration",
3
+ "version": "0.8.20",
4
+ "description": "Pi extension for LINE:HASH-anchored file operations and structural code navigation",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./dist/index.ts"
@@ -40,7 +40,7 @@
40
40
  "node": ">=20.0.0"
41
41
  },
42
42
  "dependencies": {
43
- "@jarkkojs/readseek": "^0.8.18",
43
+ "@jarkkojs/readseek": "^0.8.20",
44
44
  "diff": "^9.0.0",
45
45
  "xxhash-wasm": "^1.1.0"
46
46
  },
package/prompts/check.md CHANGED
@@ -1,8 +1,8 @@
1
- Check a source file for parser errors and missing syntax. Use after edits for quick syntax validation, not as a compiler or linter.
1
+ Run a quick syntax check on a source file. Use after edits to find parser errors and missing syntax; this is not a compiler or linter.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `path` — source file to check.
5
+ - `path` — source file.
6
6
 
7
7
  ## Output
8
8
 
package/prompts/def.md CHANGED
@@ -1,10 +1,11 @@
1
- Find symbol declarations by qualified or unqualified name. Use instead of text search when locating where a function, class, type, or other symbol is defined.
1
+ Find symbol declarations by qualified or unqualified name. Use this instead of text search when locating a function, class, type, or other definition.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `path` — file or directory, default `.`.
6
5
  - `name` — qualified or unqualified symbol name.
7
- - `lang` — language override.
8
- - `cached`, `others`, `ignored` — Git file selection; `ignored` requires `others`.
6
+ - `path` — file or directory; defaults to the current directory.
7
+ - `lang` — language override when detection is ambiguous.
8
+ - `cached`, `others`, `ignored` — Git file selection; `ignored` requires
9
+ `others`.
9
10
 
10
- After `readSeek_hover`, use its qualified symbol name.
11
+ After `readSeek_hover`, prefer its qualified symbol name.
package/prompts/edit.md CHANGED
@@ -1,71 +1,68 @@
1
- Edit existing text files safely with fresh `LINE:HASH` anchors; on `file-not-read`, read or search the file first.
1
+ Edit existing text files with fresh `LINE:HASH` anchors. Read or search the file first when no fresh anchors are available. Each `edits[]` item must use exactly one nested object: `{"set_line":{"anchor":"LINE:HASH","new_text":"..."}}`, `{"replace_lines":{"start_anchor":"LINE:HASH","end_anchor":"LINE:HASH","new_text":"..."}}`, `{"insert_after":{"anchor":"LINE:HASH","new_text":"..."}}`, `{"replace_symbol":{"symbol":"name","new_body":"..."}}`, or `{"replace":{"old_text":"...","new_text":"..."}}`.
2
2
 
3
- Anchors come from `readSeek_read`, `readSeek_grep`, `readSeek_search`, or `readSeek_write`.
3
+ Anchors come from `readSeek_read`, `readSeek_grep`, `readSeek_search`, or
4
+ `readSeek_write`.
4
5
 
5
6
  ## Variants
6
7
 
7
- | Variant | Use | Anchors |
8
- |---|---|---|
9
- | `set_line` | Replace or delete one line | 1 |
10
- | `replace_lines` | Replace or delete one contiguous range | 2 |
11
- | `insert_after` | Insert after an existing line | 1 |
12
- | `replace_symbol` | Replace one mapped symbol | 0 (`symbol`) |
13
- | `replace` | Exact string replacement; one match unless `all: true` | 0 |
8
+ | Variant | Use | Required anchor |
9
+ | --- | --- | --- |
10
+ | `set_line` | Replace or delete one line | `anchor` |
11
+ | `replace_lines` | Replace or delete one contiguous range | `start_anchor`, `end_anchor` |
12
+ | `insert_after` | Insert after one line | `anchor` |
13
+ | `replace_symbol` | Replace one mapped symbol | `symbol` instead of an anchor |
14
+ | `replace` | Replace exact text; one match unless `all: true` | None |
14
15
 
15
- Set `new_text` to `""` to delete lines; use `"\n"` for a blank line. Prefer
16
- anchored variants. Use `replace` only when anchors are impractical.
16
+ Use `new_text: ""` to delete lines and `new_text: "\n"` for a blank line.
17
+ Prefer anchored variants. Use `replace_symbol` for a whole symbol and `replace`
18
+ only when anchors are impractical.
17
19
 
18
- ## Input shape
20
+ Each `edits[]` item contains exactly one variant. `new_text` and `new_body` are
21
+ plain file content, not a diff or hashline output.
19
22
 
20
23
  ```json
21
24
  {
22
25
  "path": "src/foo.ts",
23
26
  "edits": [
24
27
  { "set_line": { "anchor": "42:ab1", "new_text": "const x = 2;" } },
25
- { "replace_lines": { "start_anchor": "50:c3d", "end_anchor": "55:e4f", "new_text": "const y = 3;\nreturn y;" } },
26
- { "insert_after": { "anchor": "60:f5a", "new_text": "// TODO\n" } },
27
- { "replace_symbol": { "symbol": "add", "new_body": "export function add(a, b) {\n return a + b;\n}" } },
28
- { "replace": { "old_text": "value", "new_text": "result", "all": true } }
28
+ {
29
+ "replace_lines": {
30
+ "start_anchor": "50:c3d",
31
+ "end_anchor": "55:e4f",
32
+ "new_text": "const y = 3;\nreturn y;"
33
+ }
34
+ },
35
+ { "insert_after": { "anchor": "60:f5a", "new_text": "// TODO\n" } }
29
36
  ]
30
37
  }
31
38
  ```
32
39
 
33
- Use only needed variants. Each `edits[]` entry has exactly one key. `new_text`
34
- and `new_body` are plain file content, not diffs or hashlines.
40
+ ## Exact, fuzzy, and symbol replacement
35
41
 
36
- ## Exact and fuzzy replacement
42
+ `replace` is exact by default and fails when its text is absent. `fuzzy: true`
43
+ retries only after exact matching fails and normalizes whitespace plus
44
+ confusable Unicode. Verify any warned fuzzy match.
37
45
 
38
- `replace` is exact by default; missing text fails. `fuzzy: true` only normalizes
39
- whitespace and confusable Unicode after exact matching fails. Verify warned fuzzy
40
- matches before continuing.
46
+ `replace_symbol` accepts `Name`, `Class.method`, or `Name@<line>` in a mappable
47
+ source file. `new_body` must be non-empty and unindented. Do not overlap a
48
+ symbol replacement with anchored edits.
41
49
 
42
- ## `replace_symbol`
50
+ ## Stale anchors and validation
43
51
 
44
- Use `replace_symbol` for one whole mapped `Name`, `Class.method`, or
45
- `Name@<line>` in any mappable source file. `new_body` must be non-empty and
46
- unindented. Confirm fuzzy symbol matches first; do not overlap them with anchored
47
- edits.
48
-
49
- ## Stale anchors
50
-
51
- On `hash-mismatch`, nearby lines marked `>>>` include fresh anchors:
52
+ A `hash-mismatch` response marks nearby current lines with `>>>`, for example:
52
53
 
53
54
  ```text
54
55
  >>> 41:b34| const renamed = 3;
55
56
  ```
56
57
 
57
- Retry with those anchors, or read/search again. Verify any auto-relocation warning.
58
-
59
- ## Validation and warnings
60
-
61
- All edits validate before writing; hard failures write nothing. Anchored edits run
62
- bottom-up. `no-op` means no change. Syntax validation for every language with a
63
- tree-sitter parser follows `readseek.syntaxValidation`: `warn` (default), `block`,
64
- or `off`. It triggers when error or missing-node counts increase and reports the
65
- post-edit diagnostic ranges.
58
+ Retry with those anchors or read/search again. Verify any automatic relocation
59
+ warning.
66
60
 
67
- ## Optional post-edit verification
61
+ All edits validate before writing; a hard failure writes nothing. Anchored edits
62
+ run bottom-up. `no-op` means no content changed. For languages with a tree-sitter
63
+ parser, `readseek.syntaxValidation` controls newly introduced parse errors:
64
+ `warn` (default), `block`, or `off`.
68
65
 
69
- `postEditVerify: true` reads back the written file and compares the persisted
70
- content, including BOM and line endings. Results provide a compact hashline diff,
71
- a unified patch, and structured `details.diffData`.
66
+ Set `postEditVerify: true` to read back the file and compare persisted content,
67
+ including its BOM and line endings. Verification returns a compact anchored
68
+ diff, unified patch, and structured `details.diffData`.
package/prompts/grep.md CHANGED
@@ -1,24 +1,27 @@
1
- Search plain text or regex in files and return edit-ready `LINE:HASH` anchors. Use for identifiers, strings, configuration, errors, comments, or documentation.
1
+ Search text or regex in files and return edit-ready `LINE:HASH` anchors. Use for identifiers, strings, configuration, errors, comments, and documentation.
2
2
 
3
3
  ## Modes
4
4
 
5
- - Default: matching lines only. Match rows look like `path:>>LINE:HASH|content`.
6
- - `context: N`: include N lines before and after each match. Context rows use `path: LINE:HASH|content`; nearby ranges are merged and deduped.
7
- - `summary: true`: return per-file match counts only. Use this first for broad searches, then narrow with `path`, `glob`, or a stricter pattern.
8
- - `scope: "symbol"`: group matches by enclosing symbol. By default returns full symbol blocks. `scopeContext: N` clips each match to ±N lines inside the symbol; `0` returns only match lines. Ignored with `summary: true`.
5
+ - Default: return matching lines as `path:>>LINE:HASH|content`.
6
+ - `context: N`: include N surrounding lines. Context rows use
7
+ `path: LINE:HASH|content`; overlapping ranges are merged.
8
+ - `summary: true`: return per-file counts only. Use this first for a broad
9
+ search, then narrow by `path`, `glob`, or pattern.
10
+ - `scope: "symbol"`: group matches by their enclosing symbol. By default the
11
+ full symbol is returned; `scopeContext: N` clips each match to ±N lines inside
12
+ it, and `0` returns only matching lines. `summary` ignores symbol scope.
9
13
 
10
14
  ## Parameters
11
15
 
12
- - `pattern` — regular expression by default; set `literal: true` for exact text or regex metacharacters.
13
- - `path` — file or directory, default cwd.
16
+ - `pattern` — regular expression by default; set `literal: true` for exact text.
17
+ - `path` — file or directory; defaults to the current directory.
14
18
  - `glob` — file-name filter such as `*.ts` or `**/*.test.ts`.
15
19
  - `ignoreCase` — case-insensitive search.
16
- - `context` — surrounding lines for normal grep.
17
- - `limit` — maximum matches, default 100.
18
- - `summary` — counts only, no anchors.
20
+ - `context` — surrounding lines in normal mode.
21
+ - `limit` — maximum matches; defaults to 100.
22
+ - `summary` — return counts without anchors.
19
23
  - `scope` — only `"symbol"` is supported.
20
- - `scopeContext` — non-negative context within symbol scope; requires `scope: "symbol"`.
24
+ - `scopeContext` — non-negative context inside symbol scope.
21
25
 
22
- If output is truncated at `limit` or by the display budget, narrow with `summary`,
23
- then `path`/`glob`, then a stricter pattern. Request context or symbol blocks only
24
- after narrowing.
26
+ If `limit` or the display budget truncates output, start with `summary`, narrow
27
+ the file set and pattern, then request context or symbol blocks.
package/prompts/hover.md CHANGED
@@ -1,6 +1,7 @@
1
- Identify the token and enclosing symbol at a cursor. Use before rename or definition lookup, or to identify a line's enclosing symbol. The file is read from disk.
1
+ Identify the token and enclosing symbol at a cursor. Use before definition lookup or rename, or to identify a line's enclosing symbol.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `path`, `line` — required file path and one-based cursor line.
5
+ - `path` — source file.
6
+ - `line` — one-based cursor line.
6
7
  - `column` — optional one-based cursor byte column.
package/prompts/read.md CHANGED
@@ -1,45 +1,50 @@
1
- Read anchored text by range, map, or symbol, process images with an explicit mode, and always read PDF text.
1
+ Read anchored text by range, symbol, or map. Standalone images require an explicit mode; PDF text is always returned.
2
2
 
3
- ## Choose the right read
3
+ ## Choose a read
4
4
 
5
- - Normal read: a small file or an `offset` / `limit` range.
6
- - `map: true`: append a structural map.
5
+ - Default: read a small file or an `offset` / `limit` range.
6
+ - `map: true`: append the file's structural map.
7
7
  - `symbol: "Name"`: read one mapped symbol.
8
- - `bundle: "local"`: include direct same-file support for a symbol.
8
+ - `bundle: "local"`: include directly related symbols from the same file.
9
9
 
10
10
  ## Parameters
11
11
 
12
12
  - `path` — file path.
13
- - `offset` / `limit` — positive lines; `offset` is 1-indexed.
14
- - `map` — full-file map; incompatible with `symbol` or `bundle`.
15
- - `symbol` — `Name`, `Class.method`, or `Name@<line>`; incompatible with `offset` / `limit`.
13
+ - `offset` / `limit` — positive line numbers; `offset` is one-based.
14
+ - `map` — append a full-file map; incompatible with `symbol` and `bundle`.
15
+ - `symbol` — `Name`, `Class.method`, or `Name@<line>`; incompatible with
16
+ `offset` and `limit`.
16
17
  - `bundle` — only `"local"`; requires `symbol` and excludes `map`.
17
- - `image` — an exposed standalone-image/PDF embedded-image mode; unavailable when `imageMode` is `"off"`.
18
- - `page` — one-based PDF page; defaults to page 1 and cannot be combined with `offset` / `limit`.
19
-
20
- Default cap: {{DEFAULT_MAX_LINES}} lines or {{DEFAULT_MAX_BYTES}}. PDF reads always return text for one page by default. Omitting `image` skips standalone images and PDF embedded images unless native vision is available in `"auto"` mode. With native vision, prepared standalone and PDF embedded images are passed directly instead of using local analysis.
21
-
22
- Truncated full-file reads append a map when available. Use its ranges for follow-up reads.
23
-
24
- ## Symbol examples
25
-
26
- | Query | Reads |
27
- |---|---|
28
- | `{ "symbol": "processEvent" }` | function or unqualified symbol |
29
- | `{ "symbol": "EventEmitter" }` | class/interface/type/enum/etc. |
30
- | `{ "symbol": "EventEmitter.emit" }` | child method/member |
31
- | `{ "symbol": "Foo.bar@42" }` | overload/definition near line 42 |
32
- | `{ "symbol": "handleRequest", "bundle": "local" }` | symbol plus direct same-file support |
33
-
34
- ## Symbol resolution
35
-
36
- `@<line>` is only a trailing suffix, as in `Foo.bar@42`; `foo@bar` is an ordinary name. Resolution prefers the containing range, then the nearest symbol at or after the line, then one above it.
37
-
38
- Result behavior:
39
-
40
- - **Found:** the symbol range.
41
- - **Ambiguous:** candidates and `name@<startLine>` retry hints.
42
- - **Fuzzy:** a warned best match; verify before editing.
43
- - **Not found/unmappable:** normal read with a warning and suggestions when available.
44
-
45
- Hash anchors from normal, symbol, and bundled reads are valid for `readSeek_edit` until the file changes.
18
+ - `image` — standalone-image/PDF embedded-image mode; unavailable when
19
+ `imageMode` is `"off"`.
20
+ - `page` — one-based PDF page; defaults to 1 and excludes `offset` / `limit`.
21
+
22
+ Text output is capped at {{DEFAULT_MAX_LINES}} lines or {{DEFAULT_MAX_BYTES}}.
23
+ A truncated full-file read appends a map when available; use its ranges for
24
+ follow-up reads.
25
+
26
+ Standalone images require `image`. In `"auto"`, `image: "none"` returns a
27
+ prepared standalone image without local analysis. PDF text is always read;
28
+ without `image`, embedded images are skipped unless an image-capable Pi model is
29
+ active in `"auto"` mode. That model receives prepared images directly.
30
+
31
+ ## Symbol lookup
32
+
33
+ | Query | Result |
34
+ | --- | --- |
35
+ | `{"symbol":"processEvent"}` | Function or other unqualified symbol |
36
+ | `{"symbol":"EventEmitter"}` | Class, interface, type, enum, or similar symbol |
37
+ | `{"symbol":"EventEmitter.emit"}` | Qualified child method or member |
38
+ | `{"symbol":"Foo.bar@42"}` | Definition or overload near line 42 |
39
+ | `{"symbol":"handleRequest","bundle":"local"}` | Symbol plus direct same-file support |
40
+
41
+ `@<line>` is a trailing disambiguator; `foo@bar` remains an ordinary name.
42
+ Resolution prefers a containing range, then the nearest symbol at or after the
43
+ line, then one above it.
44
+
45
+ A successful lookup returns the symbol range. Ambiguous results include
46
+ `name@<startLine>` retry hints. Verify fuzzy matches before editing. A missing or
47
+ unmappable symbol falls back to a normal read with a warning.
48
+
49
+ Anchors from text, symbol, and bundled reads remain valid for `readSeek_edit`
50
+ until the file changes.
package/prompts/refs.md CHANGED
@@ -1,25 +1,21 @@
1
- Find identifier usages with enclosing symbols and edit-ready anchors. Use before renaming, deleting, or changing a symbol; add a cursor scope to exclude same-named bindings.
1
+ Find identifier usages with enclosing symbols and edit-ready `LINE:HASH` anchors. Add cursor scope to follow one binding and exclude shadows.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `name` — identifier to find references for.
6
- - `path` — file or directory, default cwd.
7
- - `lang` — language hint for ambiguous, extensionless, or generated code.
8
- - `scope` — restrict results to the binding under `line`/`column` in a single file. Requires `line`.
9
- - `line` — one-based cursor line, used with `scope`.
10
- - `column` — one-based cursor byte column, used with `scope`.
11
- - `cached` — in a Git repository, search tracked/indexed files.
12
- - `others` — in a Git repository, search untracked files.
13
- - `ignored` — with `others`, include ignored untracked files.
5
+ - `name` — identifier to find.
6
+ - `path` — file or directory; defaults to the current directory.
7
+ - `lang` — language override for ambiguous, extensionless, or generated source.
8
+ - `scope` — restrict results to the binding at `line` / `column` in one file;
9
+ requires `line`.
10
+ - `line` — one-based cursor line used with `scope`.
11
+ - `column` — optional one-based cursor byte column used with `scope`.
12
+ - `cached` — search tracked/indexed files in a Git repository.
13
+ - `others` — search untracked files in a Git repository.
14
+ - `ignored` — include ignored untracked files; requires `others`.
14
15
 
15
- ## Scope
16
+ Without `scope`, results match by name. With `scope`, results follow the cursor
17
+ binding and exclude shadows.
16
18
 
17
- Without `scope`, references match by name. With `scope` and `line` (optionally
18
- `column`), results are limited to the cursor binding in one file and exclude
19
- shadows.
20
-
21
- ## Git selection
22
-
23
- In Git repositories, directory search includes tracked/indexed and untracked,
24
- non-ignored files by default. `cached` or `others` restricts the search to that
25
- group; `ignored` requires `others`.
19
+ In a Git work tree, directory search includes tracked/indexed and untracked
20
+ non-ignored files by default. Setting `cached` or `others` restricts the set;
21
+ `ignored` requires `others`.
package/prompts/rename.md CHANGED
@@ -1,9 +1,11 @@
1
- Rename the symbol at a cursor without changing resolvable same-named bindings. Use for symbol renames; use search and edit for broader refactors.
1
+ Rename the symbol at a cursor while preserving resolvable same-named bindings. Set `apply: false` to preview the verified plan.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `path`, `line`, `to` — required file, one-based cursor line, and plain new name.
5
+ - `path` — source file containing the cursor.
6
+ - `line` — one-based cursor line.
6
7
  - `column` — optional one-based cursor byte column.
7
- - `workspace` — expand across the project; local shadows are excluded where binding
8
- support is available, and other files are otherwise matched by name.
9
- - `apply` — default `true`; set `false` to return only the verified plan.
8
+ - `to` — new plain identifier.
9
+ - `workspace` — expand across the project. The cursor file remains binding-aware;
10
+ other files use name matching where binding resolution is unavailable.
11
+ - `apply` — defaults to `true`; set `false` to return only the verified plan.
package/prompts/search.md CHANGED
@@ -1,35 +1,35 @@
1
- Search syntax-aware code shapes with AST patterns and return edit-ready anchors. Use for calls, imports, declarations, JSX, object fields, or control flow; use `readSeek_grep` for plain text.
1
+ Search AST patterns (ast-grep style) and return edit-ready `LINE:HASH` anchors. Use `readSeek_grep` for plain text or regex.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `pattern` — ast-grep-style pattern to match.
6
- - `lang` — language hint for ambiguous, extensionless, generated, or JSX-like code.
7
- - `path` — file or directory, default cwd.
8
- - `cached` — in a Git repository, search tracked/indexed files.
9
- - `others` — in a Git repository, search untracked files.
10
- - `ignored` — with `others`, include ignored untracked files.
5
+ - `pattern` — AST pattern to match.
6
+ - `path` — file or directory; defaults to the current directory.
7
+ - `lang` — language override for ambiguous, extensionless, generated, or
8
+ JSX-like source.
9
+ - `cached` — search tracked/indexed files in a Git repository.
10
+ - `others` — search untracked files in a Git repository.
11
+ - `ignored` — include ignored untracked files; requires `others`.
11
12
 
12
13
  ## Pattern syntax
13
14
 
14
15
  - `$NAME` matches one AST node.
15
- - `$_` matches any one AST node when you do not need to reuse it.
16
- - `$$$ARGS` matches zero or more sibling nodes. Use it for function args, body statements, object fields, JSX children, etc.
17
- - Reusing a metavariable name requires every occurrence to match the same source text.
18
-
19
- Patterns are code, not text: formatting is mostly ignored, but syntax and required
20
- punctuation must be valid for the selected language.
21
-
22
- ## Examples
23
-
24
- - `console.log($$$ARGS)` — calls.
25
- - `import $NAME from '$SOURCE'` — default imports.
26
- - `export function $NAME($$$PARAMS) { $$$BODY }` — exported functions.
27
- - `$OBJ.$METHOD($$$ARGS)` — method calls.
28
- - `<$TAG $$$ATTRS>$$$CHILDREN</$TAG>` — JSX/TSX elements.
29
- - `if ($COND) { $$$BODY }` — control-flow blocks.
30
-
31
- ## Git selection
32
-
33
- In Git repositories, directory search includes tracked/indexed and untracked,
34
- non-ignored files by default. `cached` or `others` restricts the search to that
35
- group; `ignored` requires `others`.
16
+ - `$_` matches one node without capturing a reusable value.
17
+ - `$$$ARGS` matches zero or more sibling nodes, such as arguments, statements,
18
+ object fields, or JSX children.
19
+ - Reusing a metavariable requires every occurrence to match the same source text.
20
+
21
+ Patterns are code, not text. Formatting is mostly ignored, but syntax and
22
+ required punctuation must be valid for the selected language.
23
+
24
+ ```text
25
+ console.log($$$ARGS)
26
+ import $NAME from '$SOURCE'
27
+ export function $NAME($$$PARAMS) { $$$BODY }
28
+ $OBJ.$METHOD($$$ARGS)
29
+ <$TAG $$$ATTRS>$$$CHILDREN</$TAG>
30
+ if ($COND) { $$$BODY }
31
+ ```
32
+
33
+ In a Git work tree, directory search includes tracked/indexed and untracked
34
+ non-ignored files by default. Setting `cached` or `others` restricts the set;
35
+ `ignored` requires `others`.
package/prompts/view.md CHANGED
@@ -1,14 +1,14 @@
1
- View the structure or selected content of an indexed PDF. Start with the default overview, then narrow by page or node instead of reading the whole document.
1
+ View the structure or selected content of a PDF. Start with the overview, then narrow by page or node instead of reading the whole document.
2
2
 
3
3
  ## Parameters
4
4
 
5
- - `path` — PDF document to view.
6
- - `node` — optional node ID to use as the view root.
7
- - `page` — optional one-based source page.
8
- - `kind` — optional node kind filter.
9
- - `depth` — optional maximum depth below selected roots.
5
+ - `path` — PDF file.
6
+ - `node` — node ID to use as the view root.
7
+ - `page` — one-based PDF page.
8
+ - `kind` — node kind filter.
9
+ - `depth` — maximum depth below selected roots.
10
10
  - `outline` — return outline nodes only.
11
11
 
12
- ## Output
13
-
14
- Returns a bounded text projection with stable node IDs and source page references.
12
+ A `.readseek/` directory must already exist; run `readseek init` if needed. The
13
+ first call then creates a reusable structural index. Output is a bounded text
14
+ projection with stable node IDs and source-page references.
package/prompts/write.md CHANGED
@@ -1,19 +1,16 @@
1
- Create or replace a complete file and return `LINE:HASH` anchors. Use for new or fully generated files; use anchored edits for small changes.
1
+ Create or replace a complete text file and return `LINE:HASH` anchors. Use anchored edits for small changes to an existing file.
2
2
 
3
- ## Usage
4
-
5
- Existing files are overwritten without confirmation. Binary-looking content is
6
- rejected without writing.
3
+ Existing files are replaced without confirmation. Binary-looking content is
4
+ rejected before writing.
7
5
 
8
6
  ## Parameters
9
7
 
10
8
  - `path` — file path.
11
- - `content` — complete file contents.
9
+ - `content` — complete file content.
12
10
  - `map` — append a best-effort structural map.
13
11
 
14
12
  ## Output
15
13
 
16
- Text writes return `LINE:HASH|content`. Visible output is capped at
17
- {{DEFAULT_MAX_LINES}} lines or {{DEFAULT_MAX_BYTES}}; full anchors remain in
18
- `readSeekValue`. Results also include a compact
19
- diff, unified patch, and structured `details.diffData`.
14
+ Text output uses `LINE:HASH|content` and is capped at {{DEFAULT_MAX_LINES}} lines
15
+ or {{DEFAULT_MAX_BYTES}}. Complete anchors remain in `readSeekValue`. Results
16
+ also include a compact diff and structured `details.diffData`.