Class: Brute::Tools::Shell

Inherits:
Brute::Tool show all
Defined in:
lib/brute/tools/shell.rb

Overview

Existing features (ref: opencode bash tool):

  1. Tail-mode truncation — when output exceeds limits, keep the LAST N lines / bytes instead of the first. Command output typically has the important info (errors, summaries) at the end.
  2. Save full output to disk — when truncating, write the complete output to a temp file and include the path in the truncated result so the LLM can use Read with offset/limit to inspect it.
  3. Align limits with universal truncation (2000 lines / 50 KB).
  4. Configurable per-call timeout — accept a timeout parameter from the LLM (defaults to 5 minutes).
  5. Return a plain string instead of a Hash.

Constant Summary collapse

DEFAULT_TIMEOUT =

5 minutes

300

Instance Method Summary collapse

Methods inherited from Brute::Tool

#call, description, #description, param, param_definitions, params, #params, #params_schema

Instance Method Details

#execute(command:, cwd: nil, timeout: nil) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/brute/tools/shell.rb', line 37

def execute(command:, cwd: nil, timeout: nil)
  if cwd
    dir = File.expand_path(cwd)
  else
    dir = Dir.pwd
  end
  unless File.directory?(dir)
    raise "Directory not found: #{dir}"
  end

  timeout_secs = timeout || DEFAULT_TIMEOUT
  stdout, stderr, status = nil
  Timeout.timeout(timeout_secs) do
    stdout, stderr, status = Open3.capture3(
      "bash",
      "-c",
      command,
      chdir: dir,
    )
  end

  out = stdout.to_s
  err = stderr.to_s

  # Combine output, preferring tail-mode truncation so errors/summaries at end are preserved
  combined = out
  unless err.empty?
    combined += "\nSTDERR:\n#{err}"
  end
  if status.exitstatus != 0
    combined += "\n[exit code: #{status.exitstatus}]"
  end

  Brute::Truncation.truncate(combined, direction: :tail)
rescue Timeout::Error
  "Command timed out after #{timeout_secs}s: #{command}"
end

#nameObject



33
# File 'lib/brute/tools/shell.rb', line 33

def name; "shell"; end