UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

105 lines 4.14 kB
import { readFile } from 'fs/promises'; import path from 'path'; import { BaseTool } from '../base.js'; export class FileReadTool extends BaseTool { name = 'file_read'; displayName = '📖 Read File'; description = 'Read file contents. Requires "path" parameter (e.g., {"path": "/src/app.ts"}).'; category = 'file'; icon = '📖'; parameters = [ { name: 'path', type: 'string', description: 'Path to the file to read (absolute or relative to working directory)', required: true }, { name: 'encoding', type: 'string', description: 'File encoding (default: utf8)', default: 'utf8' } ]; permissions = { fileSystem: 'read' }; ui = { showProgress: false, collapsible: true, dangerous: false }; async run(params, context) { const { path: filePath, encoding = 'utf8' } = params; if (!filePath) { throw new Error('Missing required parameter: path. Example usage: {"path": "/src/index.ts"} or {"path": "./README.md"}'); } const resolvedPath = path.isAbsolute(filePath) ? filePath : path.join(context.workingDirectory || process.cwd(), filePath); this.reportProgress(context, `Reading file: ${resolvedPath}`); try { const content = await readFile(resolvedPath, encoding); if (encoding === 'base64' || this.isBinaryFile(resolvedPath)) { return { path: resolvedPath, encoding: 'base64', content: content.toString('base64'), size: content.length }; } const lines = content.toString().split('\n'); const maxLines = 500; let displayLines = lines; let truncated = false; if (lines.length > maxLines) { displayLines = [ ...lines.slice(0, 250), `\n... truncated ${lines.length - maxLines} lines ...\n`, ...lines.slice(-250) ]; truncated = true; } const numberedLines = displayLines.map((line, i) => { if (line.includes('... truncated')) return line; const lineNum = i < 250 ? i + 1 : lines.length - (displayLines.length - i - 1); return `${lineNum.toString().padStart(4, ' ')}${line}`; }); return { path: resolvedPath, encoding, content: truncated ? `[File truncated for token optimization. Showing ${maxLines} of ${lines.length} lines]` : content.toString(), displayContent: numberedLines.join('\n'), lines: lines.length, size: content.length, truncated }; } catch (error) { if (error.code === 'ENOENT') { throw new Error(`File not found: ${resolvedPath}. Make sure the path is correct. Use file_list to browse available files.`); } else if (error.code === 'EACCES') { throw new Error(`Permission denied: ${resolvedPath}`); } else if (error.code === 'EISDIR') { throw new Error(`Path is a directory: ${resolvedPath}. Use file_list to see directory contents instead.`); } throw error; } } isBinaryFile(filePath) { const binaryExtensions = [ '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.ico', '.webp', '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.zip', '.tar', '.gz', '.rar', '.7z', '.exe', '.dll', '.so', '.dylib', '.mp3', '.mp4', '.avi', '.mov', '.wav', '.woff', '.woff2', '.ttf', '.otf' ]; const ext = path.extname(filePath).toLowerCase(); return binaryExtensions.includes(ext); } } //# sourceMappingURL=file-read.js.map