Class: RobotLab::To::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/robot_lab/to/cli.rb

Overview

OptionParser-based CLI for robot-to.

Constant Summary collapse

VALUE_OPTIONS =

Value options: [flag, type-or-choices, description, opts-key]. Each sets opts = parsed value. Kept as data so build_parser stays simple.

[
  ["--provider NAME", String, "LLM provider to use (default: openai)", :provider],
  ["--model MODEL", String, "LLM model to use (default: gpt-5.5)", :model],
  ["--max-iterations N", Integer, "Stop after N iterations (default: unlimited)", :max_iterations],
  ["--max-tokens N", Integer, "Stop after N total tokens (default: unlimited)", :max_tokens],
  ["--stop-when CONDITION", String,
   "Natural-language condition; robot sets should_fully_stop when met", :stop_when],
  ["--max-consecutive-failures N", Integer,
   "Abort after N consecutive failures (default: 3)", :max_consecutive_failures],
  ["--max-verify-repairs N", Integer,
   "Repair-in-place attempts when --verify-command fails (default: 2)", :max_verify_repairs],
  ["--verify-command CMD", String,
   "Command that must pass before a successful iteration is committed", :verify_command],
  ["--verify-timeout SECONDS", Integer, "Timeout for --verify-command (default: 600)", :verify_timeout],
  ["--eval NAME", String, "Eval strategy: code | null (default: code when --verify-command set)", :eval],
  ["--measure CMD", String,
   "Command printing a numeric score; higher is better (Evals::Code)", :eval_measure],
  ["--target FLOAT", Float, "Stop once the measured score reaches TARGET", :eval_target],
  ["--spec PATH", String, "Spec/outline artifact the eval measures against (Evals::Prose)", :eval_spec],
  ["--floor CMD", String,
   "Mechanizable floor-check command for prose (links, coverage, AI-tells)", :eval_floor],
  ["--judge-model MODEL", String,
   "Model for the pairwise prose judge (default: --model)", :eval_judge_model],
  ["--stop-on-plateau N", Integer,
   "Stop after N iterations with no committed improvement", :stop_on_plateau],
  ["--run-dir PATH", String, "Directory for run state (default: .robot_lab_to)", :run_dir],
  ["--commit-format FORMAT", %w[default conventional],
   "Commit message format: default or conventional", :commit_format],
  ["--resume RUN_ID", String,
   "Resume a paused run (loads objective + state from its run.json)", :resume],
  ["--decision-mode MODE", %w[wait exit],
   "On a blocking decision: wait (poll) or exit (stop for --resume). Default: wait", :decision_mode],
  ["--decision-timeout SECONDS", Integer,
   "Max seconds to wait on a blocking decision (default: no limit)", :decision_timeout],
  ["--decision-poll SECONDS", Integer,
   "Seconds between polls while waiting on a decision (default: 30)", :decision_wait_poll]
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.run(argv = ARGV) ⇒ Object



49
50
51
# File 'lib/robot_lab/to/cli.rb', line 49

def self.run(argv = ARGV)
  new.run(argv)
end

Instance Method Details

#run(argv) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/robot_lab/to/cli.rb', line 53

def run(argv)
  return run_decisions(argv[1..] || []) if argv.first == "decisions"

  opts   = {}
  parser = build_parser(opts)
  args   = parser.parse!(argv.dup)

  if opts[:version]
    puts "robot-to #{VERSION}"
    return
  end

  if opts[:resume]
    return RobotLab::To.resume(opts[:resume], **opts.except(:version, :resume))
  end

  objective = args.first || read_stdin_objective
  if objective.nil? || objective.strip.empty?
    # $stderr.puts, not warn: warn is silenced when $VERBOSE is nil.
    $stderr.puts "Error: objective required (pass as argument or via stdin)"
    $stderr.puts parser
    exit 1
  end

  RobotLab::To.run(objective.strip, **opts.except(:version, :resume))
end