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) ⇒ 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)
  super
  @pending_args[name.to_s] = arguments
end