Class: Rubino::CLI::Commands

Inherits:
Thor
  • Object
show all
Defined in:
lib/rubino/cli/commands.rb

Overview

Main Thor command class. All subcommands are registered here.

Constant Summary collapse

HELP_FLAGS =

Help flags recognized on any top-level command (#134).

["--help", "-h"].freeze
HELP_WRAP_COLUMNS =

Wrap subcommand help so ‘chat –help` / `prompt –help` stay within 80 columns (#217). Thor’s stock #print_options lays the flags and their descriptions out in a 2-column table padded to the WIDEST flag — and the boolean variants (‘[–no-x], [–skip-x]`) push that column past 60, so every description row overflowed 80 (the longest hit 137) with no wrapping. Render each option as its flag line followed by the description wrapped + indented on its own line(s) instead: bounded by construction, and it reads cleaner than the ragged padded table.

80
HELP_DESC_INDENT =
6

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.default_commandObject

Allow passing prompt directly as default task: rubino “my prompt”



21
22
23
# File 'lib/rubino/cli/commands.rb', line 21

def self.default_command
  :chat
end

.exit_on_failure?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/rubino/cli/commands.rb', line 15

def self.exit_on_failure?
  true
end


65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rubino/cli/commands.rb', line 65

def self.print_options(shell, options, group_name = nil)
  return if options.empty?

  shell.say(group_name ? "#{group_name} options:" : "Options:")
  options.reject(&:hide).each do |option|
    shell.say("  #{option.usage(0)}")
    next unless option.description

    wrap_help_description(option.description).each { |line| shell.say(line) }
  end
  shell.say ""
end

.start(given_args = ARGV, config = {}) ⇒ Object

Intercept ‘–version`/`-v` at dispatch (#32). Thor otherwise routes a bare `rubino –version` to the default `chat` task, which treats the flag as a prompt and fails with an API-key error. Handle it here —print the version and exit — before any chat/credential handling.

Likewise intercept ‘rubino <command> –help` (#134): Thor 1.x only maps a LEADING help flag to the help task, so `chat –help`/`prompt –help` used to fall through as an unknown option, become the positional prompt, and start a REAL agent run (provider call + memory writes). Reroute to Thor’s own ‘help <command>` before option parsing. Thor subcommands (config/memory/sessions/jobs) already handle their own `–help` and keep their richer subcommand listing.



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rubino/cli/commands.rb', line 40

def self.start(given_args = ARGV, config = {})
  if ["--version", "-v"].include?(given_args.first)
    puts "rubino v#{Rubino::VERSION}"
    return
  end

  cmd = given_args.first.to_s.tr("-", "_")
  if given_args.drop(1).intersect?(HELP_FLAGS) && commands.key?(cmd) && !subcommands.include?(cmd)
    return super(["help", cmd], config)
  end

  super
end

.wrap_help_description(description) ⇒ Object

Greedy word-wrap of a flag description to HELP_WRAP_COLUMNS, each line indented HELP_DESC_INDENT. Wrapped here (not via Thor’s print_wrapped) so the bound is the fixed 80 the spec checks, not the live terminal width. A single word longer than the budget is emitted on its own line rather than dropped.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/rubino/cli/commands.rb', line 83

def self.wrap_help_description(description)
  indent = " " * HELP_DESC_INDENT
  budget = HELP_WRAP_COLUMNS - HELP_DESC_INDENT
  lines  = []
  line   = +""
  description.to_s.split(/\s+/).each do |word|
    if line.empty?
      line << word
    elsif line.length + 1 + word.length <= budget
      line << " " << word
    else
      lines << (indent + line)
      line = +word
    end
  end
  lines << (indent + line) unless line.empty?
  lines
end

Instance Method Details

#chat(prompt = nil) ⇒ Object



147
148
149
150
151
# File 'lib/rubino/cli/commands.rb', line 147

def chat(prompt = nil)
  # Support: rubino chat "prompt" as shorthand for -q
  opts = options.to_h.merge(prompt ? { query: prompt } : {})
  ChatCommand.new(opts).execute
end

#doctorObject



211
212
213
# File 'lib/rubino/cli/commands.rb', line 211

def doctor
  DoctorCommand.new.execute
end

#prompt(*args) ⇒ Object



168
169
170
171
172
# File 'lib/rubino/cli/commands.rb', line 168

def prompt(*args)
  query = args.join(" ")
  opts = options.to_h.merge(query: query)
  ChatCommand.new(opts).execute
end

#serverObject



198
199
200
# File 'lib/rubino/cli/commands.rb', line 198

def server
  ServerCommand.new(options).execute
end

#setupObject



103
104
105
# File 'lib/rubino/cli/commands.rb', line 103

def setup
  SetupCommand.new.execute
end

#tls_certObject



206
207
208
# File 'lib/rubino/cli/commands.rb', line 206

def tls_cert
  $stdout.write(API::TLS.ensure_cert!)
end

#toolsObject



190
191
192
# File 'lib/rubino/cli/commands.rb', line 190

def tools
  ToolsCommand.new.execute
end

#updateObject



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/rubino/cli/commands.rb', line 221

def update
  ui = Rubino.ui
  current = Rubino::VERSION

  case Rubino::UpdateCheck.install_method
  when :gem
    ok = system(*Rubino::UpdateCheck.gem_update_command)
    unless ok
      ui.warning("gem update failed. If this is a permission error, re-run the installer or try `gem update --user-install #{Rubino::UpdateCheck::GEM_NAME}`.")
      return
    end
    new_v = Rubino::UpdateCheck.installed_gem_version(Rubino::UpdateCheck::GEM_NAME)
    if new_v && Gem::Version.new(new_v) > Gem::Version.new(current)
      ui.info("rubino is now on v#{new_v} (was v#{current}).")
      ui.status("Restart any running rubino sessions to pick up the new version.")
    else
      ui.info("rubino is already up to date (v#{current}).")
    end
  else
    ui.warning("rubino wasn't installed from RubyGems (built from source / dev checkout).")
    ui.status("Re-run the installer to update:")
    ui.status("  curl -fsSL https://raw.githubusercontent.com/Jhonnyr97/rubino-agent/main/install.sh | bash")
  end
ensure
  # Drop the cached notice so the boot footer doesn't linger after update.
  Rubino::UpdateCheck.clear_cache!
end

#versionObject



216
217
218
# File 'lib/rubino/cli/commands.rb', line 216

def version
  Rubino.ui.info("rubino v#{Rubino::VERSION}")
end