Module: LLMExperiment::Shell

Defined in:
lib/llm_experiment/shell.rb

Overview

Runs commands. Kept as one small module so container-facing classes can take a shell: argument and tests can pass a recorder instead.

Class Method Summary collapse

Class Method Details

.capture(*cmd, allow_failure: false) ⇒ Object

Run a command and capture stdout. Raises unless it succeeds.

Raises:



42
43
44
45
46
47
# File 'lib/llm_experiment/shell.rb', line 42

def capture(*cmd, allow_failure: false)
  out, err, status = Open3.capture3(*cmd)
  raise Error, "command failed: #{cmd.shelljoin}\n#{err}" unless status.success? || allow_failure

  out
end

.interactive(*cmd) ⇒ Object

Hand the terminal to a command (login device flows need a real TTY).



37
38
39
# File 'lib/llm_experiment/shell.rb', line 37

def interactive(*cmd)
  system(*cmd)
end

.log(message) ⇒ Object



12
13
14
# File 'lib/llm_experiment/shell.rb', line 12

def log(message)
  warn "[llmx] #{message}"
end

.log_command(message) ⇒ Object

Command echo, as opposed to progress. Every container invocation goes through here, which is a wall of text during a grid, so it is off unless asked for. Progress messages use log and always print.



19
20
21
# File 'lib/llm_experiment/shell.rb', line 19

def log_command(message)
  log(message) if LLMExperiment.verbose
end

.sh(*cmd, allow_failure: false, log_as: nil) ⇒ Object

Run a command, stream its output, raise unless it succeeds.

log_as replaces what gets echoed, for a command carrying an argument nobody wants in their scrollback: a trial passes its whole prompt as one base64 environment value, which is kilobytes of noise on every run.

Raises:



28
29
30
31
32
33
34
# File 'lib/llm_experiment/shell.rb', line 28

def sh(*cmd, allow_failure: false, log_as: nil)
  log_command(log_as || cmd.shelljoin)
  ok = system(*cmd)
  return ok if ok || allow_failure

  raise Error, "command failed: #{log_as || cmd.shelljoin}"
end

.try(*cmd) ⇒ Object

Run a command and report whether it worked.



50
51
52
53
# File 'lib/llm_experiment/shell.rb', line 50

def try(*cmd)
  out, err, status = Open3.capture3(*cmd)
  [out + err, status.success?]
end

.try_input(input, *cmd) ⇒ Object



55
56
57
58
# File 'lib/llm_experiment/shell.rb', line 55

def try_input(input, *cmd)
  out, err, status = Open3.capture3(*cmd, stdin_data: input)
  [out + err, status.success?]
end