execute method

  1. @override
Future<ToolResult> execute(
  1. Map<String, dynamic> input
)
override

Execute the tool with the given input.

Implementation

@override
Future<ToolResult> execute(Map<String, dynamic> input) async {
  final parsed = FileReadInput.fromMap(input);
  final errors = parsed.validate();
  if (errors.isNotEmpty) {
    return ToolResult.error(errors.first);
  }

  // Resolve symlinks
  final resolvedPath = await _resolveSymlinks(parsed.filePath);

  // Check existence
  final fileType = await FileSystemEntity.type(resolvedPath);
  if (fileType == FileSystemEntityType.notFound) {
    return ToolResult.error('File not found: ${parsed.filePath}');
  }
  if (fileType == FileSystemEntityType.directory) {
    return ToolResult.error(
      '${parsed.filePath} is a directory, not a file. '
      'Use the Bash tool with ls to list directory contents.',
    );
  }

  final file = File(resolvedPath);

  // Permission check
  try {
    final stat = await file.stat();
    if (stat.type == FileSystemEntityType.notFound) {
      return ToolResult.error('File not found: ${parsed.filePath}');
    }
  } on FileSystemException catch (e) {
    return ToolResult.error('Permission denied: ${e.message}');
  }

  final stat = await file.stat();
  final fileSize = stat.size;
  final modified = stat.modified;

  // Check for binary file
  final binaryInfo = await _detectBinaryFile(file);
  if (binaryInfo != null) {
    return _handleBinaryFile(file, parsed, binaryInfo, fileSize, modified);
  }

  // Handle special file types by extension
  final ext = p.extension(parsed.filePath).toLowerCase();

  if (ext == '.ipynb') {
    return _handleNotebook(file, fileSize, modified);
  }

  if (ext == '.pdf') {
    return _handlePdf(file, parsed, fileSize, modified);
  }

  // Read as text
  return _readTextFile(file, parsed, fileSize, modified);
}