import { Box, Text } from "ink" import * as theme from "../../theme.js" import { Icon } from "../Icon.js" import type { ToolRendererProps } from "./types.js" import { truncateText, sanitizeContent, getToolDisplayName, getToolIconName } from "./utils.js" const MAX_PREVIEW_LINES = 12 /** * Check if content looks like actual file content vs just path info * File content typically has newlines or is longer than a typical path */ function isActualContent(content: string, path: string): boolean { if (!content) return false // If content equals path or is just the path, it's not actual content if (content === path || content.endsWith(path)) return false // Check if it looks like a plain path (no newlines, starts with / or drive letter) if (!content.includes("\n") && (content.startsWith("/") || /^[A-Z]:\\/.test(content))) return false // Has newlines or doesn't look like a path - treat as content return content.includes("\n") || content.length > 200 } export function FileReadTool({ toolData }: ToolRendererProps) { const iconName = getToolIconName(toolData.tool) const displayName = getToolDisplayName(toolData.tool) const path = toolData.path || "" const rawContent = toolData.content ? sanitizeContent(toolData.content) : "" const isOutsideWorkspace = toolData.isOutsideWorkspace const isList = toolData.tool.includes("list") || toolData.tool.includes("List") // Only show content if it's actual file content, not just path info const content = isActualContent(rawContent, path) ? rawContent : "" // Handle batch file reads if (toolData.batchFiles && toolData.batchFiles.length > 0) { return ( {/* Header */} {" "} {displayName} ({toolData.batchFiles.length} files) {/* File list */} {toolData.batchFiles.slice(0, 10).map((file, index) => ( {file.path} {file.lineSnippet && ({file.lineSnippet})} {file.isOutsideWorkspace && ( {" "} ⚠ outside workspace )} ))} {toolData.batchFiles.length > 10 && ( ... and {toolData.batchFiles.length - 10} more files )} ) } // Single file read const { text: previewContent, truncated, hiddenLines } = truncateText(content, MAX_PREVIEW_LINES) return ( {/* Header with path on same line for single file */} {displayName} {path && ( <> · {path} {isOutsideWorkspace && ( {" "} ⚠ outside workspace )} )} {/* Content preview - only if we have actual file content */} {previewContent && ( {isList ? ( // Directory listing - show as tree-like structure {previewContent.split("\n").map((line, i) => ( {line} ))} ) : ( // File content - show in a box {previewContent} )} {truncated && ( ... ({hiddenLines} more lines) )} )} ) }