pi-readseek 0.4.7 → 0.4.9
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/package.json +1 -1
- package/src/edit-diff.ts +1 -0
- package/src/edit.ts +1 -0
- package/src/grep.ts +18 -0
- package/src/map-cache.ts +7 -4
- package/src/read.ts +4 -3
- package/src/write.ts +6 -4
package/package.json
CHANGED
package/src/edit-diff.ts
CHANGED
package/src/edit.ts
CHANGED
|
@@ -277,6 +277,7 @@ export async function executeEdit(opts: ExecuteEditOptions): Promise<any> {
|
|
|
277
277
|
const replaceSymbolRanges: { start: number; end: number }[] = [];
|
|
278
278
|
const rsProbeResults: { type: "ok"; content: string; replacement: string; warnings: string[]; range: { start: number; end: number } }[] = [];
|
|
279
279
|
for (const rs of replaceSymbolEdits) {
|
|
280
|
+
throwIfAborted(signal);
|
|
280
281
|
const probe = await replaceSymbol({
|
|
281
282
|
filePath: absolutePath,
|
|
282
283
|
content: originalNormalized,
|
package/src/grep.ts
CHANGED
|
@@ -315,6 +315,24 @@ export async function executeGrep(opts: ExecuteGrepOptions): Promise<any> {
|
|
|
315
315
|
let parsedCount = 0;
|
|
316
316
|
let candidateUnparsedCount = 0;
|
|
317
317
|
const candidateLinePattern = /^.+(?::|-)\d+(?::|-)\s/;
|
|
318
|
+
// Pre-read all matched files with bounded concurrency so the processing
|
|
319
|
+
// loop below hits the cache on every getFileLines call instead of
|
|
320
|
+
// serialising disk I/O.
|
|
321
|
+
if (!p.summary) {
|
|
322
|
+
const pathsToRead = new Set<string>();
|
|
323
|
+
for (const line of textBlock.text.split("\n")) {
|
|
324
|
+
throwIfAborted(signal);
|
|
325
|
+
const parsed = parseGrepOutputLine(line);
|
|
326
|
+
if (parsed && Number.isFinite(parsed.lineNumber) && parsed.lineNumber >= 1) {
|
|
327
|
+
pathsToRead.add(toAbsolutePath(parsed.displayPath));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const CONCURRENCY = 8;
|
|
331
|
+
const pathList = [...pathsToRead];
|
|
332
|
+
for (let i = 0; i < pathList.length; i += CONCURRENCY) {
|
|
333
|
+
await Promise.all(pathList.slice(i, i + CONCURRENCY).map((p) => getFileLines(p)));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
318
336
|
|
|
319
337
|
const addSummaryMatch = (displayPath: string, absolutePath: string) => {
|
|
320
338
|
let group = groupsByPath.get(displayPath);
|
package/src/map-cache.ts
CHANGED
|
@@ -29,11 +29,15 @@ function getMapCacheState(): MapCacheGlobalState {
|
|
|
29
29
|
globalObject[MAP_CACHE_STATE_KEY] = state;
|
|
30
30
|
return state;
|
|
31
31
|
}
|
|
32
|
+
/** Move an existing entry to the most-recently-used position (Map insertion-order tail). */
|
|
33
|
+
function touchMapEntry<K, V>(map: Map<K, V>, key: K, value: V): void {
|
|
34
|
+
map.delete(key);
|
|
35
|
+
map.set(key, value);
|
|
36
|
+
}
|
|
32
37
|
|
|
33
38
|
function rememberInMemory(absPath: string, entry: CacheEntry): void {
|
|
34
39
|
const state = getMapCacheState();
|
|
35
|
-
|
|
36
|
-
state.cache.set(absPath, entry);
|
|
40
|
+
touchMapEntry(state.cache, absPath, entry);
|
|
37
41
|
if (state.cache.size > state.maxSize) {
|
|
38
42
|
const oldestKey = state.cache.keys().next().value;
|
|
39
43
|
if (oldestKey !== undefined) state.cache.delete(oldestKey);
|
|
@@ -55,8 +59,7 @@ export async function getOrGenerateMap(absPath: string): Promise<FileMap | null>
|
|
|
55
59
|
const state = getMapCacheState();
|
|
56
60
|
const cached = state.cache.get(absPath);
|
|
57
61
|
if (cached && cached.mtimeMs === mtimeMs) {
|
|
58
|
-
state.cache
|
|
59
|
-
state.cache.set(absPath, cached);
|
|
62
|
+
touchMapEntry(state.cache, absPath, cached);
|
|
60
63
|
return cached.map;
|
|
61
64
|
}
|
|
62
65
|
const inflight = state.inflight.get(absPath);
|
package/src/read.ts
CHANGED
|
@@ -91,7 +91,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
91
91
|
const rawBundle = typeof rawParams.bundle === "string" ? rawParams.bundle.trim() : undefined;
|
|
92
92
|
const requestedMapViaBundle =
|
|
93
93
|
rawBundle === "map" ||
|
|
94
|
-
(rawBundle === "local" && rawParams.symbol === undefined && rawParams.map
|
|
94
|
+
(rawBundle === "local" && rawParams.symbol === undefined && (rawParams.map ?? true));
|
|
95
95
|
const p = {
|
|
96
96
|
...rawParams,
|
|
97
97
|
offset: offset.value,
|
|
@@ -174,7 +174,8 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
174
174
|
}
|
|
175
175
|
const hasBinaryContent = looksLikeBinary(rawBuffer);
|
|
176
176
|
throwIfAborted(signal);
|
|
177
|
-
const
|
|
177
|
+
const rawText = rawBuffer.toString("utf-8");
|
|
178
|
+
const normalized = normalizeToLF(stripBom(rawText).text);
|
|
178
179
|
const allLines = splitReadseekLines(normalized);
|
|
179
180
|
const total = allLines.length;
|
|
180
181
|
const structuredWarnings: ReadseekWarning[] = [];
|
|
@@ -370,7 +371,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
|
|
|
370
371
|
structuredWarnings.push(buildReadseekWarning("binary-content", warning));
|
|
371
372
|
}
|
|
372
373
|
|
|
373
|
-
if (hasBareCarriageReturn(
|
|
374
|
+
if (hasBareCarriageReturn(rawText)) {
|
|
374
375
|
const warning = "[Warning: file contains bare CR (\\r) line endings — line numbering may be inconsistent with grep and other tools]";
|
|
375
376
|
structuredWarnings.push(buildReadseekWarning("bare-cr", warning));
|
|
376
377
|
}
|
package/src/write.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { existsSync, mkdirSync,
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
2
3
|
import { dirname, relative } from "node:path";
|
|
3
4
|
|
|
4
5
|
import { withFileMutationQueue, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
@@ -92,10 +93,11 @@ export interface WriteResult extends WriteDiffFields {
|
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
|
|
97
|
+
async function readPreviousTextForDiff(filePath: string): Promise<string> {
|
|
96
98
|
try {
|
|
97
99
|
if (!existsSync(filePath)) return "";
|
|
98
|
-
const previous =
|
|
100
|
+
const previous = await readFile(filePath);
|
|
99
101
|
if (looksLikeBinary(previous)) return "";
|
|
100
102
|
return previous.toString("utf-8");
|
|
101
103
|
} catch {
|
|
@@ -223,7 +225,7 @@ export async function executeWrite(opts: {
|
|
|
223
225
|
},
|
|
224
226
|
};
|
|
225
227
|
}
|
|
226
|
-
const previousContent = readPreviousTextForDiff(filePath);
|
|
228
|
+
const previousContent = await readPreviousTextForDiff(filePath);
|
|
227
229
|
const existedBeforeWrite = existsSync(filePath);
|
|
228
230
|
|
|
229
231
|
// Create parent directories
|