summaryrefslogtreecommitdiffhomepage
path: root/lib/dispatch/tool/files/read_file.rb
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-03-31 23:10:45 +0900
committerAdam Malczewski <[email protected]>2026-03-31 23:10:45 +0900
commit57c56daf5906442dacc15951c9b3405f89309839 (patch)
treee76890119c0e47acb48f8585222b7a2f5e22df56 /lib/dispatch/tool/files/read_file.rb
parent25488d32336e05b69a41391cc7b5153478d3cc8a (diff)
downloaddispatch-tool-files-dev.tar.gz
dispatch-tool-files-dev.zip
impdev
Diffstat (limited to 'lib/dispatch/tool/files/read_file.rb')
-rw-r--r--lib/dispatch/tool/files/read_file.rb68
1 files changed, 68 insertions, 0 deletions
diff --git a/lib/dispatch/tool/files/read_file.rb b/lib/dispatch/tool/files/read_file.rb
new file mode 100644
index 0000000..c0c5edc
--- /dev/null
+++ b/lib/dispatch/tool/files/read_file.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Dispatch
+ module Tool
+ module Files
+ READ_FILE = Dispatch::Tools::Definition.new(
+ name: "read_file",
+ description: "Read the contents of a file. Returns file contents with line numbers.",
+ parameters: {
+ type: "object",
+ properties: {
+ path: {
+ type: "string",
+ description: "Path to the file to read, relative to the worktree root."
+ },
+ start_line: {
+ type: "integer",
+ description: "The line number to start reading from (0-based). Defaults to 0."
+ },
+ end_line: {
+ type: "integer",
+ description: "The inclusive line number to stop reading at (0-based). Use -1 for end of file."
+ }
+ },
+ required: %w[path],
+ additionalProperties: false
+ }
+ ) do |params, context|
+ worktree_path = context[:worktree_path]
+ path = params[:path]
+
+ resolved = begin
+ Sandbox.resolve_path(path, worktree_path:)
+ rescue SandboxError => e
+ next Dispatch::Tools::Result.failure(error: e.message)
+ end
+
+ unless File.exist?(resolved)
+ next Dispatch::Tools::Result.failure(error: "File not found: #{path}")
+ end
+
+ # Binary file detection: check first 8192 bytes for null bytes
+ sample = File.binread(resolved, 8192)
+ if sample.include?("\x00")
+ next Dispatch::Tools::Result.failure(error: "Cannot read binary file: #{path}")
+ end
+
+ lines = File.readlines(resolved)
+
+ start_line = params.fetch(:start_line, 0)
+ end_line = params.fetch(:end_line, -1)
+ end_line = lines.length - 1 if end_line == -1
+
+ selected = lines[start_line..end_line] || []
+
+ # Calculate padding width based on the highest line number
+ width = end_line.to_s.length
+
+ output = selected.each_with_index.map do |line, idx|
+ line_num = start_line + idx
+ "#{line_num.to_s.rjust(width)}: #{line}"
+ end.join
+
+ Dispatch::Tools::Result.success(output:)
+ end
+ end
+ end
+end