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/readseek-client.ts
CHANGED
|
@@ -7,6 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { DetailLevel } from "./readseek/enums.js";
|
|
8
8
|
import type { FileMap, FileSymbol } from "./readseek/types.js";
|
|
9
9
|
import { SymbolKind } from "./readseek/enums.js";
|
|
10
|
+
import { resolveReadSeekTimeoutMs } from "./readseek-settings.js";
|
|
10
11
|
|
|
11
12
|
export interface ReadSeekHashline {
|
|
12
13
|
line: number;
|
|
@@ -108,21 +109,15 @@ export interface ReadSeekCheckOutput {
|
|
|
108
109
|
diagnostics: ReadSeekDiagnostic[];
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
export
|
|
112
|
-
text: string;
|
|
113
|
-
quad: [number, number, number, number, number, number, number, number];
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export interface ReadSeekTranscript {
|
|
117
|
-
text: string;
|
|
118
|
-
regions: ReadSeekTranscriptRegion[];
|
|
119
|
-
}
|
|
112
|
+
export type ReadSeekOcrText = string;
|
|
120
113
|
|
|
121
114
|
export interface ReadSeekDetectedObject {
|
|
122
115
|
label: string;
|
|
123
116
|
bbox: [number, number, number, number];
|
|
124
117
|
}
|
|
125
118
|
|
|
119
|
+
export type ReadSeekImageMode = "ocr" | "caption" | "objects";
|
|
120
|
+
|
|
126
121
|
export type ReadSeekDetection =
|
|
127
122
|
| {
|
|
128
123
|
kind: "source";
|
|
@@ -143,7 +138,7 @@ export type ReadSeekDetection =
|
|
|
143
138
|
width: number;
|
|
144
139
|
height: number;
|
|
145
140
|
animated: boolean;
|
|
146
|
-
|
|
141
|
+
ocr?: ReadSeekOcrText;
|
|
147
142
|
caption?: string;
|
|
148
143
|
objects?: ReadSeekDetectedObject[];
|
|
149
144
|
}
|
|
@@ -154,6 +149,8 @@ export type ReadSeekDetection =
|
|
|
154
149
|
mime?: string;
|
|
155
150
|
};
|
|
156
151
|
|
|
152
|
+
type ReadSeekImageDetection = Extract<ReadSeekDetection, { kind: "image" }>;
|
|
153
|
+
|
|
157
154
|
interface ReadSeekSearchOptions {
|
|
158
155
|
language?: string;
|
|
159
156
|
cached?: boolean;
|
|
@@ -162,13 +159,6 @@ interface ReadSeekSearchOptions {
|
|
|
162
159
|
signal?: AbortSignal;
|
|
163
160
|
}
|
|
164
161
|
|
|
165
|
-
interface ReadSeekDetectOptions {
|
|
166
|
-
transcribe?: boolean;
|
|
167
|
-
caption?: boolean;
|
|
168
|
-
objects?: boolean;
|
|
169
|
-
signal?: AbortSignal;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
162
|
function normalizeLanguage(language: string): string {
|
|
173
163
|
return language === "java" ? "Java" : language;
|
|
174
164
|
}
|
|
@@ -223,36 +213,43 @@ const require = createRequire(import.meta.url);
|
|
|
223
213
|
const READSEEK_REPO_PACKAGE_NAMES = new Set(["@jarkkojs/readseek", "readseek"]);
|
|
224
214
|
let defaultReadSeekDirInit: Promise<string | null> | undefined;
|
|
225
215
|
|
|
226
|
-
function
|
|
216
|
+
function readSeekPackageDir(): string {
|
|
227
217
|
return path.dirname(require.resolve("@jarkkojs/readseek/package.json"));
|
|
228
218
|
}
|
|
229
219
|
|
|
230
|
-
|
|
231
|
-
|
|
220
|
+
const READSEEK_PLATFORM_PACKAGES: Record<string, string> = {
|
|
221
|
+
"darwin-arm64": "@jarkkojs/readseek-darwin-arm64",
|
|
222
|
+
"linux-x64": "@jarkkojs/readseek-linux-x64",
|
|
223
|
+
"win32-x64": "@jarkkojs/readseek-win32-x64",
|
|
224
|
+
};
|
|
232
225
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
return "@jarkkojs/readseek-darwin-arm64";
|
|
237
|
-
case "linux":
|
|
238
|
-
return "@jarkkojs/readseek-linux-x64";
|
|
239
|
-
case "win32":
|
|
240
|
-
return "@jarkkojs/readseek-win32-x64";
|
|
241
|
-
default:
|
|
242
|
-
throw new Error(`unsupported readseek platform: ${process.platform}`);
|
|
243
|
-
}
|
|
244
|
-
})();
|
|
226
|
+
function readSeekPlatform(): string {
|
|
227
|
+
return `${process.platform}-${process.arch}`;
|
|
228
|
+
}
|
|
245
229
|
|
|
246
|
-
|
|
230
|
+
function readSeekBinaryPath(): string {
|
|
231
|
+
const platform = readSeekPlatform();
|
|
232
|
+
const platformPackage = READSEEK_PLATFORM_PACKAGES[platform];
|
|
233
|
+
if (!platformPackage) {
|
|
234
|
+
const supported = Object.keys(READSEEK_PLATFORM_PACKAGES).join(", ");
|
|
235
|
+
throw new Error(`@jarkkojs/readseek ships no binary for ${platform}; it supports ${supported}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const packageJson = require.resolve(`${platformPackage}/package.json`, { paths: [readSeekPackageDir()] });
|
|
247
239
|
return path.join(path.dirname(packageJson), "bin", process.platform === "win32" ? "readseek.exe" : "readseek");
|
|
248
240
|
}
|
|
249
241
|
|
|
250
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Report whether a readseek binary can be resolved for the running platform,
|
|
244
|
+
* along with the reason when it cannot. Used to keep the readseek tools out of
|
|
245
|
+
* the active set on hosts that readseek publishes no binary for.
|
|
246
|
+
*/
|
|
247
|
+
export function readSeekBinaryAvailability(): { available: true } | { available: false; reason: string } {
|
|
251
248
|
try {
|
|
252
|
-
|
|
253
|
-
return true;
|
|
254
|
-
} catch {
|
|
255
|
-
return false;
|
|
249
|
+
readSeekBinaryPath();
|
|
250
|
+
return { available: true };
|
|
251
|
+
} catch (err) {
|
|
252
|
+
return { available: false, reason: classifyReadSeekFailure(err).message };
|
|
256
253
|
}
|
|
257
254
|
}
|
|
258
255
|
|
|
@@ -325,13 +322,18 @@ function defaultReadSeekDir(): string | null {
|
|
|
325
322
|
|
|
326
323
|
const DEFAULT_READSEEK_TIMEOUT_MS = 120_000;
|
|
327
324
|
|
|
328
|
-
function
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
325
|
+
function readSeekTimeoutMs(): number {
|
|
326
|
+
return resolveReadSeekTimeoutMs() ?? DEFAULT_READSEEK_TIMEOUT_MS;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const READSEEK_USAGE_HINT = /\n\s*Run readseek(?: [\w-]+)* --help for more information\.?\s*$/;
|
|
330
|
+
|
|
331
|
+
function readSeekErrorMessage(stderr: string): string {
|
|
332
|
+
return stderr
|
|
333
|
+
.replace(READSEEK_USAGE_HINT, "")
|
|
334
|
+
.replace(/^error:\s*/i, "")
|
|
335
|
+
.replace(/\s*\n\s*/g, " ")
|
|
336
|
+
.trim();
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
async function spawnReadSeekRaw(args: string[], options: RunReadSeekOptions = {}): Promise<string> {
|
|
@@ -353,8 +355,8 @@ async function spawnReadSeekRaw(args: string[], options: RunReadSeekOptions = {}
|
|
|
353
355
|
|
|
354
356
|
const stdin = options.stdin;
|
|
355
357
|
const stdio: StdioOptions = [stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"];
|
|
356
|
-
const child = spawn(
|
|
357
|
-
const timeoutMs = options.timeoutMs ??
|
|
358
|
+
const child = spawn(readSeekBinaryPath(), args, { stdio, signal: options.signal });
|
|
359
|
+
const timeoutMs = options.timeoutMs ?? readSeekTimeoutMs();
|
|
358
360
|
timeout = setTimeout(() => {
|
|
359
361
|
child.kill("SIGKILL");
|
|
360
362
|
fail(new Error(`readseek timed out after ${timeoutMs} ms`));
|
|
@@ -399,8 +401,8 @@ async function spawnReadSeekRaw(args: string[], options: RunReadSeekOptions = {}
|
|
|
399
401
|
const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
|
|
400
402
|
const stderr = Buffer.concat(stderrChunks).toString("utf-8").trim();
|
|
401
403
|
if (code === 0) succeed(stdout);
|
|
402
|
-
else if (signal) fail(new Error((stderr || `readseek killed by signal ${signal}`)
|
|
403
|
-
else fail(new Error((stderr || `readseek exited with status ${code}`)
|
|
404
|
+
else if (signal) fail(new Error(readSeekErrorMessage(stderr) || `readseek killed by signal ${signal}`));
|
|
405
|
+
else fail(new Error(readSeekErrorMessage(stderr) || `readseek exited with status ${code}`));
|
|
404
406
|
});
|
|
405
407
|
});
|
|
406
408
|
}
|
|
@@ -419,11 +421,11 @@ async function ensureDefaultReadSeekDir(): Promise<string | null> {
|
|
|
419
421
|
return defaultReadSeekDirInit;
|
|
420
422
|
}
|
|
421
423
|
|
|
422
|
-
async function
|
|
424
|
+
async function readSeekInvocationArgs(args: string[]): Promise<string[]> {
|
|
423
425
|
if (isOwnReadSeekRepository()) return args;
|
|
424
426
|
|
|
425
|
-
const
|
|
426
|
-
return
|
|
427
|
+
const readSeekDir = await ensureDefaultReadSeekDir();
|
|
428
|
+
return readSeekDir ? ["--readseek-dir", readSeekDir, ...args] : args;
|
|
427
429
|
}
|
|
428
430
|
|
|
429
431
|
interface RunReadSeekOptions {
|
|
@@ -433,7 +435,7 @@ interface RunReadSeekOptions {
|
|
|
433
435
|
}
|
|
434
436
|
|
|
435
437
|
async function runReadSeekRaw(args: string[], options: RunReadSeekOptions = {}): Promise<string> {
|
|
436
|
-
return spawnReadSeekRaw(await
|
|
438
|
+
return spawnReadSeekRaw(await readSeekInvocationArgs(args), options);
|
|
437
439
|
}
|
|
438
440
|
|
|
439
441
|
async function runReadSeek(args: string[], options: RunReadSeekOptions = {}): Promise<unknown> {
|
|
@@ -556,11 +558,15 @@ function parseSearchOutput(value: unknown): ReadSeekSearchOutput {
|
|
|
556
558
|
};
|
|
557
559
|
}
|
|
558
560
|
|
|
559
|
-
export async function
|
|
560
|
-
|
|
561
|
-
|
|
561
|
+
export async function readSeekRead(
|
|
562
|
+
filePath: string,
|
|
563
|
+
startLine?: number,
|
|
564
|
+
endLine?: number,
|
|
565
|
+
options: { signal?: AbortSignal } = {},
|
|
566
|
+
): Promise<ReadSeekReadOutput> {
|
|
567
|
+
const args = ["read", startLine === undefined ? filePath : `${filePath}:${startLine}`];
|
|
562
568
|
if (endLine !== undefined) args.push("--end", String(endLine));
|
|
563
|
-
return parseReadOutput(await runReadSeek(args));
|
|
569
|
+
return parseReadOutput(await runReadSeek(args, { signal: options.signal }));
|
|
564
570
|
}
|
|
565
571
|
|
|
566
572
|
function fileMapFromReadSeekOutput(output: ReadSeekMapOutput, filePath: string, totalBytes: number): FileMap | null {
|
|
@@ -575,7 +581,7 @@ function fileMapFromReadSeekOutput(output: ReadSeekMapOutput, filePath: string,
|
|
|
575
581
|
};
|
|
576
582
|
}
|
|
577
583
|
|
|
578
|
-
export async function
|
|
584
|
+
export async function readSeekMap(
|
|
579
585
|
filePath: string,
|
|
580
586
|
totalBytes: number,
|
|
581
587
|
options: { signal?: AbortSignal } = {},
|
|
@@ -584,7 +590,7 @@ export async function readseekMap(
|
|
|
584
590
|
return fileMapFromReadSeekOutput(output, filePath, totalBytes);
|
|
585
591
|
}
|
|
586
592
|
|
|
587
|
-
export async function
|
|
593
|
+
export async function readSeekSearch(
|
|
588
594
|
target: string,
|
|
589
595
|
pattern: string,
|
|
590
596
|
options: ReadSeekSearchOptions = {},
|
|
@@ -597,13 +603,13 @@ export async function readseekSearch(
|
|
|
597
603
|
return parseSearchOutput(await runReadSeek(args, { signal: options.signal })).results;
|
|
598
604
|
}
|
|
599
605
|
|
|
600
|
-
export async function
|
|
606
|
+
export async function readSeekMapContent(
|
|
601
607
|
filePath: string,
|
|
602
608
|
content: string,
|
|
603
609
|
options: { signal?: AbortSignal } = {},
|
|
604
610
|
): Promise<FileMap | null> {
|
|
605
611
|
const output = parseMapOutput(
|
|
606
|
-
await runReadSeek(["map",
|
|
612
|
+
await runReadSeek(["map", `stdin:${filePath}`], { signal: options.signal, stdin: content }),
|
|
607
613
|
);
|
|
608
614
|
return fileMapFromReadSeekOutput(output, filePath, Buffer.byteLength(content, "utf8"));
|
|
609
615
|
}
|
|
@@ -638,7 +644,7 @@ function parseRefsOutput(value: unknown): ReadSeekRefsOutput {
|
|
|
638
644
|
};
|
|
639
645
|
}
|
|
640
646
|
|
|
641
|
-
export async function
|
|
647
|
+
export async function readSeekRefs(
|
|
642
648
|
target: string,
|
|
643
649
|
name: string,
|
|
644
650
|
options: ReadSeekRefsOptions = {},
|
|
@@ -678,34 +684,18 @@ function parseCheckOutput(value: unknown): ReadSeekCheckOutput {
|
|
|
678
684
|
};
|
|
679
685
|
}
|
|
680
686
|
|
|
681
|
-
export async function
|
|
687
|
+
export async function readSeekCheck(
|
|
682
688
|
filePath: string,
|
|
683
689
|
content: string,
|
|
684
690
|
options: { signal?: AbortSignal } = {},
|
|
685
691
|
): Promise<ReadSeekCheckOutput> {
|
|
686
692
|
return parseCheckOutput(
|
|
687
|
-
await runReadSeek(["check",
|
|
693
|
+
await runReadSeek(["check", `stdin:${filePath}`], { signal: options.signal, stdin: content }),
|
|
688
694
|
);
|
|
689
695
|
}
|
|
690
696
|
|
|
691
|
-
function
|
|
692
|
-
|
|
693
|
-
if (typeof value !== "object") throw new Error("invalid readseek detect transcribe");
|
|
694
|
-
const transcribe = value as Record<string, unknown>;
|
|
695
|
-
if (!Array.isArray(transcribe.regions)) throw new Error("invalid readseek detect transcribe.regions");
|
|
696
|
-
return {
|
|
697
|
-
text: requireString(transcribe.text, "transcribe.text"),
|
|
698
|
-
regions: transcribe.regions.map((region) => {
|
|
699
|
-
if (!region || typeof region !== "object") throw new Error("invalid readseek detect transcribe region");
|
|
700
|
-
const item = region as Record<string, unknown>;
|
|
701
|
-
const quad = item.quad;
|
|
702
|
-
if (!Array.isArray(quad) || quad.length !== 8) throw new Error("invalid readseek detect transcribe quad");
|
|
703
|
-
return {
|
|
704
|
-
text: requireString(item.text, "transcribe.region.text"),
|
|
705
|
-
quad: quad.map((n, i) => requireNumber(n, `transcribe.region.quad[${i}]`)) as ReadSeekTranscriptRegion["quad"],
|
|
706
|
-
};
|
|
707
|
-
}),
|
|
708
|
-
};
|
|
697
|
+
function parseOcrText(value: unknown): ReadSeekOcrText | undefined {
|
|
698
|
+
return optionalString(value, "ocr");
|
|
709
699
|
}
|
|
710
700
|
|
|
711
701
|
function parseDetectedObjects(value: unknown): ReadSeekDetectedObject[] | undefined {
|
|
@@ -745,7 +735,7 @@ function parseDetectOutput(value: unknown): ReadSeekDetection {
|
|
|
745
735
|
width: requireNumber(output.width, "width"),
|
|
746
736
|
height: requireNumber(output.height, "height"),
|
|
747
737
|
animated: requireBoolean(output.animated, "animated"),
|
|
748
|
-
|
|
738
|
+
ocr: parseOcrText(output.ocr),
|
|
749
739
|
caption: optionalString(output.caption, "caption"),
|
|
750
740
|
objects: parseDetectedObjects(output.objects),
|
|
751
741
|
};
|
|
@@ -765,16 +755,48 @@ function parseDetectOutput(value: unknown): ReadSeekDetection {
|
|
|
765
755
|
return { kind: "text", type, file, mime };
|
|
766
756
|
}
|
|
767
757
|
|
|
768
|
-
export async function
|
|
758
|
+
export async function readSeekDetect(
|
|
759
|
+
filePath: string,
|
|
760
|
+
options: { signal?: AbortSignal } = {},
|
|
761
|
+
): Promise<ReadSeekDetection> {
|
|
762
|
+
return parseDetectOutput(await runReadSeek(["detect", filePath], { signal: options.signal }));
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Analyze an image with each requested vision mode and merge the payloads into
|
|
767
|
+
* a single detection. readseek accepts one `--image` mode per invocation, so
|
|
768
|
+
* modes that fail are dropped as long as at least one produced a payload;
|
|
769
|
+
* otherwise the first failure is rethrown.
|
|
770
|
+
*/
|
|
771
|
+
export async function readSeekImage(
|
|
769
772
|
filePath: string,
|
|
770
|
-
|
|
773
|
+
modes: ReadSeekImageMode[],
|
|
774
|
+
options: { signal?: AbortSignal } = {},
|
|
771
775
|
): Promise<ReadSeekDetection> {
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
776
|
+
const results = await Promise.allSettled(
|
|
777
|
+
modes.map(async (mode) =>
|
|
778
|
+
parseDetectOutput(await runReadSeek(["read", "--image", mode, filePath], { signal: options.signal })),
|
|
779
|
+
),
|
|
780
|
+
);
|
|
781
|
+
|
|
782
|
+
let merged: ReadSeekImageDetection | undefined;
|
|
783
|
+
for (const result of results) {
|
|
784
|
+
if (result.status !== "fulfilled" || result.value.kind !== "image") continue;
|
|
785
|
+
const detection = result.value;
|
|
786
|
+
merged = merged === undefined
|
|
787
|
+
? detection
|
|
788
|
+
: {
|
|
789
|
+
...merged,
|
|
790
|
+
ocr: detection.ocr ?? merged.ocr,
|
|
791
|
+
caption: detection.caption ?? merged.caption,
|
|
792
|
+
objects: detection.objects ?? merged.objects,
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
if (merged !== undefined) return merged;
|
|
796
|
+
|
|
797
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
798
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
799
|
+
throw new Error(`readseek returned no image analysis for ${filePath}`);
|
|
778
800
|
}
|
|
779
801
|
|
|
780
802
|
// --- Rename ---
|
|
@@ -831,9 +853,44 @@ interface RenameOptions {
|
|
|
831
853
|
signal?: AbortSignal;
|
|
832
854
|
}
|
|
833
855
|
|
|
856
|
+
function parseRenameConflicts(value: unknown, field: string): RenameConflict[] {
|
|
857
|
+
if (value === undefined) return [];
|
|
858
|
+
if (!Array.isArray(value)) throw new Error(`invalid readseek ${field}`);
|
|
859
|
+
return value.map((item) => {
|
|
860
|
+
if (!item || typeof item !== "object") throw new Error(`invalid readseek ${field} entry`);
|
|
861
|
+
const c = item as Record<string, unknown>;
|
|
862
|
+
return {
|
|
863
|
+
line: requireNumber(c.line, `${field}.line`),
|
|
864
|
+
column: requireNumber(c.column, `${field}.column`),
|
|
865
|
+
reason: requireString(c.reason, `${field}.reason`),
|
|
866
|
+
};
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function parseRenameEdits(value: unknown, field: string): RenameEdit[] {
|
|
871
|
+
if (value === undefined) return [];
|
|
872
|
+
if (!Array.isArray(value)) throw new Error(`invalid readseek ${field}`);
|
|
873
|
+
return value.map((item) => {
|
|
874
|
+
if (!item || typeof item !== "object") throw new Error(`invalid readseek ${field} entry`);
|
|
875
|
+
const e = item as Record<string, unknown>;
|
|
876
|
+
return {
|
|
877
|
+
line: requireNumber(e.line, `${field}.line`),
|
|
878
|
+
start_column: requireNumber(e.start_column, `${field}.start_column`),
|
|
879
|
+
end_column: requireNumber(e.end_column, `${field}.end_column`),
|
|
880
|
+
start_byte: requireNumber(e.start_byte, `${field}.start_byte`),
|
|
881
|
+
end_byte: requireNumber(e.end_byte, `${field}.end_byte`),
|
|
882
|
+
occurrence: requireString(e.occurrence, `${field}.occurrence`),
|
|
883
|
+
line_hash: requireString(e.line_hash, `${field}.line_hash`),
|
|
884
|
+
text: requireString(e.text, `${field}.text`),
|
|
885
|
+
};
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
|
|
834
889
|
function parseRenameOutput(value: unknown): RenameOutput {
|
|
835
890
|
if (!value || typeof value !== "object") throw new Error("invalid readseek rename output");
|
|
836
891
|
const output = value as Record<string, unknown>;
|
|
892
|
+
const others = output.others;
|
|
893
|
+
if (others !== undefined && !Array.isArray(others)) throw new Error("invalid readseek others");
|
|
837
894
|
return {
|
|
838
895
|
file: requireString(output.file, "file"),
|
|
839
896
|
language: requireString(output.language, "language"),
|
|
@@ -842,46 +899,24 @@ function parseRenameOutput(value: unknown): RenameOutput {
|
|
|
842
899
|
old_name: requireString(output.old_name, "old_name"),
|
|
843
900
|
new_name: requireString(output.new_name, "new_name"),
|
|
844
901
|
applied: requireBoolean(output.applied, "applied"),
|
|
845
|
-
conflicts: (output.conflicts
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
})) ?? [],
|
|
860
|
-
others: (output.others as any[] | undefined)?.map((o: Record<string, unknown>) => ({
|
|
861
|
-
file: requireString(o.file, "other.file"),
|
|
862
|
-
language: requireString(o.language, "other.language"),
|
|
863
|
-
engine: optionalString(o.engine, "other.engine"),
|
|
864
|
-
file_hash: requireString(o.file_hash, "other.file_hash"),
|
|
865
|
-
conflicts: (o.conflicts as any[] | undefined)?.map((c: Record<string, unknown>) => ({
|
|
866
|
-
line: requireNumber(c.line, "conflict.line"),
|
|
867
|
-
column: requireNumber(c.column, "conflict.column"),
|
|
868
|
-
reason: requireString(c.reason, "conflict.reason"),
|
|
869
|
-
})) ?? [],
|
|
870
|
-
edits: (o.edits as any[] | undefined)?.map((e: Record<string, unknown>) => ({
|
|
871
|
-
line: requireNumber(e.line, "edit.line"),
|
|
872
|
-
start_column: requireNumber(e.start_column, "edit.start_column"),
|
|
873
|
-
end_column: requireNumber(e.end_column, "edit.end_column"),
|
|
874
|
-
start_byte: requireNumber(e.start_byte, "edit.start_byte"),
|
|
875
|
-
end_byte: requireNumber(e.end_byte, "edit.end_byte"),
|
|
876
|
-
occurrence: requireString(e.occurrence, "edit.occurrence"),
|
|
877
|
-
line_hash: requireString(e.line_hash, "edit.line_hash"),
|
|
878
|
-
text: requireString(e.text, "edit.text"),
|
|
879
|
-
})) ?? [],
|
|
880
|
-
})) ?? [],
|
|
902
|
+
conflicts: parseRenameConflicts(output.conflicts, "conflicts"),
|
|
903
|
+
edits: parseRenameEdits(output.edits, "edits"),
|
|
904
|
+
others: (others as unknown[] | undefined)?.map((entry) => {
|
|
905
|
+
if (!entry || typeof entry !== "object") throw new Error("invalid readseek other");
|
|
906
|
+
const o = entry as Record<string, unknown>;
|
|
907
|
+
return {
|
|
908
|
+
file: requireString(o.file, "other.file"),
|
|
909
|
+
language: requireString(o.language, "other.language"),
|
|
910
|
+
engine: optionalString(o.engine, "other.engine"),
|
|
911
|
+
file_hash: requireString(o.file_hash, "other.file_hash"),
|
|
912
|
+
conflicts: parseRenameConflicts(o.conflicts, "other.conflicts"),
|
|
913
|
+
edits: parseRenameEdits(o.edits, "other.edits"),
|
|
914
|
+
};
|
|
915
|
+
}) ?? [],
|
|
881
916
|
};
|
|
882
917
|
}
|
|
883
918
|
|
|
884
|
-
export async function
|
|
919
|
+
export async function readSeekRename(
|
|
885
920
|
filePath: string,
|
|
886
921
|
options: RenameOptions,
|
|
887
922
|
): Promise<RenameOutput> {
|
|
@@ -968,13 +1003,13 @@ function parseIdentifyOutput(value: unknown): IdentifyOutput {
|
|
|
968
1003
|
};
|
|
969
1004
|
}
|
|
970
1005
|
|
|
971
|
-
export async function
|
|
1006
|
+
export async function readSeekIdentify(
|
|
972
1007
|
filePath: string,
|
|
973
1008
|
content: string,
|
|
974
1009
|
options: IdentifyOptions = {},
|
|
975
1010
|
): Promise<IdentifyOutput> {
|
|
976
|
-
const
|
|
977
|
-
|
|
1011
|
+
const target = options.line === undefined ? `stdin:${filePath}` : `stdin:${filePath}:${options.line}`;
|
|
1012
|
+
const args = ["identify", target];
|
|
978
1013
|
if (options.column !== undefined) args.push("--column", String(options.column));
|
|
979
1014
|
if (options.language) args.push("--language", options.language);
|
|
980
1015
|
return parseIdentifyOutput(await runReadSeek(args, { signal: options.signal, stdin: content }));
|
|
@@ -994,9 +1029,7 @@ export interface DefLocation {
|
|
|
994
1029
|
}
|
|
995
1030
|
|
|
996
1031
|
interface DefOptions {
|
|
997
|
-
name
|
|
998
|
-
fromIdentify?: boolean;
|
|
999
|
-
identifyInput?: string;
|
|
1032
|
+
name: string;
|
|
1000
1033
|
language?: string;
|
|
1001
1034
|
cached?: boolean;
|
|
1002
1035
|
others?: boolean;
|
|
@@ -1025,21 +1058,14 @@ function parseDefCompact(value: unknown): DefLocation[] {
|
|
|
1025
1058
|
});
|
|
1026
1059
|
}
|
|
1027
1060
|
|
|
1028
|
-
export async function
|
|
1061
|
+
export async function readSeekDef(
|
|
1029
1062
|
target: string,
|
|
1030
|
-
options: DefOptions
|
|
1063
|
+
options: DefOptions,
|
|
1031
1064
|
): Promise<DefLocation[]> {
|
|
1032
|
-
const args = ["def", target, "--format", "plain"];
|
|
1033
|
-
if (options.fromIdentify) {
|
|
1034
|
-
args.push("--from-identify");
|
|
1035
|
-
}
|
|
1036
|
-
if (options.name) {
|
|
1037
|
-
args.push(options.name);
|
|
1038
|
-
}
|
|
1065
|
+
const args = ["def", target, "--format", "plain", options.name];
|
|
1039
1066
|
if (options.language) args.push("--language", options.language);
|
|
1040
1067
|
if (options.cached) args.push("--cached");
|
|
1041
1068
|
if (options.others) args.push("--others");
|
|
1042
1069
|
if (options.ignored) args.push("--ignored");
|
|
1043
|
-
|
|
1044
|
-
return parseDefCompact(await runReadSeek(args, { signal: options.signal, stdin }));
|
|
1070
|
+
return parseDefCompact(await runReadSeek(args, { signal: options.signal }));
|
|
1045
1071
|
}
|
package/src/readseek-params.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function langParam() {
|
|
|
16
16
|
* TypeBox fragment for the Git-scope parameters shared by every readseek
|
|
17
17
|
* search tool. Returns fresh schema instances so each tool spreads its own.
|
|
18
18
|
*/
|
|
19
|
-
export function
|
|
19
|
+
export function readSeekGitSearchParams() {
|
|
20
20
|
return {
|
|
21
21
|
cached: Type.Optional(Type.Boolean({ description: "In a Git repository, search tracked/indexed files" })),
|
|
22
22
|
others: Type.Optional(Type.Boolean({ description: "In a Git repository, search untracked files" })),
|