pi-readseek 0.4.12 → 0.4.14

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/src/read.ts CHANGED
@@ -13,12 +13,11 @@ import { Text } from "@earendil-works/pi-tui";
13
13
  import { defineToolPromptMetadata } from "./tool-prompt-metadata.js";
14
14
  import { normalizeToLF, stripBom, hasBareCarriageReturn } from "./edit-diff.js";
15
15
  import { ensureHashInit, escapeControlCharsForDisplay } from "./hashline.js";
16
- import { buildReadseekWarning, buildToolErrorResult, renderReadseekLines, type ReadseekLine, type ReadseekWarning } from "./readseek-value.js";
16
+ import { buildReadSeekWarning, buildToolErrorResult, renderReadSeekLines, type ReadSeekLine, type ReadSeekWarning } from "./readseek-value.js";
17
17
  import { looksLikeBinary } from "./binary-detect.js";
18
- import { isSupportedImageBuffer } from "./image-detect.js";
19
18
  import { resolveToCwd } from "./path-utils.js";
20
19
  import { throwIfAborted } from "./runtime.js";
21
- import { getOrGenerateMap } from "./map-cache.js";
20
+ import { getOrGenerateMap } from "./file-map.js";
22
21
  import { formatFileMapWithBudget } from "./readseek/formatter.js";
23
22
  import { findSymbol, type SymbolMatch } from "./readseek/symbol-lookup.js";
24
23
  import { formatAmbiguous, formatNotFound } from "./readseek/symbol-error-format.js";
@@ -26,15 +25,15 @@ import { buildReadOutput } from "./read-output.js";
26
25
 
27
26
  import { buildLocalBundle } from "./read-local-bundle.js";
28
27
  import { coerceObviousBase10Int } from "./coerce-obvious-int.js";
29
- import { readseekRead } from "./readseek-client.js";
28
+ import { readseekRead, readseekDetect, type ReadSeekDetection } from "./readseek-client.js";
30
29
  import { formatReadCallText, formatReadResultText } from "./read-render-helpers.js";
31
30
  import { clampLineToWidth, clampLinesToWidth, linkToolPath, renderPendingResult, renderToolLabel, resolveRenderResultContext, summaryLine, wrapReadHashlinesForWidth } from "./tui-render-utils.js";
32
31
  import type { FileAnchoredCallback } from "./tool-types.js";
33
- import { registerReadseekTool } from "./register-tool.js";
32
+ import { registerReadSeekTool } from "./register-tool.js";
34
33
 
35
34
  const READ_PROMPT_METADATA = defineToolPromptMetadata({
36
35
  promptUrl: new URL("../prompts/read.md", import.meta.url),
37
- promptSnippet: "Read text files or images; text reads include hashline anchors and optional maps/symbol lookup",
36
+ promptSnippet: "Read text files or images; text reads include hashline anchors and optional maps/symbol lookup, image reads include the attachment plus OCR text",
38
37
  });
39
38
 
40
39
  interface ReadParams {
@@ -138,15 +137,8 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
138
137
  const message = "Cannot combine map with symbol. Use one or the other.";
139
138
  return buildToolErrorResult("read", "invalid-params-combo", message, { path: rawParams.path });
140
139
  }
141
- // Delegate images to the built-in read tool
142
140
  throwIfAborted(signal);
143
141
  const ext = rawPath.split(".").pop()?.toLowerCase() ?? "";
144
- if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext)) {
145
- const builtinRead = createReadTool(cwd);
146
- return succeed(await builtinRead.execute(toolCallId, p, signal, onUpdate));
147
- }
148
-
149
- throwIfAborted(signal);
150
142
  let rawBuffer: Buffer;
151
143
  try {
152
144
  rawBuffer = await fsReadFile(absolutePath);
@@ -168,17 +160,37 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
168
160
  return buildToolErrorResult("read", "fs-error", message, { path: rawParams.path, details: { fsCode: code, fsMessage: err?.message } });
169
161
  }
170
162
 
171
- if (isSupportedImageBuffer(rawBuffer)) {
172
- const builtinRead = createReadTool(cwd);
173
- return succeed(await builtinRead.execute(toolCallId, p, signal, onUpdate));
174
- }
175
163
  const hasBinaryContent = looksLikeBinary(rawBuffer);
164
+ if (hasBinaryContent) {
165
+ // Images are always binary; classify and OCR in a single readseek detect call.
166
+ let detection: ReadSeekDetection | undefined;
167
+ try {
168
+ detection = await readseekDetect(absolutePath, { ocr: true, signal });
169
+ } catch {
170
+ // detect unavailable — fall through to binary-as-text handling below
171
+ }
172
+ if (detection?.image) {
173
+ const builtinRead = createReadTool(cwd);
174
+ const builtinResult = await builtinRead.execute(toolCallId, p, signal, onUpdate);
175
+ const ocrText = detection.ocr?.text?.trim();
176
+ if (ocrText) {
177
+ return succeed({
178
+ ...builtinResult,
179
+ content: [
180
+ ...(builtinResult.content ?? []),
181
+ { type: "text" as const, text: `OCR text extracted from image:\n${ocrText}` },
182
+ ],
183
+ });
184
+ }
185
+ return succeed(builtinResult);
186
+ }
187
+ }
176
188
  throwIfAborted(signal);
177
189
  const rawText = rawBuffer.toString("utf-8");
178
190
  const normalized = normalizeToLF(stripBom(rawText).text);
179
- const allLines = splitReadseekLines(normalized);
191
+ const allLines = splitReadSeekLines(normalized);
180
192
  const total = allLines.length;
181
- const structuredWarnings: ReadseekWarning[] = [];
193
+ const structuredWarnings: ReadSeekWarning[] = [];
182
194
  let startLine = p.offset !== undefined ? p.offset : 1;
183
195
  let endIdx = p.limit !== undefined ? Math.min(startLine - 1 + p.limit, total) : total;
184
196
  if (p.offset !== undefined && startLine > total) {
@@ -203,7 +215,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
203
215
  };
204
216
  lines: string[];
205
217
  }>;
206
- warnings: ReadseekWarning[];
218
+ warnings: ReadSeekWarning[];
207
219
  }
208
220
  | null = null;
209
221
  if (p.symbol) {
@@ -248,7 +260,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
248
260
  lines.push(` To confirm: ${confirmHint}.]`);
249
261
  const bannerText = lines.join("\n");
250
262
  structuredWarnings.push(
251
- buildReadseekWarning("fuzzy-symbol-match", bannerText, {
263
+ buildReadSeekWarning("fuzzy-symbol-match", bannerText, {
252
264
  tier: lookup.tier,
253
265
  symbol: lookup.symbol,
254
266
  otherCandidates: lookup.otherCandidates,
@@ -261,7 +273,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
261
273
  if (p.bundle === "local") {
262
274
  if (!symbolFileMap) {
263
275
  const extLabel = ext || "unknown";
264
- const warning = buildReadseekWarning(
276
+ const warning = buildReadSeekWarning(
265
277
  "bundle-unmappable",
266
278
  `[Warning: local bundle unavailable because symbol mapping is not available for .${extLabel} files — showing plain symbol read]`,
267
279
  );
@@ -282,7 +294,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
282
294
  } else {
283
295
  const bundle = buildLocalBundle(symbolFileMap, symbolMatch, allLines);
284
296
  if (!bundle) {
285
- const warning = buildReadseekWarning(
297
+ const warning = buildReadSeekWarning(
286
298
  "bundle-context-unavailable",
287
299
  `[Warning: local bundle context could not be determined for symbol '${symbolMatch.name}' — showing plain symbol read]`,
288
300
  );
@@ -333,7 +345,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
333
345
  : `readseek returned ${readseekOutput.hashlines.length} lines for requested range ${startLine}-${endIdx} (${expectedLineCount} expected)`;
334
346
  return buildToolErrorResult("read", "readseek-output-mismatch", message, { path: rawParams.path });
335
347
  }
336
- const readseekLines: ReadseekLine[] = readseekOutput.hashlines.map((line) => ({
348
+ const readseekLines: ReadSeekLine[] = readseekOutput.hashlines.map((line) => ({
337
349
  line: line.line,
338
350
  hash: line.hash,
339
351
  anchor: `${line.line}:${line.hash}`,
@@ -341,7 +353,7 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
341
353
  display: escapeControlCharsForDisplay(line.text),
342
354
  }));
343
355
  const selected = readseekLines.map((line) => line.raw);
344
- const formatted = renderReadseekLines(readseekLines);
356
+ const formatted = renderReadSeekLines(readseekLines);
345
357
 
346
358
  const truncation = truncateHead(formatted, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });
347
359
 
@@ -363,17 +375,17 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
363
375
  }
364
376
 
365
377
  if (symbolWarning) {
366
- structuredWarnings.push(buildReadseekWarning("symbol-warning", symbolWarning.trim()));
378
+ structuredWarnings.push(buildReadSeekWarning("symbol-warning", symbolWarning.trim()));
367
379
  }
368
380
 
369
381
  if (hasBinaryContent) {
370
382
  const warning = "[Warning: file appears to be binary — output may be garbled]";
371
- structuredWarnings.push(buildReadseekWarning("binary-content", warning));
383
+ structuredWarnings.push(buildReadSeekWarning("binary-content", warning));
372
384
  }
373
385
 
374
386
  if (hasBareCarriageReturn(rawText)) {
375
387
  const warning = "[Warning: file contains bare CR (\\r) line endings — line numbering may be inconsistent with grep and other tools]";
376
- structuredWarnings.push(buildReadseekWarning("bare-cr", warning));
388
+ structuredWarnings.push(buildReadSeekWarning("bare-cr", warning));
377
389
  }
378
390
 
379
391
  const readOutput = buildReadOutput({
@@ -420,14 +432,14 @@ export async function executeRead(opts: ExecuteReadOptions): Promise<AgentToolRe
420
432
  });
421
433
  }
422
434
 
423
- function splitReadseekLines(text: string): string[] {
435
+ function splitReadSeekLines(text: string): string[] {
424
436
  if (text.length === 0) return [];
425
437
  const withoutTrailingTerminator = text.endsWith("\n") ? text.slice(0, -1) : text;
426
438
  return withoutTrailingTerminator.split("\n");
427
439
  }
428
440
 
429
441
  export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}) {
430
- const tool = registerReadseekTool(pi, {
442
+ const tool = registerReadSeekTool(pi, {
431
443
  policy: "read-only",
432
444
  pythonName: "read",
433
445
  defaultExposure: "safe-by-default",
@@ -497,7 +509,7 @@ export function registerReadTool(pi: ExtensionAPI, options: ReadToolOptions = {}
497
509
  return new Text(clampLinesToWidth([summaryLine(errorText)], width).join("\n"), 0, 0);
498
510
  }
499
511
 
500
- const readseekValue = (result.details as any)?.readseekValue as { range: { startLine: number; endLine: number; totalLines: number }; truncation: any; symbol: any; map: any; warnings: ReadseekWarning[] } | undefined;
512
+ const readseekValue = (result.details as any)?.readseekValue as { range: { startLine: number; endLine: number; totalLines: number }; truncation: any; symbol: any; map: any; warnings: ReadSeekWarning[] } | undefined;
501
513
  if (!readseekValue) {
502
514
  const lines = textContent.split("\n").filter(Boolean).length || textContent.split("\n").length;
503
515
  return new Text(summaryLine(`loaded ${lines} ${lines === 1 ? "line" : "lines"}`, { hidden: !!textContent && !expanded }), 0, 0);
@@ -2,10 +2,6 @@
2
2
  * Constants for thresholds.
3
3
  */
4
4
  export const THRESHOLDS = {
5
- /** Maximum lines before truncation */
6
- MAX_LINES: 2000,
7
- /** Maximum bytes before truncation */
8
- MAX_BYTES: 50 * 1024,
9
5
  /** Maximum map size in bytes */
10
6
  MAX_MAP_BYTES: 25 * 1024,
11
7
  /** Target size for full detail */
@@ -30,37 +30,14 @@ function formatNumber(n: number): string {
30
30
  /**
31
31
  * Format a symbol for display.
32
32
  */
33
- function formatSymbol(
34
- symbol: FileSymbol,
35
- level: DetailLevel,
36
- indent = 0
37
- ): string {
33
+ function formatSymbol(symbol: FileSymbol, indent = 0): string {
38
34
  const prefix = " ".repeat(indent);
39
35
  const lineRange =
40
36
  symbol.startLine === symbol.endLine
41
37
  ? `[${symbol.startLine}]`
42
38
  : `[${symbol.startLine}-${symbol.endLine}]`;
43
39
 
44
- let { name } = symbol;
45
-
46
- if (level === DetailLevel.Full) {
47
- if (symbol.signature) {
48
- // Check whether the signature already contains the symbol name.
49
- // Full-declaration signatures (e.g. Rust "pub fn foo(x: i32) -> bool")
50
- // include the name; partial signatures (e.g. Python "(x, y) -> None")
51
- // do not and should be appended.
52
- if (symbol.signature.includes(name)) {
53
- name = symbol.signature;
54
- } else {
55
- if (symbol.modifiers?.length) {
56
- name = `${symbol.modifiers.join(" ")} ${name}`;
57
- }
58
- name = `${name}${symbol.signature}`;
59
- }
60
- } else if (symbol.modifiers?.length) {
61
- name = `${symbol.modifiers.join(" ")} ${name}`;
62
- }
63
- }
40
+ const { name } = symbol;
64
41
 
65
42
  // Format based on kind
66
43
  let formatted: string;
@@ -88,11 +65,6 @@ function formatSymbol(
88
65
  }
89
66
  }
90
67
 
91
- // Append docstring at Full detail level
92
- if (level === DetailLevel.Full && symbol.docstring) {
93
- formatted += ` — ${symbol.docstring}`;
94
- }
95
-
96
68
  return formatted;
97
69
  }
98
70
 
@@ -107,7 +79,7 @@ function formatSymbols(
107
79
  const lines: string[] = [];
108
80
 
109
81
  for (const symbol of symbols) {
110
- lines.push(formatSymbol(symbol, level, indent));
82
+ lines.push(formatSymbol(symbol, indent));
111
83
 
112
84
  // Add children for full, compact, and minimal levels (not outline or truncated)
113
85
  if (
@@ -118,7 +90,7 @@ function formatSymbols(
118
90
  // For minimal, flatten children
119
91
  if (level === DetailLevel.Minimal) {
120
92
  for (const child of symbol.children) {
121
- lines.push(formatSymbol(child, level, indent + 1));
93
+ lines.push(formatSymbol(child, indent + 1));
122
94
  }
123
95
  } else {
124
96
  lines.push(...formatSymbols(symbol.children, level, indent + 1));
@@ -132,7 +104,7 @@ function formatSymbols(
132
104
  /**
133
105
  * Format a complete file map to a string.
134
106
  */
135
- export function formatFileMap(map: FileMap, level?: DetailLevel): string {
107
+ function formatFileMap(map: FileMap, level?: DetailLevel): string {
136
108
  const effectiveLevel = level ?? map.detailLevel;
137
109
  const fileName = basename(map.path);
138
110
 
@@ -165,20 +137,6 @@ export function formatFileMap(map: FileMap, level?: DetailLevel): string {
165
137
  lines.push("");
166
138
  }
167
139
 
168
- // Add imports if present and not outline or truncated level
169
- if (
170
- effectiveLevel !== DetailLevel.Outline &&
171
- effectiveLevel !== DetailLevel.Truncated &&
172
- map.imports.length > 0
173
- ) {
174
- const importList =
175
- map.imports.length > 10
176
- ? [...map.imports.slice(0, 10), `...${map.imports.length - 10} more`]
177
- : map.imports;
178
- lines.push(`imports: ${importList.join(", ")}`);
179
- lines.push("");
180
- }
181
-
182
140
  // Add symbols
183
141
  if (map.truncatedInfo) {
184
142
  // Truncated format: first half, separator, second half
@@ -236,13 +194,12 @@ export function formatFileMap(map: FileMap, level?: DetailLevel): string {
236
194
  /**
237
195
  * Reduce detail level of a file map.
238
196
  */
239
- export function reduceToLevel(map: FileMap, level: DetailLevel): FileMap {
197
+ function reduceToLevel(map: FileMap, level: DetailLevel): FileMap {
240
198
  if (level === DetailLevel.Outline) {
241
- // Remove all children and signatures
199
+ // Remove all children
242
200
  return {
243
201
  ...map,
244
202
  detailLevel: DetailLevel.Outline,
245
- imports: [],
246
203
  symbols: map.symbols.map((s) => ({
247
204
  name: s.name,
248
205
  kind: s.kind,
@@ -253,7 +210,6 @@ export function reduceToLevel(map: FileMap, level: DetailLevel): FileMap {
253
210
  }
254
211
 
255
212
  if (level === DetailLevel.Minimal) {
256
- // Remove signatures and docstrings but keep children flattened
257
213
  return {
258
214
  ...map,
259
215
  detailLevel: DetailLevel.Minimal,
@@ -262,48 +218,28 @@ export function reduceToLevel(map: FileMap, level: DetailLevel): FileMap {
262
218
  kind: s.kind,
263
219
  startLine: s.startLine,
264
220
  endLine: s.endLine,
265
- isExported: s.isExported,
266
221
  children: s.children?.map((c) => ({
267
222
  name: c.name,
268
223
  kind: c.kind,
269
224
  startLine: c.startLine,
270
225
  endLine: c.endLine,
271
- isExported: c.isExported,
272
226
  })),
273
227
  })),
274
228
  };
275
229
  }
276
230
 
277
231
  if (level === DetailLevel.Compact) {
278
- // Remove signatures but keep structure
279
- return {
280
- ...map,
281
- detailLevel: DetailLevel.Compact,
282
- symbols: map.symbols.map((s) => stripSignatures(s)),
283
- };
232
+ return { ...map, detailLevel: DetailLevel.Compact };
284
233
  }
285
234
 
286
235
  return { ...map, detailLevel: DetailLevel.Full };
287
236
  }
288
237
 
289
- function stripSignatures(symbol: FileSymbol): FileSymbol {
290
- return {
291
- name: symbol.name,
292
- kind: symbol.kind,
293
- startLine: symbol.startLine,
294
- endLine: symbol.endLine,
295
- modifiers: symbol.modifiers,
296
- docstring: symbol.docstring,
297
- isExported: symbol.isExported,
298
- children: symbol.children?.map(stripSignatures),
299
- };
300
- }
301
-
302
238
  /**
303
239
  * Reduce a file map to truncated form: first N + last N symbols only.
304
240
  * Used when even Outline level exceeds budget.
305
241
  */
306
- export function reduceToTruncated(
242
+ function reduceToTruncated(
307
243
  map: FileMap,
308
244
  symbolsEach: number = THRESHOLDS.TRUNCATED_SYMBOLS_EACH
309
245
  ): FileMap {
@@ -333,7 +269,6 @@ export function reduceToTruncated(
333
269
  ...map,
334
270
  symbols: [...firstSymbols, ...lastSymbols],
335
271
  detailLevel: DetailLevel.Truncated,
336
- imports: [],
337
272
  truncatedInfo: {
338
273
  totalSymbols: total,
339
274
  shownSymbols: symbolsEach * 2,
@@ -9,7 +9,7 @@ export interface SymbolMatch {
9
9
  parentName?: string;
10
10
  }
11
11
 
12
- export type SymbolLookupResult =
12
+ type SymbolLookupResult =
13
13
  | { type: "found"; symbol: SymbolMatch }
14
14
  | { type: "ambiguous"; candidates: SymbolMatch[] }
15
15
  | {
@@ -88,22 +88,6 @@ function preferJavaTopLevelType(map: FileMap, candidates: SymbolCandidate[]): Sy
88
88
  return topLevelTypes.length === 1 ? topLevelTypes[0] : undefined;
89
89
  }
90
90
 
91
- function javaPackageName(map: FileMap): string | undefined {
92
- if (map.language !== "Java") return undefined;
93
- for (const entry of map.imports) {
94
- const match = /^package\s+([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*;?$/.exec(entry);
95
- if (match) return match[1];
96
- }
97
- return undefined;
98
- }
99
-
100
- function stripJavaPackagePrefix(map: FileMap, query: string): string | undefined {
101
- const packageName = javaPackageName(map);
102
- if (!packageName) return undefined;
103
- const prefix = `${packageName}.`;
104
- return query.startsWith(prefix) ? query.slice(prefix.length) : undefined;
105
- }
106
-
107
91
  function resolveDotPathSuffix(symbols: FileSymbol[], parts: string[]): SymbolCandidate[] {
108
92
  for (let start = 1; start < parts.length; start++) {
109
93
  const candidates = resolveDotPath(symbols, parts.slice(start));
@@ -118,7 +102,6 @@ export function findSymbol(map: FileMap, query: string): SymbolLookupResult {
118
102
  if (map.symbols.length === 0) return { type: "not-found" };
119
103
 
120
104
  const allSymbols = flattenSymbols(map.symbols);
121
- const javaRelativeQuery = stripJavaPackagePrefix(map, q);
122
105
 
123
106
  const atLineMatch = /^(.+?)@(\d+)$/.exec(q);
124
107
  if (atLineMatch) {
@@ -189,16 +172,6 @@ export function findSymbol(map: FileMap, query: string): SymbolLookupResult {
189
172
  return { type: "ambiguous", candidates: toMatches(exact.slice(0, 5)) };
190
173
  }
191
174
 
192
- if (javaRelativeQuery) {
193
- const javaExact = allSymbols.filter((c) => c.symbol.name === javaRelativeQuery);
194
- if (javaExact.length === 1) return { type: "found", symbol: toMatch(javaExact[0].symbol, javaExact[0].parentName) };
195
- if (javaExact.length > 1) {
196
- const preferred = preferJavaTopLevelType(map, javaExact);
197
- if (preferred) return { type: "found", symbol: toMatch(preferred.symbol, preferred.parentName) };
198
- return { type: "ambiguous", candidates: toMatches(javaExact.slice(0, 5)) };
199
- }
200
- }
201
-
202
175
  if (q.includes(".")) {
203
176
  const parts = q.split(".").map((p) => p.trim());
204
177
  if (parts.length >= 2 && parts.every((p) => p.length > 0)) {
@@ -212,21 +185,6 @@ export function findSymbol(map: FileMap, query: string): SymbolLookupResult {
212
185
  candidates: toMatches(candidates.slice(0, 5)),
213
186
  };
214
187
  }
215
- const javaParts = javaRelativeQuery?.includes(".")
216
- ? javaRelativeQuery.split(".").map((p) => p.trim())
217
- : [];
218
- if (javaParts.length >= 2 && javaParts.every((p) => p.length > 0)) {
219
- const javaCandidates = resolveDotPath(map.symbols, javaParts);
220
- if (javaCandidates.length === 1) {
221
- return { type: "found", symbol: toMatch(javaCandidates[0].symbol, javaCandidates[0].parentName) };
222
- }
223
- if (javaCandidates.length > 1) {
224
- return {
225
- type: "ambiguous",
226
- candidates: toMatches(javaCandidates.slice(0, 5)),
227
- };
228
- }
229
- }
230
188
  const suffixCandidates = resolveDotPathSuffix(map.symbols, parts);
231
189
  if (suffixCandidates.length === 1) {
232
190
  return { type: "found", symbol: toMatch(suffixCandidates[0].symbol, suffixCandidates[0].parentName) };
@@ -12,16 +12,8 @@ export interface FileSymbol {
12
12
  startLine: number;
13
13
  /** Ending line number (1-indexed) */
14
14
  endLine: number;
15
- /** Optional signature (for functions/methods) */
16
- signature?: string;
17
15
  /** Child symbols (for nested structures like methods in classes) */
18
16
  children?: FileSymbol[];
19
- /** Additional modifiers (async, static, etc.) */
20
- modifiers?: string[];
21
- /** First line of JSDoc / docstring (if present) */
22
- docstring?: string;
23
- /** Whether this symbol is exported from its module */
24
- isExported?: boolean;
25
17
  }
26
18
 
27
19
  /**
@@ -50,20 +42,8 @@ export interface FileMap {
50
42
  language: string;
51
43
  /** Extracted symbols */
52
44
  symbols: FileSymbol[];
53
- /** Module imports / dependencies */
54
- imports: string[];
55
45
  /** Detail level used for this map */
56
46
  detailLevel: DetailLevel;
57
47
  /** Truncation metadata (present when symbols are truncated) */
58
48
  truncatedInfo?: TruncatedInfo;
59
49
  }
60
-
61
- /**
62
- * Language information.
63
- */
64
- export interface LanguageInfo {
65
- /** Language identifier */
66
- id: string;
67
- /** Display name */
68
- name: string;
69
- }