pi-readseek 0.5.0 → 0.5.2
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 +7 -6
- package/package.json +1 -1
- package/prompts/read.md +1 -1
- package/src/hover.ts +2 -2
- package/src/read.ts +6 -10
- package/src/readseek-settings.ts +18 -18
- package/src/rename.ts +2 -2
- package/src/tool-prompt-metadata.ts +2 -2
package/README.md
CHANGED
|
@@ -38,17 +38,18 @@ npm install --save-dev @jarkkojs/readseek
|
|
|
38
38
|
|
|
39
39
|
`pi-readseek` reads optional JSON settings from:
|
|
40
40
|
|
|
41
|
-
- `~/.pi/agent/
|
|
42
|
-
- `.pi/
|
|
41
|
+
- `~/.pi/agent/settings.json` — Global
|
|
42
|
+
- `.pi/settings.json` — Project
|
|
43
43
|
|
|
44
|
-
Project settings override global settings.
|
|
45
|
-
`
|
|
44
|
+
Project settings override global settings. The `readseek` section lives inside pi's
|
|
45
|
+
shared `settings.json`, alongside other extensions' sections. All settings are
|
|
46
|
+
optional (defaults shown):
|
|
46
47
|
|
|
47
48
|
```json
|
|
48
49
|
{
|
|
49
50
|
"readseek": {
|
|
50
51
|
"excludeTools": [],
|
|
51
|
-
"
|
|
52
|
+
"imageMode": "force",
|
|
52
53
|
"syntaxValidation": "warn",
|
|
53
54
|
"timeoutMs": 120000,
|
|
54
55
|
"grep": {
|
|
@@ -62,7 +63,7 @@ Project settings override global settings. All settings live in a single
|
|
|
62
63
|
- **excludeTools:** active tool names to hide after activating `readSeek_*`
|
|
63
64
|
tools. For a readseek-only file surface, use `["read", "edit", "write",
|
|
64
65
|
"grep"]`.
|
|
65
|
-
- **
|
|
66
|
+
- **imageMode:** image OCR/caption/object analysis in `readSeek_read`: `"force"`
|
|
66
67
|
(or its alias `"on"`) always runs it, `"off"` returns only the image
|
|
67
68
|
attachment, and `"auto"` runs it only when the active model does not support
|
|
68
69
|
native image input.
|
package/package.json
CHANGED
package/prompts/read.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Read files through readseek. Text output uses `LINE:HASH|content` anchors that can be copied directly into `readSeek_edit`; supported images return attachments and may append OCR/caption/object text depending on `readseek.
|
|
1
|
+
Read files through readseek. Text output uses `LINE:HASH|content` anchors that can be copied directly into `readSeek_edit`; supported images return attachments and may append OCR/caption/object text depending on `readseek.imageMode`. Default cap: {{DEFAULT_MAX_LINES}} lines or {{DEFAULT_MAX_BYTES}}.
|
|
2
2
|
|
|
3
3
|
## Choose the right read
|
|
4
4
|
|
package/src/hover.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { formatFsError } from "./fs-error.js";
|
|
|
11
11
|
import { classifyReadSeekFailure, readSeekIdentify } from "./readseek-client.js";
|
|
12
12
|
import { filePathParam, registerReadSeekTool } from "./register-tool.js";
|
|
13
13
|
|
|
14
|
-
import { clampLinesToWidth, linkToolPath, renderPendingResult, resolveRenderResultContext, summaryLine } from "./tui-render-utils.js";
|
|
14
|
+
import { clampLineToWidth, clampLinesToWidth, linkToolPath, renderPendingResult, resolveRenderResultContext, summaryLine } from "./tui-render-utils.js";
|
|
15
15
|
|
|
16
16
|
const HOVER_PROMPT_METADATA = defineToolPromptMetadata({
|
|
17
17
|
promptUrl: new URL("../prompts/hover.md", import.meta.url),
|
|
@@ -109,7 +109,7 @@ export function registerHoverTool(pi: ExtensionAPI) {
|
|
|
109
109
|
let text = theme.fg("toolTitle", theme.bold("hover"));
|
|
110
110
|
text += ` ${linkToolPath(theme.fg("accent", displayPath), displayPath, cwd)}`;
|
|
111
111
|
if (args?.line) text += theme.fg("dim", `:${args.line}`);
|
|
112
|
-
return text;
|
|
112
|
+
return new Text(clampLineToWidth(text, context.width), 0, 0);
|
|
113
113
|
},
|
|
114
114
|
renderResult(result: any, options: ToolRenderResultOptions, theme: any, ...rest: any[]) {
|
|
115
115
|
const { isPartial, isError, width } = resolveRenderResultContext(options, rest);
|
package/src/read.ts
CHANGED
|
@@ -28,14 +28,14 @@ import { buildLocalBundle } from "./read-local-bundle.js";
|
|
|
28
28
|
import { coerceObviousBase10Int } from "./coerce-obvious-int.js";
|
|
29
29
|
import { readSeekRead, readSeekDetect, readSeekImage, type ReadSeekDetection } from "./readseek-client.js";
|
|
30
30
|
import { formatReadCallText, formatReadResultText } from "./read-render-helpers.js";
|
|
31
|
-
import {
|
|
31
|
+
import { resolveReadSeekImageMode } from "./readseek-settings.js";
|
|
32
32
|
import { clampLineToWidth, clampLinesToWidth, linkToolPath, renderPendingResult, renderToolLabel, resolveRenderResultContext, summaryLine, wrapReadHashlinesForWidthCached } from "./tui-render-utils.js";
|
|
33
33
|
import type { FileAnchoredCallback } from "./tool-types.js";
|
|
34
34
|
import { filePathParam, mapParam, optionalIntOrString, registerReadSeekTool } from "./register-tool.js";
|
|
35
35
|
|
|
36
36
|
const READ_PROMPT_METADATA = defineToolPromptMetadata({
|
|
37
37
|
promptUrl: new URL("../prompts/read.md", import.meta.url),
|
|
38
|
-
promptSnippet: "Read text files or images; text reads include hashline anchors and optional maps/symbol lookup, image reads include the attachment plus OCR text",
|
|
38
|
+
promptSnippet: "Read text files or images; text reads include hashline anchors and optional maps/symbol lookup, image reads include the attachment plus OCR text, an image caption, and detected objects",
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
interface ReadParams {
|
|
@@ -58,7 +58,7 @@ export interface ExecuteReadOptions {
|
|
|
58
58
|
onUpdate: any;
|
|
59
59
|
cwd: string;
|
|
60
60
|
onSuccessfulRead?: FileAnchoredCallback;
|
|
61
|
-
/** Whether the active model accepts image input natively. Used when
|
|
61
|
+
/** Whether the active model accepts image input natively. Used when imageMode is auto. */
|
|
62
62
|
modelSupportsImages?: boolean;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -177,11 +177,10 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
177
177
|
if (detection?.kind === "image") {
|
|
178
178
|
const builtinRead = createReadTool(cwd);
|
|
179
179
|
const builtinResult = await builtinRead.execute(toolCallId, p, signal, onUpdate);
|
|
180
|
-
const
|
|
181
|
-
const shouldRunVision =
|
|
180
|
+
const imageMode = resolveReadSeekImageMode();
|
|
181
|
+
const shouldRunVision = imageMode === "force" || (imageMode === "auto" && !opts.modelSupportsImages);
|
|
182
182
|
if (!shouldRunVision) return succeed(builtinResult);
|
|
183
183
|
|
|
184
|
-
let ocrFailed = false;
|
|
185
184
|
try {
|
|
186
185
|
const ocrDetection = await readSeekImage(absolutePath, ["ocr", "caption", "objects"], { signal });
|
|
187
186
|
const imageAnalysis = formatImageAnalysis(ocrDetection);
|
|
@@ -195,14 +194,11 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
195
194
|
});
|
|
196
195
|
}
|
|
197
196
|
} catch {
|
|
198
|
-
ocrFailed = true;
|
|
199
|
-
}
|
|
200
|
-
if (ocrFailed) {
|
|
201
197
|
return succeed({
|
|
202
198
|
...builtinResult,
|
|
203
199
|
content: [
|
|
204
200
|
...(builtinResult.content ?? []),
|
|
205
|
-
{ type: "text" as const, text: "[Warning: local image analysis
|
|
201
|
+
{ type: "text" as const, text: "[Warning: local image analysis unavailable — showing image attachment only]" },
|
|
206
202
|
],
|
|
207
203
|
});
|
|
208
204
|
}
|
package/src/readseek-settings.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { readFileSync, statSync, type Stats } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
|
-
export type
|
|
5
|
+
export type ReadSeekImageAnalysisMode = "force" | "off" | "auto";
|
|
6
6
|
export type ReadSeekSyntaxValidationMode = "warn" | "block" | "off";
|
|
7
7
|
|
|
8
8
|
interface ReadSeekGrepSettings {
|
|
@@ -12,7 +12,7 @@ interface ReadSeekGrepSettings {
|
|
|
12
12
|
|
|
13
13
|
interface ReadSeekJsonSettings {
|
|
14
14
|
excludeTools?: string[];
|
|
15
|
-
|
|
15
|
+
imageMode?: ReadSeekImageAnalysisMode;
|
|
16
16
|
syntaxValidation?: ReadSeekSyntaxValidationMode;
|
|
17
17
|
timeoutMs?: number;
|
|
18
18
|
grep?: ReadSeekGrepSettings;
|
|
@@ -29,15 +29,15 @@ export interface ReadSeekSettingsResult {
|
|
|
29
29
|
warnings: ReadSeekSettingsWarning[];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const READSEEK_KEYS = ["excludeTools", "
|
|
32
|
+
const READSEEK_KEYS = ["excludeTools", "imageMode", "syntaxValidation", "timeoutMs", "grep"];
|
|
33
33
|
const READSEEK_GREP_KEYS = ["maxLines", "maxBytes"];
|
|
34
34
|
|
|
35
|
-
function
|
|
36
|
-
return join(homedir(), ".pi/agent/
|
|
35
|
+
function globalSettingsPath(): string {
|
|
36
|
+
return join(homedir(), ".pi/agent/settings.json");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function
|
|
40
|
-
return join(process.cwd(), ".pi/
|
|
39
|
+
function projectSettingsPath(): string {
|
|
40
|
+
return join(process.cwd(), ".pi/settings.json");
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -91,16 +91,16 @@ function readEnum<T extends string>(
|
|
|
91
91
|
return undefined;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
function
|
|
94
|
+
function readImageMode(
|
|
95
95
|
raw: Record<string, unknown>,
|
|
96
96
|
source: string,
|
|
97
97
|
warnings: ReadSeekSettingsWarning[],
|
|
98
|
-
):
|
|
99
|
-
if (!("
|
|
100
|
-
const val = raw.
|
|
98
|
+
): ReadSeekImageAnalysisMode | undefined {
|
|
99
|
+
if (!("imageMode" in raw)) return undefined;
|
|
100
|
+
const val = raw.imageMode;
|
|
101
101
|
if (val === "on") return "force";
|
|
102
102
|
if (val === "force" || val === "off" || val === "auto") return val;
|
|
103
|
-
warnings.push(invalid(source, "readseek.
|
|
103
|
+
warnings.push(invalid(source, "readseek.imageMode"));
|
|
104
104
|
return undefined;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -153,8 +153,8 @@ function validateSettings(raw: unknown, source: string): ReadSeekSettingsResult
|
|
|
153
153
|
const excludeTools = readStringArray(section, "excludeTools", "readseek.excludeTools", source, warnings);
|
|
154
154
|
if (excludeTools !== undefined) settings.excludeTools = excludeTools;
|
|
155
155
|
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
156
|
+
const imageMode = readImageMode(section, source, warnings);
|
|
157
|
+
if (imageMode !== undefined) settings.imageMode = imageMode;
|
|
158
158
|
|
|
159
159
|
const syntaxValidation = readEnum(
|
|
160
160
|
section,
|
|
@@ -232,16 +232,16 @@ function mergeSettings(base: ReadSeekJsonSettings, override: ReadSeekJsonSetting
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
export function resolveReadSeekJsonSettings(): ReadSeekSettingsResult {
|
|
235
|
-
const globalResult = readSettingsFile(
|
|
236
|
-
const projectResult = readSettingsFile(
|
|
235
|
+
const globalResult = readSettingsFile(globalSettingsPath());
|
|
236
|
+
const projectResult = readSettingsFile(projectSettingsPath());
|
|
237
237
|
return {
|
|
238
238
|
settings: mergeSettings(globalResult.settings, projectResult.settings),
|
|
239
239
|
warnings: [...globalResult.warnings, ...projectResult.warnings],
|
|
240
240
|
};
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
export function
|
|
244
|
-
return resolveReadSeekJsonSettings().settings.
|
|
243
|
+
export function resolveReadSeekImageMode(): ReadSeekImageAnalysisMode {
|
|
244
|
+
return resolveReadSeekJsonSettings().settings.imageMode ?? "force";
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
export function resolveReadSeekSyntaxValidation(): ReadSeekSyntaxValidationMode | undefined {
|
package/src/rename.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { resolveToCwd } from "./path-utils.js";
|
|
|
9
9
|
import { classifyReadSeekFailure, readSeekRename, type RenameOutput } from "./readseek-client.js";
|
|
10
10
|
import { filePathParam, registerReadSeekTool } from "./register-tool.js";
|
|
11
11
|
|
|
12
|
-
import { clampLinesToWidth, linkToolPath, renderPendingResult, resolveRenderResultContext, summaryLine } from "./tui-render-utils.js";
|
|
12
|
+
import { clampLineToWidth, clampLinesToWidth, linkToolPath, renderPendingResult, resolveRenderResultContext, summaryLine } from "./tui-render-utils.js";
|
|
13
13
|
|
|
14
14
|
const RENAME_PROMPT_METADATA = defineToolPromptMetadata({
|
|
15
15
|
promptUrl: new URL("../prompts/rename.md", import.meta.url),
|
|
@@ -125,7 +125,7 @@ export function registerRenameTool(pi: ExtensionAPI) {
|
|
|
125
125
|
let text = theme.fg("toolTitle", theme.bold("rename"));
|
|
126
126
|
text += ` ${linkToolPath(theme.fg("accent", displayPath), displayPath, cwd)}`;
|
|
127
127
|
if (args?.to) text += theme.fg("dim", ` → ${args.to}`);
|
|
128
|
-
return text;
|
|
128
|
+
return new Text(clampLineToWidth(text, context.width), 0, 0);
|
|
129
129
|
},
|
|
130
130
|
renderResult(result: any, options: ToolRenderResultOptions, theme: any, ...rest: any[]) {
|
|
131
131
|
const { isPartial, isError, expanded, width } = resolveRenderResultContext(options, rest);
|
|
@@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
|
|
5
5
|
const COMPACT_DESCRIPTIONS: Record<string, string> = {
|
|
6
|
-
"read.md": "Read text files/images by path; text has LINE:HASH anchors, images return the attachment plus OCR
|
|
6
|
+
"read.md": "Read text files/images by path; text has LINE:HASH anchors, images return the attachment plus OCR text, a caption, and detected objects.",
|
|
7
7
|
"edit.md": "Edit existing text files using fresh LINE:HASH anchors from readSeek_read, readSeek_grep, readSeek_search, or readSeek_write.",
|
|
8
8
|
"grep.md": "Search file contents; non-summary results include LINE:HASH anchors for edits.",
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ const COMPACT_GUIDELINES: Record<string, string[]> = {
|
|
|
16
16
|
"read.md": [
|
|
17
17
|
"Use readSeek_read for file contents, images/screenshots, ranges, symbols, and edit anchors.",
|
|
18
18
|
"Use map or symbol mode before pulling large code files into context.",
|
|
19
|
-
"Use readSeek_read for images; it returns the image attachment plus OCR
|
|
19
|
+
"Use readSeek_read for images; it returns the image attachment plus OCR text, a caption, and detected objects, so you don't need separate OCR tools.",
|
|
20
20
|
],
|
|
21
21
|
"edit.md": [
|
|
22
22
|
"Use readSeek_edit with fresh LINE:HASH anchors for existing files.",
|