aidp 0.5.0 → 0.8.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/README.md +128 -151
- data/bin/aidp +1 -1
- data/lib/aidp/analysis/kb_inspector.rb +471 -0
- data/lib/aidp/analysis/seams.rb +159 -0
- data/lib/aidp/analysis/tree_sitter_grammar_loader.rb +480 -0
- data/lib/aidp/analysis/tree_sitter_scan.rb +686 -0
- data/lib/aidp/analyze/error_handler.rb +2 -78
- data/lib/aidp/analyze/json_file_storage.rb +292 -0
- data/lib/aidp/analyze/progress.rb +12 -0
- data/lib/aidp/analyze/progress_visualizer.rb +12 -17
- data/lib/aidp/analyze/ruby_maat_integration.rb +13 -31
- data/lib/aidp/analyze/runner.rb +256 -87
- data/lib/aidp/analyze/steps.rb +6 -0
- data/lib/aidp/cli/jobs_command.rb +103 -435
- data/lib/aidp/cli.rb +317 -191
- data/lib/aidp/config.rb +298 -10
- data/lib/aidp/debug_logger.rb +195 -0
- data/lib/aidp/debug_mixin.rb +187 -0
- data/lib/aidp/execute/progress.rb +9 -0
- data/lib/aidp/execute/runner.rb +221 -40
- data/lib/aidp/execute/steps.rb +17 -7
- data/lib/aidp/execute/workflow_selector.rb +211 -0
- data/lib/aidp/harness/completion_checker.rb +268 -0
- data/lib/aidp/harness/condition_detector.rb +1526 -0
- data/lib/aidp/harness/config_loader.rb +373 -0
- data/lib/aidp/harness/config_manager.rb +382 -0
- data/lib/aidp/harness/config_schema.rb +1006 -0
- data/lib/aidp/harness/config_validator.rb +355 -0
- data/lib/aidp/harness/configuration.rb +477 -0
- data/lib/aidp/harness/enhanced_runner.rb +494 -0
- data/lib/aidp/harness/error_handler.rb +616 -0
- data/lib/aidp/harness/provider_config.rb +423 -0
- data/lib/aidp/harness/provider_factory.rb +306 -0
- data/lib/aidp/harness/provider_manager.rb +1269 -0
- data/lib/aidp/harness/provider_type_checker.rb +88 -0
- data/lib/aidp/harness/runner.rb +411 -0
- data/lib/aidp/harness/state/errors.rb +28 -0
- data/lib/aidp/harness/state/metrics.rb +219 -0
- data/lib/aidp/harness/state/persistence.rb +128 -0
- data/lib/aidp/harness/state/provider_state.rb +132 -0
- data/lib/aidp/harness/state/ui_state.rb +68 -0
- data/lib/aidp/harness/state/workflow_state.rb +123 -0
- data/lib/aidp/harness/state_manager.rb +586 -0
- data/lib/aidp/harness/status_display.rb +888 -0
- data/lib/aidp/harness/ui/base.rb +16 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +545 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +252 -0
- data/lib/aidp/harness/ui/error_handler.rb +132 -0
- data/lib/aidp/harness/ui/frame_manager.rb +361 -0
- data/lib/aidp/harness/ui/job_monitor.rb +500 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +311 -0
- data/lib/aidp/harness/ui/navigation/menu_formatter.rb +120 -0
- data/lib/aidp/harness/ui/navigation/menu_item.rb +142 -0
- data/lib/aidp/harness/ui/navigation/menu_state.rb +139 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +202 -0
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +176 -0
- data/lib/aidp/harness/ui/progress_display.rb +280 -0
- data/lib/aidp/harness/ui/question_collector.rb +141 -0
- data/lib/aidp/harness/ui/spinner_group.rb +184 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +152 -0
- data/lib/aidp/harness/ui/status_manager.rb +312 -0
- data/lib/aidp/harness/ui/status_widget.rb +280 -0
- data/lib/aidp/harness/ui/workflow_controller.rb +312 -0
- data/lib/aidp/harness/user_interface.rb +2381 -0
- data/lib/aidp/provider_manager.rb +131 -7
- data/lib/aidp/providers/anthropic.rb +28 -109
- data/lib/aidp/providers/base.rb +170 -0
- data/lib/aidp/providers/cursor.rb +52 -183
- data/lib/aidp/providers/gemini.rb +24 -109
- data/lib/aidp/providers/macos_ui.rb +99 -5
- data/lib/aidp/providers/opencode.rb +194 -0
- data/lib/aidp/storage/csv_storage.rb +172 -0
- data/lib/aidp/storage/file_manager.rb +214 -0
- data/lib/aidp/storage/json_storage.rb +140 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp.rb +56 -35
- data/templates/ANALYZE/06a_tree_sitter_scan.md +217 -0
- data/templates/COMMON/AGENT_BASE.md +11 -0
- data/templates/EXECUTE/00_PRD.md +4 -4
- data/templates/EXECUTE/02_ARCHITECTURE.md +5 -4
- data/templates/EXECUTE/07_TEST_PLAN.md +4 -1
- data/templates/EXECUTE/08_TASKS.md +4 -4
- data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +4 -4
- data/templates/README.md +279 -0
- data/templates/aidp-development.yml.example +373 -0
- data/templates/aidp-minimal.yml.example +48 -0
- data/templates/aidp-production.yml.example +475 -0
- data/templates/aidp.yml.example +598 -0
- metadata +106 -64
- data/lib/aidp/analyze/agent_personas.rb +0 -71
- data/lib/aidp/analyze/agent_tool_executor.rb +0 -445
- data/lib/aidp/analyze/data_retention_manager.rb +0 -426
- data/lib/aidp/analyze/database.rb +0 -260
- data/lib/aidp/analyze/dependencies.rb +0 -335
- data/lib/aidp/analyze/export_manager.rb +0 -425
- data/lib/aidp/analyze/focus_guidance.rb +0 -517
- data/lib/aidp/analyze/incremental_analyzer.rb +0 -543
- data/lib/aidp/analyze/language_analysis_strategies.rb +0 -897
- data/lib/aidp/analyze/large_analysis_progress.rb +0 -504
- data/lib/aidp/analyze/memory_manager.rb +0 -365
- data/lib/aidp/analyze/metrics_storage.rb +0 -336
- data/lib/aidp/analyze/parallel_processor.rb +0 -460
- data/lib/aidp/analyze/performance_optimizer.rb +0 -694
- data/lib/aidp/analyze/repository_chunker.rb +0 -704
- data/lib/aidp/analyze/static_analysis_detector.rb +0 -577
- data/lib/aidp/analyze/storage.rb +0 -662
- data/lib/aidp/analyze/tool_configuration.rb +0 -456
- data/lib/aidp/analyze/tool_modernization.rb +0 -750
- data/lib/aidp/database/pg_adapter.rb +0 -148
- data/lib/aidp/database_config.rb +0 -69
- data/lib/aidp/database_connection.rb +0 -72
- data/lib/aidp/database_migration.rb +0 -158
- data/lib/aidp/job_manager.rb +0 -41
- data/lib/aidp/jobs/base_job.rb +0 -47
- data/lib/aidp/jobs/provider_execution_job.rb +0 -96
- data/lib/aidp/project_detector.rb +0 -117
- data/lib/aidp/providers/agent_supervisor.rb +0 -348
- data/lib/aidp/providers/supervised_base.rb +0 -317
- data/lib/aidp/providers/supervised_cursor.rb +0 -22
- data/lib/aidp/sync.rb +0 -13
- data/lib/aidp/workspace.rb +0 -19
@@ -0,0 +1,494 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "ui/enhanced_tui"
|
4
|
+
require_relative "ui/enhanced_workflow_selector"
|
5
|
+
require_relative "ui/job_monitor"
|
6
|
+
require_relative "ui/workflow_controller"
|
7
|
+
require_relative "ui/progress_display"
|
8
|
+
require_relative "ui/status_widget"
|
9
|
+
|
10
|
+
module Aidp
|
11
|
+
module Harness
|
12
|
+
# Enhanced harness runner with modern TTY-based TUI
|
13
|
+
class EnhancedRunner
|
14
|
+
STATES = {
|
15
|
+
idle: "idle",
|
16
|
+
running: "running",
|
17
|
+
paused: "paused",
|
18
|
+
waiting_for_user: "waiting_for_user",
|
19
|
+
waiting_for_rate_limit: "waiting_for_rate_limit",
|
20
|
+
stopped: "stopped",
|
21
|
+
completed: "completed",
|
22
|
+
error: "error"
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
def initialize(project_dir, mode = :analyze, options = {})
|
26
|
+
@project_dir = project_dir
|
27
|
+
@mode = mode.to_sym
|
28
|
+
@options = options
|
29
|
+
@state = STATES[:idle]
|
30
|
+
@start_time = nil
|
31
|
+
@current_step = nil
|
32
|
+
@current_provider = nil
|
33
|
+
@user_input = options[:user_input] || {}
|
34
|
+
@user_input = {} if @user_input.nil? # Ensure it's never nil
|
35
|
+
@execution_log = []
|
36
|
+
|
37
|
+
# Store workflow configuration
|
38
|
+
@selected_steps = options[:selected_steps] || []
|
39
|
+
@workflow_type = options[:workflow_type] || :default
|
40
|
+
|
41
|
+
# Initialize enhanced TUI components
|
42
|
+
@tui = UI::EnhancedTUI.new
|
43
|
+
@workflow_selector = UI::EnhancedWorkflowSelector.new(@tui)
|
44
|
+
@job_monitor = UI::JobMonitor.new
|
45
|
+
@workflow_controller = UI::WorkflowController.new
|
46
|
+
@progress_display = UI::ProgressDisplay.new
|
47
|
+
@status_widget = UI::StatusWidget.new
|
48
|
+
|
49
|
+
# Initialize other components
|
50
|
+
@configuration = Configuration.new(project_dir)
|
51
|
+
@state_manager = StateManager.new(project_dir, @mode)
|
52
|
+
@condition_detector = ConditionDetector.new
|
53
|
+
@provider_manager = ProviderManager.new(@configuration)
|
54
|
+
@error_handler = ErrorHandler.new(@provider_manager, @configuration)
|
55
|
+
@completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Main execution method with enhanced TUI
|
59
|
+
def run
|
60
|
+
@state = STATES[:running]
|
61
|
+
@start_time = Time.now
|
62
|
+
|
63
|
+
@tui.show_message("🚀 Starting #{@mode.to_s.capitalize} Mode", :info)
|
64
|
+
|
65
|
+
begin
|
66
|
+
# Start TUI display loop
|
67
|
+
@tui.start_display_loop
|
68
|
+
|
69
|
+
# Load existing state if resuming
|
70
|
+
# Temporarily disabled to test
|
71
|
+
# load_state if @state_manager.has_state?
|
72
|
+
|
73
|
+
# Get the appropriate runner for the mode
|
74
|
+
runner = get_mode_runner
|
75
|
+
|
76
|
+
# Register main workflow job
|
77
|
+
register_workflow_job
|
78
|
+
|
79
|
+
# Show initial workflow status
|
80
|
+
show_workflow_status(runner)
|
81
|
+
|
82
|
+
# Show mode-specific feedback
|
83
|
+
show_mode_specific_feedback
|
84
|
+
|
85
|
+
# Main execution loop
|
86
|
+
loop do
|
87
|
+
break if should_stop?
|
88
|
+
|
89
|
+
# Check for pause conditions
|
90
|
+
if should_pause?
|
91
|
+
handle_pause_condition
|
92
|
+
next
|
93
|
+
end
|
94
|
+
|
95
|
+
# Get next step to execute with spinner
|
96
|
+
next_step = show_step_spinner("Finding next step to execute...") do
|
97
|
+
get_next_step(runner)
|
98
|
+
end
|
99
|
+
break unless next_step
|
100
|
+
|
101
|
+
# Execute the step with enhanced TUI integration
|
102
|
+
execute_step_with_enhanced_tui(runner, next_step)
|
103
|
+
|
104
|
+
# Update state
|
105
|
+
update_state
|
106
|
+
end
|
107
|
+
|
108
|
+
# Mark workflow as completed
|
109
|
+
complete_workflow_job
|
110
|
+
|
111
|
+
# Check completion criteria
|
112
|
+
if all_steps_completed?(runner)
|
113
|
+
completion_status = @completion_checker.completion_status
|
114
|
+
if completion_status[:all_complete]
|
115
|
+
@state = STATES[:completed]
|
116
|
+
@workflow_controller.complete_workflow("All steps completed successfully")
|
117
|
+
@tui.show_message("🎉 Harness completed successfully - all criteria met", :success)
|
118
|
+
else
|
119
|
+
@tui.show_message("⚠️ Steps completed but completion criteria not met", :warning)
|
120
|
+
handle_completion_criteria_not_met(completion_status)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
rescue => e
|
124
|
+
@state = STATES[:error]
|
125
|
+
# Single error message - don't duplicate
|
126
|
+
@tui.show_message("❌ Error: #{e.message}", :error)
|
127
|
+
ensure
|
128
|
+
# Save state before exiting
|
129
|
+
save_state
|
130
|
+
@tui.stop_display_loop
|
131
|
+
cleanup
|
132
|
+
end
|
133
|
+
|
134
|
+
{status: @state, message: get_completion_message}
|
135
|
+
end
|
136
|
+
|
137
|
+
# Enhanced step execution with TUI integration
|
138
|
+
def execute_step_with_enhanced_tui(runner, step_name)
|
139
|
+
@current_step = step_name
|
140
|
+
@tui.show_message("🔄 Executing step: #{step_name}", :info)
|
141
|
+
|
142
|
+
# Register step as a job
|
143
|
+
step_job_id = "step_#{step_name}"
|
144
|
+
step_job_data = {
|
145
|
+
name: step_name,
|
146
|
+
status: :running,
|
147
|
+
progress: 0,
|
148
|
+
provider: @current_provider || "unknown",
|
149
|
+
message: "Starting execution..."
|
150
|
+
}
|
151
|
+
@tui.add_job(step_job_id, step_job_data)
|
152
|
+
|
153
|
+
# Show step execution display
|
154
|
+
@tui.show_step_execution(step_name, :starting, {provider: @current_provider})
|
155
|
+
|
156
|
+
# Mark step as in progress
|
157
|
+
runner.mark_step_in_progress(step_name)
|
158
|
+
|
159
|
+
# Get current provider
|
160
|
+
@current_provider = @provider_manager.current_provider
|
161
|
+
|
162
|
+
# Execute the step with error handling and spinner
|
163
|
+
start_time = Time.now
|
164
|
+
|
165
|
+
# Show spinner while executing the step
|
166
|
+
spinner_message = "Executing #{step_name}..."
|
167
|
+
result = show_step_spinner(spinner_message) do
|
168
|
+
@error_handler.execute_with_retry do
|
169
|
+
step_options = @options.merge(user_input: @user_input)
|
170
|
+
runner.run_step(step_name, step_options)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
duration = Time.now - start_time
|
174
|
+
|
175
|
+
# Update step job status
|
176
|
+
if result && result[:status] == "completed"
|
177
|
+
@tui.update_job(step_job_id, {
|
178
|
+
status: :completed,
|
179
|
+
progress: 100,
|
180
|
+
message: "Completed successfully"
|
181
|
+
})
|
182
|
+
@tui.show_step_execution(step_name, :completed, {duration: duration})
|
183
|
+
runner.mark_step_completed(step_name)
|
184
|
+
else
|
185
|
+
@tui.update_job(step_job_id, {
|
186
|
+
status: :failed,
|
187
|
+
message: result&.dig(:error) || "Step execution failed"
|
188
|
+
})
|
189
|
+
@tui.show_step_execution(step_name, :failed, {
|
190
|
+
error: result&.dig(:error) || "Unknown error"
|
191
|
+
})
|
192
|
+
end
|
193
|
+
|
194
|
+
# Check for conditions that require user interaction
|
195
|
+
if @condition_detector.needs_user_feedback?(result)
|
196
|
+
handle_user_feedback_request_with_tui(result)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Check for rate limiting
|
200
|
+
if @condition_detector.is_rate_limited?(result)
|
201
|
+
handle_rate_limit(result)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Remove job after a delay to show completion
|
205
|
+
Thread.new do
|
206
|
+
sleep 2
|
207
|
+
@tui.remove_job(step_job_id)
|
208
|
+
end
|
209
|
+
|
210
|
+
result
|
211
|
+
end
|
212
|
+
|
213
|
+
# Enhanced user feedback handling
|
214
|
+
def handle_user_feedback_request_with_tui(result)
|
215
|
+
@state = STATES[:waiting_for_user]
|
216
|
+
@workflow_controller.pause_workflow("Waiting for user feedback")
|
217
|
+
@tui.show_message("⏸️ Waiting for user feedback", :warning)
|
218
|
+
|
219
|
+
# Extract questions from result
|
220
|
+
questions = @condition_detector.extract_questions(result)
|
221
|
+
|
222
|
+
# Show input area
|
223
|
+
@tui.show_input_area("Please provide feedback:")
|
224
|
+
|
225
|
+
# Collect user input using enhanced TUI
|
226
|
+
user_responses = {}
|
227
|
+
questions.each_with_index do |question_data, index|
|
228
|
+
question_number = question_data[:number] || (index + 1)
|
229
|
+
prompt = "Question #{question_number}: #{question_data[:question]}"
|
230
|
+
|
231
|
+
response = @tui.get_user_input(prompt)
|
232
|
+
user_responses["question_#{question_number}"] = response
|
233
|
+
end
|
234
|
+
|
235
|
+
# Store user input
|
236
|
+
@user_input.merge!(user_responses)
|
237
|
+
user_responses.each do |key, value|
|
238
|
+
@state_manager.add_user_input(key, value)
|
239
|
+
end
|
240
|
+
|
241
|
+
@state = STATES[:running]
|
242
|
+
@workflow_controller.resume_workflow("User feedback collected")
|
243
|
+
@tui.show_message("✅ User feedback collected", :success)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Enhanced workflow status display
|
247
|
+
def show_workflow_status(runner)
|
248
|
+
workflow_data = {
|
249
|
+
workflow_type: @workflow_type,
|
250
|
+
steps: @selected_steps || runner.all_steps,
|
251
|
+
completed_steps: runner.progress.completed_steps.size,
|
252
|
+
current_step: runner.progress.current_step,
|
253
|
+
progress_percentage: calculate_progress_percentage(runner)
|
254
|
+
}
|
255
|
+
|
256
|
+
@tui.show_workflow_status(workflow_data)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Job monitoring integration
|
260
|
+
def register_workflow_job
|
261
|
+
job_data = {
|
262
|
+
name: "Main Workflow",
|
263
|
+
status: :running,
|
264
|
+
progress: 0,
|
265
|
+
provider: @current_provider || "unknown",
|
266
|
+
message: "Starting workflow execution..."
|
267
|
+
}
|
268
|
+
|
269
|
+
@tui.add_job("main_workflow", job_data)
|
270
|
+
end
|
271
|
+
|
272
|
+
def complete_workflow_job
|
273
|
+
@tui.update_job("main_workflow", {
|
274
|
+
status: :completed,
|
275
|
+
progress: 100,
|
276
|
+
message: "Workflow completed"
|
277
|
+
})
|
278
|
+
end
|
279
|
+
|
280
|
+
# Control methods
|
281
|
+
|
282
|
+
def stop
|
283
|
+
@state = STATES[:stopped]
|
284
|
+
@workflow_controller.stop_workflow("User requested stop")
|
285
|
+
@tui.show_message("⏹️ Harness stopped by user", :warning)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Status methods
|
289
|
+
def status
|
290
|
+
{
|
291
|
+
state: @state,
|
292
|
+
mode: @mode,
|
293
|
+
current_step: @current_step,
|
294
|
+
current_provider: @current_provider,
|
295
|
+
start_time: @start_time,
|
296
|
+
duration: @start_time ? Time.now - @start_time : 0,
|
297
|
+
user_input_count: @user_input.size,
|
298
|
+
execution_log_count: @execution_log.size,
|
299
|
+
jobs_count: @tui.instance_variable_get(:@jobs).size
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
def show_step_spinner(message)
|
306
|
+
# Use the unified spinner helper
|
307
|
+
Aidp::Harness::UI.with_processing_spinner(message) do
|
308
|
+
yield
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def get_mode_runner
|
313
|
+
case @mode
|
314
|
+
when :analyze
|
315
|
+
Aidp::Analyze::Runner.new(@project_dir, self)
|
316
|
+
when :execute
|
317
|
+
Aidp::Execute::Runner.new(@project_dir, self)
|
318
|
+
else
|
319
|
+
raise ArgumentError, "Unsupported mode: #{@mode}"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def get_next_step(runner)
|
324
|
+
runner.next_step
|
325
|
+
end
|
326
|
+
|
327
|
+
def should_stop?
|
328
|
+
@state == STATES[:stopped] ||
|
329
|
+
@state == STATES[:completed] ||
|
330
|
+
@state == STATES[:error]
|
331
|
+
end
|
332
|
+
|
333
|
+
def should_pause?
|
334
|
+
@state == STATES[:paused] ||
|
335
|
+
@state == STATES[:waiting_for_user] ||
|
336
|
+
@state == STATES[:waiting_for_rate_limit]
|
337
|
+
end
|
338
|
+
|
339
|
+
def handle_pause_condition
|
340
|
+
case @state
|
341
|
+
when STATES[:paused]
|
342
|
+
sleep(1)
|
343
|
+
when STATES[:waiting_for_user]
|
344
|
+
# User interface handles this
|
345
|
+
nil
|
346
|
+
when STATES[:waiting_for_rate_limit]
|
347
|
+
# Rate limit handling
|
348
|
+
nil
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def all_steps_completed?(runner)
|
353
|
+
runner.all_steps_completed?
|
354
|
+
end
|
355
|
+
|
356
|
+
def calculate_progress_percentage(runner)
|
357
|
+
total_steps = runner.all_steps.size
|
358
|
+
completed_steps = runner.progress.completed_steps.size
|
359
|
+
return 0 if total_steps == 0
|
360
|
+
(completed_steps.to_f / total_steps * 100).round(2)
|
361
|
+
end
|
362
|
+
|
363
|
+
def update_state
|
364
|
+
@state_manager.update_state({
|
365
|
+
state: @state,
|
366
|
+
current_step: @current_step,
|
367
|
+
current_provider: @current_provider,
|
368
|
+
user_input: @user_input,
|
369
|
+
last_updated: Time.now
|
370
|
+
})
|
371
|
+
end
|
372
|
+
|
373
|
+
def load_state
|
374
|
+
if @state_manager.has_state?
|
375
|
+
state = @state_manager.load_state
|
376
|
+
# Ensure state is not nil before accessing it
|
377
|
+
if state.is_a?(Hash)
|
378
|
+
@user_input.merge!(state[:user_input] || {})
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def save_state
|
384
|
+
@state_manager.save_state({
|
385
|
+
state: @state,
|
386
|
+
current_step: @current_step,
|
387
|
+
current_provider: @current_provider,
|
388
|
+
user_input: @user_input,
|
389
|
+
last_updated: Time.now
|
390
|
+
})
|
391
|
+
end
|
392
|
+
|
393
|
+
def show_mode_specific_feedback
|
394
|
+
case @mode
|
395
|
+
when :analyze
|
396
|
+
@tui.show_message("🔬 Starting codebase analysis...", :info)
|
397
|
+
@tui.show_message("Press 'j' to view background jobs, 'h' for help", :info)
|
398
|
+
when :execute
|
399
|
+
@tui.show_message("🏗️ Starting development workflow...", :info)
|
400
|
+
@tui.show_message("Press 'j' to view background jobs, 'h' for help", :info)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def handle_error(error)
|
405
|
+
# Single comprehensive error report
|
406
|
+
@tui.show_message("❌ Harness error: #{error.message}", :error)
|
407
|
+
@tui.show_message("Error type: #{error.class.name}", :error)
|
408
|
+
|
409
|
+
# Log error details for debugging
|
410
|
+
@execution_log << {
|
411
|
+
timestamp: Time.now,
|
412
|
+
level: :error,
|
413
|
+
message: error.message,
|
414
|
+
backtrace: error.backtrace&.first(5)
|
415
|
+
}
|
416
|
+
|
417
|
+
# Show backtrace in debug mode only
|
418
|
+
if ENV["DEBUG"]
|
419
|
+
@tui.show_message("Backtrace: #{error.backtrace&.first(3)&.join("\n")}", :error)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def handle_completion_criteria_not_met(completion_status)
|
424
|
+
@tui.show_message("Completion criteria not met: #{completion_status[:summary]}", :warning)
|
425
|
+
|
426
|
+
if @tui.get_confirmation("Continue anyway? This may indicate issues that should be addressed.", default: false)
|
427
|
+
@state = STATES[:completed]
|
428
|
+
@workflow_controller.complete_workflow("Completed with user override")
|
429
|
+
@tui.show_message("✅ Harness completed with user override", :success)
|
430
|
+
else
|
431
|
+
@state = STATES[:error]
|
432
|
+
@workflow_controller.stop_workflow("Completion criteria not met")
|
433
|
+
@tui.show_message("❌ Harness stopped due to unmet completion criteria", :error)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def handle_rate_limit(_result)
|
438
|
+
@state = STATES[:waiting_for_rate_limit]
|
439
|
+
@tui.show_message("⏳ Rate limit detected, switching provider", :warning)
|
440
|
+
|
441
|
+
@provider_manager.mark_rate_limited(@current_provider)
|
442
|
+
next_provider = @provider_manager.switch_provider
|
443
|
+
@current_provider = next_provider
|
444
|
+
|
445
|
+
if next_provider
|
446
|
+
@state = STATES[:running]
|
447
|
+
@tui.show_message("🔄 Switched to provider: #{next_provider}", :info)
|
448
|
+
else
|
449
|
+
wait_for_rate_limit_reset
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
def wait_for_rate_limit_reset
|
454
|
+
reset_time = @provider_manager.next_reset_time
|
455
|
+
if reset_time
|
456
|
+
@tui.show_message("⏰ Waiting for rate limit reset at #{reset_time}", :warning)
|
457
|
+
sleep_until_reset(reset_time)
|
458
|
+
@state = STATES[:running]
|
459
|
+
else
|
460
|
+
@state = STATES[:error]
|
461
|
+
raise "All providers rate limited with no reset time available"
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def sleep_until_reset(reset_time)
|
466
|
+
while Time.now < reset_time && @state == STATES[:waiting_for_rate_limit]
|
467
|
+
remaining = reset_time - Time.now
|
468
|
+
@tui.show_message("⏳ Rate limit reset in #{remaining.to_i} seconds", :info)
|
469
|
+
sleep(1)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def cleanup
|
474
|
+
# Cleanup any remaining jobs
|
475
|
+
@tui.instance_variable_get(:@jobs).keys.each do |job_id|
|
476
|
+
@tui.remove_job(job_id)
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def get_completion_message
|
481
|
+
case @state
|
482
|
+
when STATES[:completed]
|
483
|
+
"Harness completed successfully"
|
484
|
+
when STATES[:stopped]
|
485
|
+
"Harness stopped by user"
|
486
|
+
when STATES[:error]
|
487
|
+
"Harness encountered an error"
|
488
|
+
else
|
489
|
+
"Harness finished"
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|