Class: Rubino::CLI::ChatCommand

Inherits:
Object
  • Object
show all
Includes:
UI::ProbeWaitIndicator
Defined in:
lib/rubino/cli/chat_command.rb

Overview

Interactive and non-interactive chat session command. Supported flags:

-q/--query    one-shot non-interactive prompt
-c/--continue resume most recent session
-r/--resume   resume session by ID or title
--provider    override provider
--yolo        skip all approval prompts
--max-turns   override max tool iterations
--ignore-rules skip AGENTS.md and context files

Constant Summary collapse

DOUBLE_TAP_SECONDS =

Window (seconds) for the Aider-style double-tap: a second Ctrl+C within this of the first re-raises so the user can actually quit.

2.0
REWIND_SNIPPET_CHARS =

Picker snippet length — enough to recognize the message at a glance.

60
YOLO_CONFIRM_MIN_SECONDS =

The confirm press must come after a deliberate beat (a blind mash re-arms instead of confirming — the exact failure mode of #152 was 2-5 quick presses while watching the stream) and before the arm goes stale (the toast is long gone; a lone later press must re-confirm).

0.3
YOLO_CONFIRM_WINDOW_SECONDS =
5.0
PROMPT_CARET =
""
PROMPT_RAIL =
""
OUTPUT_FORMATS =

Valid –output-format values (one-shot only). ‘text` is the default prose path; `json`/`stream-json` are the machine-readable headless modes (0.5.0, #312). The hyphen spelling is normalized to an underscore symbol.

%i[text json stream_json].freeze

Instance Method Summary collapse

Methods included from UI::ProbeWaitIndicator

#probe_thinking_finished, #probe_thinking_started

Constructor Details

#initialize(options = {}) ⇒ ChatCommand

Returns a new instance of ChatCommand.



43
44
45
# File 'lib/rubino/cli/chat_command.rb', line 43

def initialize(options = {})
  @options = options
end

Instance Method Details

#executeObject



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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rubino/cli/chat_command.rb', line 47

def execute
  query = opt(:query) || opt(:q)

  # Stdin fallback (#329c): when no prompt was given on the command line
  # (no -q/--query, no positional) AND stdin is a pipe/file (not a TTY),
  # read the prompt from stdin so `echo "..." | rubino prompt` and
  # `rubino prompt < file` work like other Unix tools. `prompt` with no
  # args supplies an EMPTY query (args.join == ""), so a blank query also
  # falls through to stdin here; only when stdin is also empty do we hit
  # the no-prompt guard below. A TTY stdin (bare interactive use) is left
  # untouched — nil query stays the interactive path.
  if query.nil? || query.strip.empty?
    piped = read_piped_prompt
    query = piped if piped && !piped.strip.empty?
  end

  # Empty/whitespace guard for the headless path (P2-H3): an empty
  # `-q`/`prompt ""` is truthy in Ruby, so it used to be dispatched
  # straight to the model — a wasted API turn and unpredictable
  # autonomous behaviour. Interactive mode already guards this
  # (`next if input.strip.empty?`); reject a blank one-shot query up
  # front with a clear stderr message + non-zero exit, BEFORE any setup,
  # model-config check, or runner is built. A nil query (bare `chat`)
  # is the interactive path and is left untouched.
  fail_arg!("no prompt provided") if query && query.strip.empty?

  ensure_setup!
  ensure_model_configured!

  if query
    run_oneshot(query)
  else
    run_interactive
  end
rescue Rubino::AmbiguousSessionError, Rubino::SessionError => e
  # Render session-resolution errors as a clean stderr message + non-zero
  # exit, not a Ruby stack trace. AmbiguousSessionError's message
  # already includes the candidate list, so just print it.
  warn e.message
  exit(1)
end