pi-readseek 0.4.29 → 0.5.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.
- package/README.md +38 -44
- package/index.ts +45 -7
- package/package.json +2 -2
- package/prompts/def.md +2 -9
- package/prompts/edit.md +13 -13
- package/prompts/grep.md +3 -3
- package/prompts/hover.md +2 -6
- package/prompts/read.md +3 -3
- package/prompts/refs.md +1 -1
- package/prompts/rename.md +3 -7
- package/prompts/sg.md +1 -1
- package/prompts/write.md +5 -5
- package/src/def.ts +12 -19
- package/src/edit-classify.ts +0 -127
- package/src/edit-output.ts +5 -11
- package/src/edit-syntax-validate.ts +4 -3
- package/src/edit.ts +21 -42
- package/src/file-map.ts +2 -2
- package/src/grep-budget.ts +7 -51
- package/src/grep-output.ts +4 -4
- package/src/grep.ts +19 -26
- package/src/hover.ts +4 -8
- package/src/read-output.ts +4 -4
- package/src/read.ts +28 -37
- package/src/readseek-client.ts +171 -145
- package/src/readseek-params.ts +1 -1
- package/src/readseek-settings.ts +138 -55
- package/src/readseek-value.ts +4 -6
- package/src/refs-output.ts +3 -3
- package/src/refs.ts +6 -10
- package/src/register-tool.ts +4 -42
- package/src/rename.ts +6 -10
- package/src/replace-symbol.ts +2 -2
- package/src/sg-output.ts +3 -3
- package/src/sg.ts +21 -25
- package/src/syntax-validate-mode.ts +3 -13
- package/src/tool-prompt-metadata.ts +12 -12
- package/src/tui-render-utils.ts +2 -2
- package/src/write.ts +50 -80
package/src/read.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { buildReadOutput } from "./read-output.js";
|
|
|
26
26
|
|
|
27
27
|
import { buildLocalBundle } from "./read-local-bundle.js";
|
|
28
28
|
import { coerceObviousBase10Int } from "./coerce-obvious-int.js";
|
|
29
|
-
import {
|
|
29
|
+
import { readSeekRead, readSeekDetect, readSeekImage, type ReadSeekDetection } from "./readseek-client.js";
|
|
30
30
|
import { formatReadCallText, formatReadResultText } from "./read-render-helpers.js";
|
|
31
31
|
import { resolveReadSeekOcrMode } from "./readseek-settings.js";
|
|
32
32
|
import { clampLineToWidth, clampLinesToWidth, linkToolPath, renderPendingResult, renderToolLabel, resolveRenderResultContext, summaryLine, wrapReadHashlinesForWidthCached } from "./tui-render-utils.js";
|
|
@@ -65,17 +65,17 @@ export interface ExecuteReadOptions {
|
|
|
65
65
|
function hasReadAnchors(result: AgentToolResult<any>): boolean {
|
|
66
66
|
const details = (result as { details?: unknown }).details;
|
|
67
67
|
if (!details || typeof details !== "object") return false;
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
70
|
-
const lines = (
|
|
68
|
+
const readSeekValue = (details as { readSeekValue?: unknown }).readSeekValue;
|
|
69
|
+
if (!readSeekValue || typeof readSeekValue !== "object") return false;
|
|
70
|
+
const lines = (readSeekValue as { lines?: unknown }).lines;
|
|
71
71
|
return Array.isArray(lines) && lines.length > 0;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function formatImageAnalysis(detection: ReadSeekDetection): string | undefined {
|
|
75
75
|
if (detection.kind !== "image") return undefined;
|
|
76
76
|
const sections: string[] = [];
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
77
|
+
const ocr = detection.ocr?.trim();
|
|
78
|
+
if (ocr) sections.push(`OCR text from image:\n${ocr}`);
|
|
79
79
|
const caption = detection.caption?.trim();
|
|
80
80
|
if (caption) sections.push(`Image caption:\n${caption}`);
|
|
81
81
|
if (detection.objects?.length) {
|
|
@@ -171,24 +171,19 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
171
171
|
if (hasBinaryContent) {
|
|
172
172
|
let detection: ReadSeekDetection | undefined;
|
|
173
173
|
try {
|
|
174
|
-
detection = await
|
|
174
|
+
detection = await readSeekDetect(absolutePath, { signal });
|
|
175
175
|
} catch {
|
|
176
176
|
}
|
|
177
177
|
if (detection?.kind === "image") {
|
|
178
178
|
const builtinRead = createReadTool(cwd);
|
|
179
179
|
const builtinResult = await builtinRead.execute(toolCallId, p, signal, onUpdate);
|
|
180
180
|
const ocrMode = resolveReadSeekOcrMode();
|
|
181
|
-
const
|
|
182
|
-
if (!
|
|
181
|
+
const shouldRunVision = ocrMode === "force" || (ocrMode === "auto" && !opts.modelSupportsImages);
|
|
182
|
+
if (!shouldRunVision) return succeed(builtinResult);
|
|
183
183
|
|
|
184
184
|
let ocrFailed = false;
|
|
185
185
|
try {
|
|
186
|
-
const ocrDetection = await
|
|
187
|
-
transcribe: true,
|
|
188
|
-
caption: true,
|
|
189
|
-
objects: true,
|
|
190
|
-
signal,
|
|
191
|
-
});
|
|
186
|
+
const ocrDetection = await readSeekImage(absolutePath, ["ocr", "caption", "objects"], { signal });
|
|
192
187
|
const imageAnalysis = formatImageAnalysis(ocrDetection);
|
|
193
188
|
if (imageAnalysis) {
|
|
194
189
|
return succeed({
|
|
@@ -356,33 +351,33 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
356
351
|
}
|
|
357
352
|
|
|
358
353
|
throwIfAborted(signal);
|
|
359
|
-
let
|
|
354
|
+
let readSeekOutput: Awaited<ReturnType<typeof readSeekRead>>;
|
|
360
355
|
try {
|
|
361
|
-
|
|
362
|
-
? await
|
|
363
|
-
: await
|
|
356
|
+
readSeekOutput = total === 0
|
|
357
|
+
? await readSeekRead(absolutePath, undefined, undefined, { signal })
|
|
358
|
+
: await readSeekRead(absolutePath, startLine, endIdx, { signal });
|
|
364
359
|
} catch (err: any) {
|
|
365
360
|
const detail = err?.message ? ` — ${err.message}` : "";
|
|
366
361
|
const message = `readseek failed while reading ${rawPath}${detail}`;
|
|
367
362
|
return buildToolErrorResult("read", "readseek-error", message, { path: rawParams.path, hint: "Ensure @jarkkojs/readseek and its npm platform package are installed.", details: { message: err?.message } });
|
|
368
363
|
}
|
|
369
364
|
const expectedLineCount = Math.max(0, endIdx - startLine + 1);
|
|
370
|
-
const invalidLine =
|
|
371
|
-
if (
|
|
365
|
+
const invalidLine = readSeekOutput.hashlines.find((line, index) => line.line !== startLine + index);
|
|
366
|
+
if (readSeekOutput.hashlines.length !== expectedLineCount || invalidLine) {
|
|
372
367
|
const message = invalidLine
|
|
373
368
|
? `readseek returned non-sequential line ${invalidLine.line} for requested range ${startLine}-${endIdx}`
|
|
374
|
-
: `readseek returned ${
|
|
369
|
+
: `readseek returned ${readSeekOutput.hashlines.length} lines for requested range ${startLine}-${endIdx} (${expectedLineCount} expected)`;
|
|
375
370
|
return buildToolErrorResult("read", "readseek-output-mismatch", message, { path: rawParams.path });
|
|
376
371
|
}
|
|
377
|
-
const
|
|
372
|
+
const readSeekLines: ReadSeekLine[] = readSeekOutput.hashlines.map((line) => ({
|
|
378
373
|
line: line.line,
|
|
379
374
|
hash: line.hash,
|
|
380
375
|
anchor: `${line.line}:${line.hash}`,
|
|
381
376
|
raw: line.text,
|
|
382
377
|
display: escapeControlCharsForDisplay(line.text),
|
|
383
378
|
}));
|
|
384
|
-
const selected =
|
|
385
|
-
const formatted = renderReadSeekLines(
|
|
379
|
+
const selected = readSeekLines.map((line) => line.raw);
|
|
380
|
+
const formatted = renderReadSeekLines(readSeekLines);
|
|
386
381
|
|
|
387
382
|
const truncation = truncateHead(formatted, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });
|
|
388
383
|
|
|
@@ -423,7 +418,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
423
418
|
endLine: endIdx,
|
|
424
419
|
totalLines: total,
|
|
425
420
|
selectedLines: selected,
|
|
426
|
-
lines:
|
|
421
|
+
lines: readSeekLines,
|
|
427
422
|
warnings: structuredWarnings,
|
|
428
423
|
truncation: truncation.truncated
|
|
429
424
|
? {
|
|
@@ -456,7 +451,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
456
451
|
content: [{ type: "text", text: readOutput.text }],
|
|
457
452
|
details: {
|
|
458
453
|
truncation: truncation.truncated ? truncation : undefined,
|
|
459
|
-
|
|
454
|
+
readSeekValue: readOutput.readSeekValue,
|
|
460
455
|
},
|
|
461
456
|
});
|
|
462
457
|
}
|
|
@@ -469,11 +464,7 @@ function splitReadSeekLines(text: string): string[] {
|
|
|
469
464
|
|
|
470
465
|
export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}) {
|
|
471
466
|
const tool = registerReadSeekTool(pi, {
|
|
472
|
-
|
|
473
|
-
pythonName: "read",
|
|
474
|
-
defaultExposure: "safe-by-default",
|
|
475
|
-
}, {
|
|
476
|
-
name: "read",
|
|
467
|
+
name: "readSeek_read",
|
|
477
468
|
label: "Read",
|
|
478
469
|
description: READ_PROMPT_METADATA.description,
|
|
479
470
|
promptSnippet: READ_PROMPT_METADATA.promptSnippet,
|
|
@@ -529,16 +520,16 @@ export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}
|
|
|
529
520
|
return new Text(clampLinesToWidth([summaryLine(errorText)], width).join("\n"), 0, 0);
|
|
530
521
|
}
|
|
531
522
|
|
|
532
|
-
const
|
|
533
|
-
if (!
|
|
523
|
+
const readSeekValue = (result.details as any)?.readSeekValue as { range: { startLine: number; endLine: number; totalLines: number }; truncation: any; symbol: any; map: any; warnings: ReadSeekWarning[] } | undefined;
|
|
524
|
+
if (!readSeekValue) {
|
|
534
525
|
const lines = textContent.split("\n").filter(Boolean).length || textContent.split("\n").length;
|
|
535
526
|
return new Text(summaryLine(`loaded ${lines} ${lines === 1 ? "line" : "lines"}`, { hidden: !!textContent && !expanded }), 0, 0);
|
|
536
527
|
}
|
|
537
528
|
|
|
538
|
-
const info = formatReadResultText({ range:
|
|
539
|
-
const visibleLines = info.truncated &&
|
|
529
|
+
const info = formatReadResultText({ range: readSeekValue.range, truncation: readSeekValue.truncation, symbol: readSeekValue.symbol, map: readSeekValue.map, warnings: readSeekValue.warnings });
|
|
530
|
+
const visibleLines = info.truncated && readSeekValue.truncation ? readSeekValue.truncation.outputLines : readSeekValue.range.endLine - readSeekValue.range.startLine + 1;
|
|
540
531
|
const loadedWord = visibleLines === 1 ? "line" : "lines";
|
|
541
|
-
const summaryParts: string[] = [info.truncated ? `loaded ${visibleLines} of ${
|
|
532
|
+
const summaryParts: string[] = [info.truncated ? `loaded ${visibleLines} of ${readSeekValue.truncation?.totalLines ?? readSeekValue.range.totalLines} ${loadedWord} (truncated)` : `loaded ${visibleLines} ${loadedWord}`];
|
|
542
533
|
if (info.symbolBadge) summaryParts.push(info.symbolBadge);
|
|
543
534
|
for (const badge of info.badges) summaryParts.push(badge);
|
|
544
535
|
const summary = summaryParts.join(" • ");
|