Class: Rubino::UI::HeadlessTrace

Inherits:
Null
  • Object
show all
Defined in:
lib/rubino/ui/headless_trace.rb

Overview

Non-interactive one-shot TEXT adapter that adds a default-on per-tool ACTIVITY TRACE to the otherwise-silent headless path. It IS a Null adapter (so it keeps every fail-closed / approval-block-latch behaviour the rubino prompt / -q text path depends on — see UI::Null) and adds ONE concise line per tool completion, routed to STDERR:

· edit foo.rb
· bash npm test
· read README.md

The trace goes to STDERR by construction so the final answer on STDOUT stays clean — x=$(rubino prompt …) captures ONLY the answer (#418), while a human watching the terminal still sees what the agent did. This mirrors the industry norm: Codex exec, gemini-cli -p, and rubino's upstream Hermes (-q) all show tool activity on stderr by default, with --quiet (Hermes -Q) selecting the silent machine path (plain UI::Null).

The line vocabulary (name hint) is shared with the interactive tool-card open row via UI::ToolLabel, so the two never drift.

Instance Attribute Summary

Attributes inherited from Null

#messages

Instance Method Summary collapse

Methods inherited from Null

#approval_blocked?, #ask, #assistant_text, #blank_line, #blocked_messages, #body, #box_close, #box_open, #branch_confirmation, #compression_finished, #compression_started, #confirm, #confirm_destructive, #error, #info, #input_injected, #interactive?, #job_enqueued, #job_finished, #job_started, #mode_changed, #note, #probe_aside, #queued, #reasoning_changed, #reasoning_status, #replay_user_input, #reset!, #select, #separator, #status, #stream, #stream_end, #subagent_approval_choice, #success, #table, #think_changed, #think_status, #thinking_finished, #thinking_started, #tool_blocked, #tool_body, #tool_chunk, #warning

Methods inherited from Base

#ask, #assistant_text, #blank_line, #blocking_human_input?, #body, #box_close, #box_open, #compression_finished, #compression_started, #confirm, #confirm_destructive, #error, #hint_row, #info, #input_injected, #interactive?, #job_enqueued, #job_finished, #job_started, #mode_changed, #note, #panel_line, #queued, #replay_user_input, #select, #separator, #status, #stream, #stream_end, #success, #table, #thinking_started, #tool_body, #turn_interrupted, #warning

Constructor Details

#initialize(verbose: false, io: $stderr) ⇒ HeadlessTrace

verbose: widens the per-tool hint (fuller args), mirroring Claude's --verbose. io: is injectable for specs; defaults to the real stderr.



27
28
29
30
31
32
# File 'lib/rubino/ui/headless_trace.rb', line 27

def initialize(verbose: false, io: $stderr)
  super()
  @verbose = verbose
  @trace_io = io
  @pending_args = {}
end

Instance Method Details

#tool_finished(name, result: nil) ⇒ Object

Emit the one trace line per tool COMPLETION (not start) — so a tool that never returns doesn't leave a dangling line, and the order matches the actual work done. Best-effort: a trace write must NEVER fail the run or leak onto stdout.



46
47
48
49
# File 'lib/rubino/ui/headless_trace.rb', line 46

def tool_finished(name, result: nil)
  super
  emit_trace_line(name.to_s)
end

#tool_started(name, arguments: nil, at: nil, call_id: nil) ⇒ Object

Capture the arguments at start so #tool_finished can render the same name hint label the interactive card shows. The task subagent tool renders its own delegation line on finish, so we skip it here.



37
38
39
40
# File 'lib/rubino/ui/headless_trace.rb', line 37

def tool_started(name, arguments: nil, at: nil, call_id: nil)
  super
  @pending_args[name.to_s] = arguments
end