Module: Agentic::UI

Defined in:
lib/agentic/ui.rb

Overview

UI helpers for the CLI

Class Method Summary collapse

Class Method Details

.box(title, content, options = {}) ⇒ String

Creates a colored text box

Parameters:

  • title (String)

    The box title

  • content (String)

    The box content

  • options (Hash) (defaults to: {})

    Additional options for the box

Returns:

  • (String)

    The formatted box



38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/agentic/ui.rb', line 38

def self.box(title, content, options = {})
  # Calculate width based on visible characters (strip ANSI codes)
  visible_lines = content.lines.map { |line| line.gsub(/\e\[[0-9;]*m/, "") }
  max_line_length = visible_lines.map(&:length).max || 0

  TTY::Box.frame(
    title: {top_left: title},
    width: [100, max_line_length + 4].min,
    padding: 1,
    **options
  ) { content }
end

.clear_and_reposition(line_count) ⇒ Object

Clears lines and repositions cursor for table updates

Parameters:

  • line_count (Integer)

    Number of lines to clear



181
182
183
# File 'lib/agentic/ui.rb', line 181

def self.clear_and_reposition(line_count)
  print cursor.up(line_count) + cursor.clear_lines(line_count, :down)
end

.colorize(text, color) ⇒ String

Returns colored text

Parameters:

  • text (String)

    The text to colorize

  • color (Symbol)

    The color to use

Returns:

  • (String)

    The colorized text



61
62
63
# File 'lib/agentic/ui.rb', line 61

def self.colorize(text, color)
  pastel.send(color, text)
end

.cursorTTY::Cursor

Returns a cursor instance for terminal positioning

Returns:

  • (TTY::Cursor)

    The cursor instance



175
176
177
# File 'lib/agentic/ui.rb', line 175

def self.cursor
  @cursor ||= TTY::Cursor
end

.format_duration(seconds) ⇒ String

Formats a duration in seconds to a human-readable string

Parameters:

  • seconds (Float)

    The duration in seconds

Returns:

  • (String)

    The formatted duration



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/agentic/ui.rb', line 89

def self.format_duration(seconds)
  if seconds < 1
    "#{(seconds * 1000).round}ms"
  elsif seconds < 60
    "#{seconds.round(2)}s"
  elsif seconds < 3600
    minutes = (seconds / 60).floor
    remaining_seconds = (seconds % 60).round
    "#{minutes}m #{remaining_seconds}s"
  else
    hours = (seconds / 3600).floor
    minutes = ((seconds % 3600) / 60).floor
    "#{hours}h #{minutes}m"
  end
end

.pastelPastel

Returns a pastel instance for colorizing text

Returns:

  • (Pastel)

    The pastel instance



53
54
55
# File 'lib/agentic/ui.rb', line 53

def self.pastel
  @pastel ||= Pastel.new
end

.progress_bar(title, total, options = {}) ⇒ TTY::ProgressBar

Creates and returns a new progress bar

Parameters:

  • title (String)

    The progress bar title

  • total (Integer)

    The total number of steps

  • options (Hash) (defaults to: {})

    Additional options for the progress bar

Returns:

  • (TTY::ProgressBar)

    The progress bar object



26
27
28
29
30
31
# File 'lib/agentic/ui.rb', line 26

def self.progress_bar(title, total, options = {})
  TTY::ProgressBar.new("[:bar] #{title} :percent",
    total: total,
    width: 40,
    **options)
end

.spinner(message, format: :dots) ⇒ TTY::Spinner

Creates and returns a new spinner

Parameters:

  • message (String)

    The message to display with the spinner

  • format (Symbol) (defaults to: :dots)

    The spinner format

Returns:

  • (TTY::Spinner)

    The spinner object



17
18
19
# File 'lib/agentic/ui.rb', line 17

def self.spinner(message, format: :dots)
  TTY::Spinner.new("[:spinner] #{message}", format: format)
end

.status_text(text, status) ⇒ String

Returns a text with a colored status indicator

Parameters:

  • text (String)

    The text to display

  • status (Symbol)

    The status

Returns:

  • (String)

    The text with colored status



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/agentic/ui.rb', line 69

def self.status_text(text, status)
  status_color = case status
  when :success, :completed
    :green
  when :failure, :failed, :error
    :red
  when :warning, :pending
    :yellow
  when :info, :in_progress
    :blue
  else
    :white
  end

  pastel.send(status_color, text)
end

.task_display_table(tasks, options = {}) ⇒ String

Creates a holistic task display table

Parameters:

  • tasks (Array<Hash>)

    Array of task data with status, description, etc.

  • options (Hash) (defaults to: {})

    Display options

Returns:

  • (String)

    The formatted table



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/agentic/ui.rb', line 152

def self.task_display_table(tasks, options = {})
  return "" if tasks.empty?

  # Use simplified headers when show_agent_column is false
  show_agent_column = options.fetch(:show_agent_column, true)
  headers = if show_agent_column
    ["Status", "Task", "Agent", "Duration", "Output"]
  else
    ["Status", "Task", "Duration", "Output"]
  end

  table = TTY::Table.new(
    header: headers,
    rows: tasks.map { |task| format_task_row(task, show_agent_column: show_agent_column) }
  )

  table.render(:unicode,
    padding: [0, 1],
    **options)
end

.task_status_indicator(status) ⇒ String

Returns a task status indicator

Parameters:

  • status (Symbol)

    The status

Returns:

  • (String)

    The status indicator



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/agentic/ui.rb', line 129

def self.task_status_indicator(status)
  case status
  when :completed
    colorize("", :green)
  when :failed
    colorize("", :red)
  when :in_progress
    colorize("", :blue)
  when :building_agent, :agent_ready
    colorize("", :yellow)  # Pending task execution
  when :pending
    colorize("", :yellow)
  when :canceled
    colorize("", :yellow)
  else
    colorize("?", :white)
  end
end

.with_spinner(message, quiet: false) { ... } ⇒ Object

Handles a long-running operation with a spinner

Parameters:

  • message (String)

    The message to display

  • quiet (Boolean) (defaults to: false)

    Whether to suppress output

Yields:

  • The block to execute

Returns:

  • (Object)

    The return value of the block



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/agentic/ui.rb', line 110

def self.with_spinner(message, quiet: false)
  return yield if quiet

  spinner = self.spinner(message)
  spinner.auto_spin

  begin
    result = yield
    spinner.success("(#{colorize("", :green)}) #{message}")
    result
  rescue => e
    spinner.error("(#{colorize("", :red)}) #{message}: #{e.message}")
    raise
  end
end