aidp 0.9.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/aidp/analyze/error_handler.rb +4 -2
- data/lib/aidp/{analysis → analyze}/kb_inspector.rb +106 -89
- data/lib/aidp/analyze/prioritizer.rb +3 -2
- data/lib/aidp/analyze/ruby_maat_integration.rb +20 -3
- data/lib/aidp/analyze/runner.rb +27 -9
- data/lib/aidp/{analysis → analyze}/seams.rb +1 -1
- data/lib/aidp/analyze/steps.rb +7 -7
- data/lib/aidp/{analysis → analyze}/tree_sitter_grammar_loader.rb +22 -5
- data/lib/aidp/{analysis → analyze}/tree_sitter_scan.rb +32 -15
- data/lib/aidp/cli/first_run_wizard.rb +37 -28
- data/lib/aidp/cli/jobs_command.rb +37 -18
- data/lib/aidp/cli/terminal_io.rb +3 -3
- data/lib/aidp/cli.rb +131 -63
- data/lib/aidp/execute/runner.rb +27 -9
- data/lib/aidp/execute/steps.rb +18 -18
- data/lib/aidp/execute/workflow_selector.rb +36 -21
- data/lib/aidp/harness/enhanced_runner.rb +3 -3
- data/lib/aidp/harness/provider_factory.rb +3 -1
- data/lib/aidp/harness/provider_manager.rb +34 -15
- data/lib/aidp/harness/runner.rb +24 -5
- data/lib/aidp/harness/simple_user_interface.rb +19 -4
- data/lib/aidp/harness/status_display.rb +121 -104
- data/lib/aidp/harness/ui/enhanced_tui.rb +33 -5
- data/lib/aidp/harness/ui/error_handler.rb +3 -2
- data/lib/aidp/harness/ui/frame_manager.rb +52 -32
- data/lib/aidp/harness/ui/navigation/main_menu.rb +23 -14
- data/lib/aidp/harness/ui/progress_display.rb +28 -5
- data/lib/aidp/harness/ui/status_widget.rb +17 -8
- data/lib/aidp/harness/ui/workflow_controller.rb +25 -9
- data/lib/aidp/harness/user_interface.rb +341 -328
- data/lib/aidp/provider_manager.rb +10 -6
- data/lib/aidp/providers/anthropic.rb +3 -3
- data/lib/aidp/providers/base.rb +20 -1
- data/lib/aidp/providers/cursor.rb +6 -8
- data/lib/aidp/providers/gemini.rb +3 -3
- data/lib/aidp/providers/github_copilot.rb +264 -0
- data/lib/aidp/providers/opencode.rb +6 -8
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp.rb +4 -4
- metadata +6 -6
- data/lib/aidp/analyze/progress_visualizer.rb +0 -314
@@ -15,7 +15,8 @@ module Aidp
|
|
15
15
|
def initialize(ui_components = {})
|
16
16
|
super()
|
17
17
|
@frame = ui_components[:frame] || TTY::Box
|
18
|
-
@formatter = ui_components[:formatter] || FrameFormatter.new
|
18
|
+
@formatter = ui_components[:formatter] || (defined?(FrameFormatter) ? FrameFormatter.new : nil)
|
19
|
+
@output = ui_components[:output]
|
19
20
|
@frame_open = false
|
20
21
|
@frame_stack = []
|
21
22
|
@frame_history = []
|
@@ -26,6 +27,18 @@ module Aidp
|
|
26
27
|
}
|
27
28
|
end
|
28
29
|
|
30
|
+
private
|
31
|
+
|
32
|
+
def display_message(message)
|
33
|
+
if @output
|
34
|
+
@output.say(message)
|
35
|
+
else
|
36
|
+
puts message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
public
|
41
|
+
|
29
42
|
def open_frame(frame_type, title, frame_data = nil, &block)
|
30
43
|
validate_frame_type(frame_type)
|
31
44
|
validate_title(title)
|
@@ -45,9 +58,9 @@ module Aidp
|
|
45
58
|
|
46
59
|
if block_given?
|
47
60
|
content = yield
|
48
|
-
|
61
|
+
display_message(@frame.frame(formatted_title, content, width: 80))
|
49
62
|
else
|
50
|
-
|
63
|
+
display_message(@frame.frame(formatted_title, width: 80))
|
51
64
|
end
|
52
65
|
rescue InvalidFrameError => e
|
53
66
|
raise e
|
@@ -60,11 +73,18 @@ module Aidp
|
|
60
73
|
validate_title(title)
|
61
74
|
raise DisplayError, "No parent frame exists for nesting" if @frame_stack.empty?
|
62
75
|
|
63
|
-
formatted_title = @formatter.format_frame_title(frame_type, title, frame_data)
|
76
|
+
formatted_title = @formatter ? @formatter.format_frame_title(frame_type, title, frame_data) : title.to_s
|
64
77
|
@frame_stack.push({type: frame_type, title: title, data: frame_data})
|
65
|
-
|
66
|
-
|
78
|
+
|
79
|
+
frame_result = @frame.frame(formatted_title, width: 80) do
|
80
|
+
if block_given?
|
81
|
+
yield || ""
|
82
|
+
else
|
83
|
+
""
|
84
|
+
end
|
67
85
|
end
|
86
|
+
|
87
|
+
display_message(frame_result)
|
68
88
|
rescue InvalidFrameError => e
|
69
89
|
raise e
|
70
90
|
rescue => e
|
@@ -98,7 +118,7 @@ module Aidp
|
|
98
118
|
when :failed then "Failed"
|
99
119
|
else status.to_s.capitalize
|
100
120
|
end
|
101
|
-
|
121
|
+
display_message("Status: #{status_text}")
|
102
122
|
end
|
103
123
|
|
104
124
|
def current_frame_status
|
@@ -125,18 +145,18 @@ module Aidp
|
|
125
145
|
end
|
126
146
|
|
127
147
|
def display_frame_summary
|
128
|
-
|
129
|
-
|
148
|
+
display_message("\n📊 Frame Summary")
|
149
|
+
display_message("=" * 50)
|
130
150
|
|
131
151
|
if @frame_stats[:total_frames] == 0
|
132
|
-
|
152
|
+
display_message("No frames used")
|
133
153
|
return
|
134
154
|
end
|
135
155
|
|
136
|
-
|
156
|
+
display_message("Total Frames: #{@frame_stats[:total_frames]}")
|
137
157
|
|
138
158
|
unless @frame_stats[:frame_types].empty?
|
139
|
-
|
159
|
+
display_message("\nFrame Types:")
|
140
160
|
@frame_stats[:frame_types].each do |type, count|
|
141
161
|
emoji = case type
|
142
162
|
when :section then "📋"
|
@@ -145,12 +165,12 @@ module Aidp
|
|
145
165
|
when :step then "🔧"
|
146
166
|
else "📋"
|
147
167
|
end
|
148
|
-
|
168
|
+
display_message(" #{emoji} #{type.to_s.capitalize}: #{count}")
|
149
169
|
end
|
150
170
|
end
|
151
171
|
|
152
172
|
unless @frame_stats[:status_counts].empty?
|
153
|
-
|
173
|
+
display_message("\nStatus Counts:")
|
154
174
|
@frame_stats[:status_counts].each do |status, count|
|
155
175
|
status_emoji = case status
|
156
176
|
when :running then "🔄"
|
@@ -158,12 +178,12 @@ module Aidp
|
|
158
178
|
when :failed then "❌"
|
159
179
|
else "❓"
|
160
180
|
end
|
161
|
-
|
181
|
+
display_message(" #{status_emoji} #{status.to_s.capitalize}: #{count}")
|
162
182
|
end
|
163
183
|
end
|
164
184
|
|
165
|
-
|
166
|
-
|
185
|
+
display_message("\nCurrent Frame Depth: #{@frame_depth}")
|
186
|
+
display_message("Frames in History: #{@frame_history.length}")
|
167
187
|
end
|
168
188
|
|
169
189
|
def clear_frame_history
|
@@ -182,13 +202,13 @@ module Aidp
|
|
182
202
|
validate_title(title)
|
183
203
|
raise ArgumentError, "Block required for frame_with_block" unless block_given?
|
184
204
|
|
185
|
-
formatted_title = @formatter.format_frame_title(frame_type, title, frame_data)
|
205
|
+
formatted_title = @formatter ? @formatter.format_frame_title(frame_type, title, frame_data) : title.to_s
|
186
206
|
@frame_open = true
|
187
207
|
@frame_stack.push({type: frame_type, title: title, data: frame_data})
|
188
208
|
|
189
209
|
begin
|
190
210
|
content = yield
|
191
|
-
|
211
|
+
display_message(@frame.frame(formatted_title, content, width: 80))
|
192
212
|
|
193
213
|
@frame_open = false
|
194
214
|
@frame_stack.pop unless @frame_stack.empty?
|
@@ -207,7 +227,7 @@ module Aidp
|
|
207
227
|
def divider(text)
|
208
228
|
validate_text(text)
|
209
229
|
|
210
|
-
formatted_text = @formatter.format_divider_text(text)
|
230
|
+
formatted_text = @formatter ? @formatter.format_divider_text(text) : text
|
211
231
|
@frame.divider(formatted_text)
|
212
232
|
rescue => e
|
213
233
|
raise DisplayError, "Failed to create divider: #{e.message}"
|
@@ -216,12 +236,12 @@ module Aidp
|
|
216
236
|
def section(title, &block)
|
217
237
|
validate_title(title)
|
218
238
|
|
219
|
-
formatted_title = @formatter.format_section_title(title)
|
239
|
+
formatted_title = @formatter ? @formatter.format_section_title(title) : "📋 #{title}"
|
220
240
|
if block_given?
|
221
241
|
content = yield
|
222
|
-
|
242
|
+
display_message(@frame.frame(formatted_title, content, width: 80))
|
223
243
|
else
|
224
|
-
|
244
|
+
display_message(@frame.frame(formatted_title, width: 80))
|
225
245
|
end
|
226
246
|
rescue => e
|
227
247
|
raise DisplayError, "Failed to create section: #{e.message}"
|
@@ -230,10 +250,10 @@ module Aidp
|
|
230
250
|
def subsection(title, &block)
|
231
251
|
validate_title(title)
|
232
252
|
|
233
|
-
formatted_title = @formatter.format_subsection_title(title)
|
234
|
-
|
253
|
+
formatted_title = @formatter ? @formatter.format_subsection_title(title) : "📝 #{title}"
|
254
|
+
display_message(@frame.frame(formatted_title, width: 80) do
|
235
255
|
yield if block_given?
|
236
|
-
end
|
256
|
+
end)
|
237
257
|
rescue => e
|
238
258
|
raise DisplayError, "Failed to create subsection: #{e.message}"
|
239
259
|
end
|
@@ -241,10 +261,10 @@ module Aidp
|
|
241
261
|
def workflow_frame(workflow_name, &block)
|
242
262
|
validate_workflow_name(workflow_name)
|
243
263
|
|
244
|
-
formatted_title = @formatter.format_workflow_title(workflow_name)
|
245
|
-
|
264
|
+
formatted_title = @formatter ? @formatter.format_workflow_title(workflow_name) : "⚙️ #{workflow_name}"
|
265
|
+
display_message(@frame.frame(formatted_title, width: 80) do
|
246
266
|
yield if block_given?
|
247
|
-
end
|
267
|
+
end)
|
248
268
|
rescue => e
|
249
269
|
raise DisplayError, "Failed to create workflow frame: #{e.message}"
|
250
270
|
end
|
@@ -252,10 +272,10 @@ module Aidp
|
|
252
272
|
def step_frame(step_name, step_number, total_steps, &block)
|
253
273
|
validate_step_inputs(step_name, step_number, total_steps)
|
254
274
|
|
255
|
-
formatted_title = @formatter.format_step_title(step_name, step_number, total_steps)
|
256
|
-
|
275
|
+
formatted_title = @formatter ? @formatter.format_step_title(step_name, step_number, total_steps) : "🔧 #{step_name} (#{step_number}/#{total_steps})"
|
276
|
+
display_message(@frame.frame(formatted_title, width: 80) do
|
257
277
|
yield if block_given?
|
258
|
-
end
|
278
|
+
end)
|
259
279
|
rescue => e
|
260
280
|
raise DisplayError, "Failed to create step frame: #{e.message}"
|
261
281
|
end
|
@@ -23,6 +23,7 @@ module Aidp
|
|
23
23
|
@pastel = Pastel.new
|
24
24
|
@formatter = ui_components[:formatter] || MenuFormatter.new
|
25
25
|
@state_manager = ui_components[:state_manager] || MenuState.new
|
26
|
+
@output = ui_components[:output]
|
26
27
|
@menu_items = []
|
27
28
|
@current_level = 0
|
28
29
|
@breadcrumb = []
|
@@ -69,9 +70,9 @@ module Aidp
|
|
69
70
|
|
70
71
|
# Add navigation instructions if items exist
|
71
72
|
if menu_items.any?
|
72
|
-
|
73
|
+
display_message "Use arrow keys to navigate, Enter to select"
|
73
74
|
else
|
74
|
-
|
75
|
+
display_message "No options available"
|
75
76
|
end
|
76
77
|
rescue => e
|
77
78
|
raise NavigationError, "Failed to display menu: #{e.message}"
|
@@ -133,7 +134,7 @@ module Aidp
|
|
133
134
|
if index >= 0 && index < menu_items.length
|
134
135
|
return menu_items[index]
|
135
136
|
else
|
136
|
-
|
137
|
+
display_message "Invalid selection"
|
137
138
|
next
|
138
139
|
end
|
139
140
|
else
|
@@ -142,14 +143,14 @@ module Aidp
|
|
142
143
|
if selected_item
|
143
144
|
return selected_item
|
144
145
|
else
|
145
|
-
|
146
|
+
display_message "Invalid selection"
|
146
147
|
next
|
147
148
|
end
|
148
149
|
end
|
149
150
|
end
|
150
151
|
|
151
152
|
# If we get here, we've exceeded max attempts
|
152
|
-
|
153
|
+
display_message "Too many invalid attempts. Returning first option."
|
153
154
|
menu_items.first
|
154
155
|
end
|
155
156
|
|
@@ -194,10 +195,10 @@ module Aidp
|
|
194
195
|
end
|
195
196
|
|
196
197
|
def display_navigation_help
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
198
|
+
display_message "Navigation Help"
|
199
|
+
display_message "Use arrow keys to navigate"
|
200
|
+
display_message "Press Enter to select"
|
201
|
+
display_message "Press Escape to go back"
|
201
202
|
end
|
202
203
|
|
203
204
|
# Additional methods expected by tests
|
@@ -220,15 +221,23 @@ module Aidp
|
|
220
221
|
# Make display_breadcrumb public for testing
|
221
222
|
def display_breadcrumb
|
222
223
|
if @breadcrumb.empty?
|
223
|
-
|
224
|
+
display_message "Home"
|
224
225
|
else
|
225
226
|
breadcrumb_text = @formatter.format_breadcrumb(@breadcrumb)
|
226
|
-
|
227
|
+
display_message(breadcrumb_text)
|
227
228
|
end
|
228
229
|
end
|
229
230
|
|
230
231
|
private
|
231
232
|
|
233
|
+
def display_message(message)
|
234
|
+
if @output
|
235
|
+
@output.say(message)
|
236
|
+
else
|
237
|
+
puts message
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
232
241
|
def validate_menu_item(item)
|
233
242
|
raise InvalidMenuError, "Menu item must be a MenuItem" unless item.is_a?(MenuItem)
|
234
243
|
end
|
@@ -243,14 +252,14 @@ module Aidp
|
|
243
252
|
|
244
253
|
def display_menu_header(title)
|
245
254
|
formatted_title = @formatter.format_menu_title(title)
|
246
|
-
|
247
|
-
|
255
|
+
display_message(formatted_title)
|
256
|
+
display_message(@formatter.format_separator)
|
248
257
|
end
|
249
258
|
|
250
259
|
def display_menu_items
|
251
260
|
@menu_items.each_with_index do |item, index|
|
252
261
|
formatted_item = @formatter.format_menu_item(item, index + 1)
|
253
|
-
|
262
|
+
display_message(formatted_item)
|
254
263
|
end
|
255
264
|
end
|
256
265
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "tty-progressbar"
|
4
|
+
require "tty-prompt"
|
4
5
|
require "pastel"
|
5
6
|
require_relative "base"
|
6
7
|
|
@@ -24,7 +25,8 @@ module Aidp
|
|
24
25
|
@auto_refresh_enabled = false
|
25
26
|
@refresh_interval = 1.0
|
26
27
|
@refresh_thread = nil
|
27
|
-
@output = ui_components[:output]
|
28
|
+
@output = ui_components[:output]
|
29
|
+
@prompt = ui_components[:prompt] || TTY::Prompt.new
|
28
30
|
@spinner_class = begin
|
29
31
|
ui_components[:spinner] || TTY::Spinner
|
30
32
|
rescue
|
@@ -115,7 +117,7 @@ module Aidp
|
|
115
117
|
raise ArgumentError, "Progress items must be an array" unless progress_items.is_a?(Array)
|
116
118
|
|
117
119
|
if progress_items.empty?
|
118
|
-
@
|
120
|
+
display_message(@pastel.dim("No progress items to display."), type: :muted)
|
119
121
|
return
|
120
122
|
end
|
121
123
|
|
@@ -199,7 +201,7 @@ module Aidp
|
|
199
201
|
" (Step: #{progress_data[:current_step]})"
|
200
202
|
task_id = progress_data[:id] ? "[#{progress_data[:id]}] " : ""
|
201
203
|
|
202
|
-
|
204
|
+
display_message("#{task_id}#{progress}% #{message}#{step_info}", type: :info)
|
203
205
|
end
|
204
206
|
|
205
207
|
def display_detailed_progress(progress_data)
|
@@ -210,13 +212,13 @@ module Aidp
|
|
210
212
|
started_at = progress_data[:started_at] ? progress_data[:started_at].strftime("%H:%M:%S") : "N/A"
|
211
213
|
eta = progress_data[:eta] || "N/A"
|
212
214
|
|
213
|
-
|
215
|
+
display_message("Progress: #{progress}% - #{message} (Step: #{current_step}/#{total_steps}, Started: #{started_at}, ETA: #{eta})", type: :info)
|
214
216
|
end
|
215
217
|
|
216
218
|
def display_minimal_progress(progress_data)
|
217
219
|
progress = progress_data[:progress] || 0
|
218
220
|
message = progress_data[:message] || "Processing..."
|
219
|
-
|
221
|
+
display_message("Progress: #{progress}% - #{message}", type: :info)
|
220
222
|
end
|
221
223
|
|
222
224
|
def create_progress_bar(progress)
|
@@ -251,6 +253,27 @@ module Aidp
|
|
251
253
|
timestamp: Time.now
|
252
254
|
}
|
253
255
|
end
|
256
|
+
|
257
|
+
private
|
258
|
+
|
259
|
+
def display_message(message, type: :info)
|
260
|
+
if @prompt
|
261
|
+
color = case type
|
262
|
+
when :error then :red
|
263
|
+
when :success then :green
|
264
|
+
when :warning then :yellow
|
265
|
+
when :info then :blue
|
266
|
+
when :highlight then :cyan
|
267
|
+
when :muted then :bright_black
|
268
|
+
else :white
|
269
|
+
end
|
270
|
+
@prompt.say(message, color: color)
|
271
|
+
elsif @output
|
272
|
+
@output.puts(message)
|
273
|
+
else
|
274
|
+
puts(message)
|
275
|
+
end
|
276
|
+
end
|
254
277
|
end
|
255
278
|
|
256
279
|
# Formats progress display text
|
@@ -18,6 +18,7 @@ module Aidp
|
|
18
18
|
@spinner = ui_components[:spinner] || TTY::Spinner
|
19
19
|
@pastel = Pastel.new
|
20
20
|
@formatter = ui_components[:formatter] || StatusFormatter.new
|
21
|
+
@output = ui_components[:output]
|
21
22
|
@status_history = []
|
22
23
|
@current_spinner = nil
|
23
24
|
@spinner_active = false
|
@@ -56,7 +57,7 @@ module Aidp
|
|
56
57
|
validate_message(message)
|
57
58
|
|
58
59
|
formatted_message = @formatter.format_success_message(message)
|
59
|
-
|
60
|
+
display_message(formatted_message)
|
60
61
|
rescue => e
|
61
62
|
raise DisplayError, "Failed to show success status: #{e.message}"
|
62
63
|
end
|
@@ -65,7 +66,7 @@ module Aidp
|
|
65
66
|
validate_message(message)
|
66
67
|
|
67
68
|
formatted_message = @formatter.format_error_message(message)
|
68
|
-
|
69
|
+
display_message(formatted_message)
|
69
70
|
rescue => e
|
70
71
|
raise DisplayError, "Failed to show error status: #{e.message}"
|
71
72
|
end
|
@@ -74,7 +75,7 @@ module Aidp
|
|
74
75
|
validate_message(message)
|
75
76
|
|
76
77
|
formatted_message = @formatter.format_warning_message(message)
|
77
|
-
|
78
|
+
display_message(formatted_message)
|
78
79
|
rescue => e
|
79
80
|
raise DisplayError, "Failed to show warning status: #{e.message}"
|
80
81
|
end
|
@@ -181,6 +182,14 @@ module Aidp
|
|
181
182
|
|
182
183
|
private
|
183
184
|
|
185
|
+
def display_message(message)
|
186
|
+
if @output
|
187
|
+
@output.say(message)
|
188
|
+
else
|
189
|
+
puts message
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
184
193
|
def validate_message(message)
|
185
194
|
raise InvalidStatusError, "Message cannot be empty" if message.to_s.strip.empty?
|
186
195
|
end
|
@@ -211,22 +220,22 @@ module Aidp
|
|
211
220
|
end
|
212
221
|
|
213
222
|
def display_loading_status(message)
|
214
|
-
|
223
|
+
display_message("⏳ #{message}")
|
215
224
|
end
|
216
225
|
|
217
226
|
def display_success_status(message)
|
218
|
-
|
227
|
+
display_message("✅ #{message}")
|
219
228
|
end
|
220
229
|
|
221
230
|
def display_error_status(message, error_data)
|
222
|
-
|
231
|
+
display_message("❌ #{message}")
|
223
232
|
if error_data && error_data[:message]
|
224
|
-
|
233
|
+
display_message(" #{error_data[:message]}")
|
225
234
|
end
|
226
235
|
end
|
227
236
|
|
228
237
|
def display_warning_status(message)
|
229
|
-
|
238
|
+
display_message("⚠️ #{message}")
|
230
239
|
end
|
231
240
|
end
|
232
241
|
|
@@ -27,6 +27,7 @@ module Aidp
|
|
27
27
|
@status_manager = ui_components[:status_manager] || StatusManager.new
|
28
28
|
@frame_manager = ui_components[:frame_manager] || FrameManager.new
|
29
29
|
@formatter = ui_components[:formatter] || WorkflowControllerFormatter.new
|
30
|
+
@output = ui_components[:output]
|
30
31
|
|
31
32
|
@current_state = :running
|
32
33
|
@state_history = []
|
@@ -187,8 +188,23 @@ module Aidp
|
|
187
188
|
@control_thread = nil
|
188
189
|
end
|
189
190
|
|
191
|
+
# Testing helper method to set state
|
192
|
+
def set_state_for_testing(state)
|
193
|
+
@control_mutex.synchronize do
|
194
|
+
@current_state = state
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
190
198
|
private
|
191
199
|
|
200
|
+
def display_message(message)
|
201
|
+
if @output
|
202
|
+
@output.say(message)
|
203
|
+
else
|
204
|
+
puts message
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
192
208
|
def validate_state_transition(action)
|
193
209
|
case action
|
194
210
|
when :pause
|
@@ -229,19 +245,19 @@ module Aidp
|
|
229
245
|
end
|
230
246
|
|
231
247
|
def display_status_info(status)
|
232
|
-
|
233
|
-
|
248
|
+
display_message("Current State: #{@formatter.format_state(status[:state])}")
|
249
|
+
display_message("State Name: #{status[:state_name]}")
|
234
250
|
|
235
251
|
if status[:pause_time]
|
236
|
-
|
252
|
+
display_message("Paused Since: #{status[:pause_time]}")
|
237
253
|
end
|
238
254
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
255
|
+
display_message("\nAvailable Actions:")
|
256
|
+
display_message(" Pause: #{status[:can_pause] ? "Yes" : "No"}")
|
257
|
+
display_message(" Resume: #{status[:can_resume] ? "Yes" : "No"}")
|
258
|
+
display_message(" Cancel: #{status[:can_cancel] ? "Yes" : "No"}")
|
259
|
+
display_message(" Stop: #{status[:can_stop] ? "Yes" : "No"}")
|
260
|
+
display_message(" Complete: #{status[:can_complete] ? "Yes" : "No"}")
|
245
261
|
end
|
246
262
|
|
247
263
|
def control_interface_loop
|