pi-read-map 1.2.3 → 1.2.5
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/CHANGELOG.md +13 -0
- package/README.md +4 -3
- package/package.json +1 -1
- package/src/index.ts +77 -12
- package/src/mappers/fallback.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.5] - 2026-02-15
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `sendMessage` calls in `tool_result` handler now use `deliverAs: "followUp"` instead of the default `"steer"` mode. The default `"steer"` mode interrupts streaming and skips remaining parallel tools — when multiple reads ran concurrently and one triggered a file-map or directory-listing message, the remaining tool calls were skipped, leaving `tool_use` blocks without matching `tool_result` blocks. This caused a 400 error from the Claude API on the next request.
|
|
10
|
+
|
|
11
|
+
## [1.2.4] - 2026-02-15
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Binary/image files (`.jpg`, `.png`, `.gif`, `.webp`, etc.) no longer enter the map generation pipeline — they are delegated directly to the built-in read tool. Previously, a >50 KB image would pass the size threshold, run `wc -l` on binary data, and trigger ctags/grep fallback. When multiple image reads ran in parallel, the resulting `sendMessage` calls broke the Claude API's `tool_use`/`tool_result` pairing requirement.
|
|
16
|
+
- Fallback mapper now returns `null` when grep finds zero symbols instead of returning an empty `FileMap`. This prevents unnecessary `sendMessage` calls for unmappable files.
|
|
17
|
+
|
|
5
18
|
## [1.2.2] - 2026-02-14
|
|
6
19
|
|
|
7
20
|
### Changed
|
package/README.md
CHANGED
|
@@ -157,9 +157,10 @@ tests/
|
|
|
157
157
|
|
|
158
158
|
The extension intercepts `read` calls and decides:
|
|
159
159
|
|
|
160
|
-
1. **
|
|
161
|
-
2. **
|
|
162
|
-
3. **
|
|
160
|
+
1. **Binary files** (images, audio, video, archives, etc.): Delegate to built-in read tool
|
|
161
|
+
2. **Small files** (≤2,000 lines, ≤50 KB): Delegate to built-in read tool
|
|
162
|
+
3. **Targeted reads** (offset or limit provided): Delegate to built-in read tool
|
|
163
|
+
4. **Large files:**
|
|
163
164
|
- Call built-in read for the first chunk
|
|
164
165
|
- Detect language from file extension
|
|
165
166
|
- Dispatch to a mapper (language-specific → ctags → grep fallback)
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { Text } from "@mariozechner/pi-tui";
|
|
|
10
10
|
import { Type } from "@sinclair/typebox";
|
|
11
11
|
import { exec } from "node:child_process";
|
|
12
12
|
import { stat } from "node:fs/promises";
|
|
13
|
-
import { basename, resolve } from "node:path";
|
|
13
|
+
import { basename, extname, resolve } from "node:path";
|
|
14
14
|
import { promisify } from "node:util";
|
|
15
15
|
|
|
16
16
|
import type { FileMapMessageDetails } from "./types.js";
|
|
@@ -22,6 +22,60 @@ export type { FileMapMessageDetails } from "./types.js";
|
|
|
22
22
|
|
|
23
23
|
const execAsync = promisify(exec);
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* File extensions that are binary/image files and should be
|
|
27
|
+
* delegated directly to the built-in read tool without map generation.
|
|
28
|
+
*/
|
|
29
|
+
const BINARY_EXTENSIONS = new Set([
|
|
30
|
+
".jpg",
|
|
31
|
+
".jpeg",
|
|
32
|
+
".png",
|
|
33
|
+
".gif",
|
|
34
|
+
".webp",
|
|
35
|
+
".bmp",
|
|
36
|
+
".ico",
|
|
37
|
+
".tiff",
|
|
38
|
+
".tif",
|
|
39
|
+
".svg",
|
|
40
|
+
".avif",
|
|
41
|
+
".heic",
|
|
42
|
+
".heif",
|
|
43
|
+
// Audio/video
|
|
44
|
+
".mp3",
|
|
45
|
+
".mp4",
|
|
46
|
+
".wav",
|
|
47
|
+
".avi",
|
|
48
|
+
".mov",
|
|
49
|
+
".mkv",
|
|
50
|
+
".flac",
|
|
51
|
+
".ogg",
|
|
52
|
+
".webm",
|
|
53
|
+
// Archives
|
|
54
|
+
".zip",
|
|
55
|
+
".tar",
|
|
56
|
+
".gz",
|
|
57
|
+
".bz2",
|
|
58
|
+
".xz",
|
|
59
|
+
".7z",
|
|
60
|
+
".rar",
|
|
61
|
+
// Binary data
|
|
62
|
+
".bin",
|
|
63
|
+
".exe",
|
|
64
|
+
".dll",
|
|
65
|
+
".so",
|
|
66
|
+
".dylib",
|
|
67
|
+
".o",
|
|
68
|
+
".a",
|
|
69
|
+
".wasm",
|
|
70
|
+
".pdf",
|
|
71
|
+
".doc",
|
|
72
|
+
".docx",
|
|
73
|
+
".xls",
|
|
74
|
+
".xlsx",
|
|
75
|
+
".ppt",
|
|
76
|
+
".pptx",
|
|
77
|
+
]);
|
|
78
|
+
|
|
25
79
|
// In-memory cache for maps
|
|
26
80
|
const mapCache = new Map<string, { mtime: number; map: string }>();
|
|
27
81
|
|
|
@@ -82,11 +136,14 @@ export default function piReadMapExtension(pi: ExtensionAPI): void {
|
|
|
82
136
|
// Send pending directory listing after read-on-directory error
|
|
83
137
|
const pendingLs = pendingDirectoryLs.get(event.toolCallId);
|
|
84
138
|
if (pendingLs) {
|
|
85
|
-
pi.sendMessage(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
139
|
+
pi.sendMessage(
|
|
140
|
+
{
|
|
141
|
+
customType: "directory-listing",
|
|
142
|
+
content: `${pendingLs.path} is a directory. Here is ls:\n${pendingLs.listing}`,
|
|
143
|
+
display: true,
|
|
144
|
+
},
|
|
145
|
+
{ deliverAs: "followUp" }
|
|
146
|
+
);
|
|
90
147
|
pendingDirectoryLs.delete(event.toolCallId);
|
|
91
148
|
}
|
|
92
149
|
|
|
@@ -96,12 +153,15 @@ export default function piReadMapExtension(pi: ExtensionAPI): void {
|
|
|
96
153
|
}
|
|
97
154
|
|
|
98
155
|
// Send the map as a custom message
|
|
99
|
-
pi.sendMessage(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
156
|
+
pi.sendMessage(
|
|
157
|
+
{
|
|
158
|
+
customType: "file-map",
|
|
159
|
+
content: pending.map,
|
|
160
|
+
display: true,
|
|
161
|
+
details: pending.details,
|
|
162
|
+
},
|
|
163
|
+
{ deliverAs: "followUp" }
|
|
164
|
+
);
|
|
105
165
|
|
|
106
166
|
// Clean up
|
|
107
167
|
pendingMaps.delete(event.toolCallId);
|
|
@@ -257,6 +317,11 @@ export default function piReadMapExtension(pi: ExtensionAPI): void {
|
|
|
257
317
|
// Resolve path
|
|
258
318
|
const absPath = resolve(cwd, inputPath.replace(/^@/, ""));
|
|
259
319
|
|
|
320
|
+
// Skip binary/image files — delegate directly without map generation
|
|
321
|
+
if (BINARY_EXTENSIONS.has(extname(absPath).toLowerCase())) {
|
|
322
|
+
return builtInRead.execute(toolCallId, params, signal, onUpdate);
|
|
323
|
+
}
|
|
324
|
+
|
|
260
325
|
// Check file size and line count
|
|
261
326
|
let stats;
|
|
262
327
|
try {
|
package/src/mappers/fallback.ts
CHANGED