pi-read-map 1.2.2 → 1.2.4

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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.2.4] - 2026-02-15
6
+
7
+ ### Fixed
8
+
9
+ - 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.
10
+ - Fallback mapper now returns `null` when grep finds zero symbols instead of returning an empty `FileMap`. This prevents unnecessary `sendMessage` calls for unmappable files.
11
+
5
12
  ## [1.2.2] - 2026-02-14
6
13
 
7
14
  ### 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. **Small files** (≤2,000 lines, ≤50 KB): Delegate to built-in read tool
161
- 2. **Targeted reads** (offset or limit provided): Delegate to built-in read tool
162
- 3. **Large files:**
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-read-map",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Pi extension that adds structural file maps for large files",
5
5
  "type": "module",
6
6
  "pi": {
package/src/constants.ts CHANGED
@@ -7,11 +7,11 @@ export const THRESHOLDS = {
7
7
  /** Maximum bytes before truncation */
8
8
  MAX_BYTES: 50 * 1024,
9
9
  /** Maximum map size in bytes */
10
- MAX_MAP_BYTES: 20 * 1024,
10
+ MAX_MAP_BYTES: 25 * 1024,
11
11
  /** Target size for full detail */
12
12
  FULL_TARGET_BYTES: 10 * 1024,
13
13
  /** Target size for compact detail */
14
- COMPACT_TARGET_BYTES: 15 * 1024,
14
+ COMPACT_TARGET_BYTES: 20 * 1024,
15
15
  /** Maximum size for outline level */
16
16
  MAX_OUTLINE_BYTES: 50 * 1024,
17
17
  /** Maximum size for truncated level (hard cap) */
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
 
@@ -257,6 +311,11 @@ export default function piReadMapExtension(pi: ExtensionAPI): void {
257
311
  // Resolve path
258
312
  const absPath = resolve(cwd, inputPath.replace(/^@/, ""));
259
313
 
314
+ // Skip binary/image files — delegate directly without map generation
315
+ if (BINARY_EXTENSIONS.has(extname(absPath).toLowerCase())) {
316
+ return builtInRead.execute(toolCallId, params, signal, onUpdate);
317
+ }
318
+
260
319
  // Check file size and line count
261
320
  let stats;
262
321
  try {
@@ -141,6 +141,11 @@ export async function fallbackMapper(
141
141
  };
142
142
  });
143
143
 
144
+ // No symbols found — nothing useful to map
145
+ if (symbols.length === 0) {
146
+ return null;
147
+ }
148
+
144
149
  // Get language info
145
150
  const langInfo = detectLanguage(filePath);
146
151