Class: ConsoleAgent::Tools::CodeTools

Inherits:
Object
  • Object
show all
Defined in:
lib/console_agent/tools/code_tools.rb

Constant Summary collapse

MAX_FILE_LINES =
200
MAX_LIST_ENTRIES =
100
MAX_SEARCH_RESULTS =
50

Instance Method Summary collapse

Instance Method Details

#list_files(directory = nil) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/console_agent/tools/code_tools.rb', line 8

def list_files(directory = nil)
  directory = sanitize_directory(directory || 'app')
  root = rails_root
  return "Rails.root is not available." unless root

  full_path = File.join(root, directory)
  return "Directory '#{directory}' not found." unless File.directory?(full_path)

  files = Dir.glob(File.join(full_path, '**', '*.rb')).sort
  files = files.map { |f| f.sub("#{root}/", '') }

  if files.length > MAX_LIST_ENTRIES
    truncated = files.first(MAX_LIST_ENTRIES)
    truncated.join("\n") + "\n... and #{files.length - MAX_LIST_ENTRIES} more files"
  elsif files.empty?
    "No Ruby files found in '#{directory}'."
  else
    files.join("\n")
  end
rescue => e
  "Error listing files: #{e.message}"
end

#read_file(path) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/console_agent/tools/code_tools.rb', line 31

def read_file(path)
  return "Error: path is required." if path.nil? || path.strip.empty?

  root = rails_root
  return "Rails.root is not available." unless root

  path = sanitize_path(path)
  full_path = File.expand_path(File.join(root, path))

  # Security: ensure resolved path is under Rails.root
  unless full_path.start_with?(File.expand_path(root))
    return "Error: path must be within the Rails application."
  end

  return "File '#{path}' not found." unless File.exist?(full_path)
  return "Error: '#{path}' is a directory, not a file." if File.directory?(full_path)

  lines = File.readlines(full_path)
  if lines.length > MAX_FILE_LINES
    numbered = lines.first(MAX_FILE_LINES).each_with_index.map { |line, i| "#{i + 1}: #{line}" }
    numbered.join + "\n... truncated (#{lines.length} total lines, showing first #{MAX_FILE_LINES})"
  else
    lines.each_with_index.map { |line, i| "#{i + 1}: #{line}" }.join
  end
rescue => e
  "Error reading file '#{path}': #{e.message}"
end

#search_code(query, directory = nil) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/console_agent/tools/code_tools.rb', line 59

def search_code(query, directory = nil)
  return "Error: query is required." if query.nil? || query.strip.empty?

  directory = sanitize_directory(directory || 'app')
  root = rails_root
  return "Rails.root is not available." unless root

  full_path = File.join(root, directory)
  return "Directory '#{directory}' not found." unless File.directory?(full_path)

  results = []
  Dir.glob(File.join(full_path, '**', '*.rb')).sort.each do |file|
    break if results.length >= MAX_SEARCH_RESULTS

    relative = file.sub("#{root}/", '')
    File.readlines(file).each_with_index do |line, idx|
      if line.include?(query)
        results << "#{relative}:#{idx + 1}: #{line.strip}"
        break if results.length >= MAX_SEARCH_RESULTS
      end
    end
  rescue => e
    # skip unreadable files
  end

  if results.empty?
    "No matches found for '#{query}' in #{directory}/."
  else
    header = "Found #{results.length} match#{'es' if results.length != 1}:\n"
    header + results.join("\n")
  end
rescue => e
  "Error searching: #{e.message}"
end