Class: Aidp::Harness::EnhancedRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/harness/enhanced_runner.rb

Overview

Enhanced harness runner with modern TTY-based TUI

Defined Under Namespace

Classes: Sleeper

Constant Summary collapse

STATES =
{
  idle: "idle",
  running: "running",
  paused: "paused",
  waiting_for_user: "waiting_for_user",
  waiting_for_rate_limit: "waiting_for_rate_limit",
  stopped: "stopped",
  completed: "completed",
  error: "error"
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_dir, mode = :analyze, options = {}, prompt: TTY::Prompt.new, sleeper: Sleeper.new) ⇒ EnhancedRunner

Returns a new instance of EnhancedRunner.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/aidp/harness/enhanced_runner.rb', line 33

def initialize(project_dir, mode = :analyze, options = {}, prompt: TTY::Prompt.new, sleeper: Sleeper.new)
  @project_dir = project_dir
  @mode = mode.to_sym
  @options = options
  @prompt = prompt
  @sleeper = sleeper
  @state = STATES[:idle]
  @start_time = nil
  @current_step = nil
  @current_provider = nil
  @user_input = options[:user_input] || {}
  @user_input = {} if @user_input.nil? # Ensure it's never nil
  @execution_log = []

  # Store workflow configuration
  @selected_steps = options[:selected_steps] || []
  @workflow_type = options[:workflow_type] || :default

  # Initialize enhanced TUI components (with dependency injection)
  @tui = options[:tui] || UI::EnhancedTUI.new
  @workflow_selector = options[:workflow_selector] || UI::EnhancedWorkflowSelector.new(@tui)
  @job_monitor = options[:job_monitor] || UI::JobMonitor.new
  @workflow_controller = options[:workflow_controller] || UI::WorkflowController.new
  @progress_display = options[:progress_display] || UI::ProgressDisplay.new
  @status_widget = options[:status_widget] || UI::StatusWidget.new

  # Initialize other components (with dependency injection)
  @configuration = options[:configuration] || Configuration.new(project_dir)
  @state_manager = options[:state_manager] || StateManager.new(project_dir, @mode)
  @provider_manager = options[:provider_manager] || ProviderManager.new(@configuration, prompt: @prompt)

  # Use ZFC-enabled condition detector
  # ZfcConditionDetector will create its own ProviderFactory if needed
  # Falls back to legacy pattern matching when ZFC is disabled
  if options[:condition_detector]
    @condition_detector = options[:condition_detector]
  else
    require_relative "zfc_condition_detector"
    @condition_detector = ZfcConditionDetector.new(@configuration)
  end

  @error_handler = options[:error_handler] || ErrorHandler.new(@provider_manager, @configuration)
  @completion_checker = options[:completion_checker] || CompletionChecker.new(@project_dir, @workflow_type)
end

Instance Attribute Details

#current_stepObject (readonly)

Get current step



84
85
86
# File 'lib/aidp/harness/enhanced_runner.rb', line 84

def current_step
  @current_step
end

#provider_managerObject (readonly)

Get provider manager



97
98
99
# File 'lib/aidp/harness/enhanced_runner.rb', line 97

def provider_manager
  @provider_manager
end

Instance Method Details

#complete_workflow_jobObject



330
331
332
333
334
335
336
# File 'lib/aidp/harness/enhanced_runner.rb', line 330

def complete_workflow_job
  @tui.update_job("main_workflow", {
    status: :completed,
    progress: 100,
    message: "Workflow completed"
  })
end

#current_providerObject

Get current provider (delegate to provider manager)



79
80
81
# File 'lib/aidp/harness/enhanced_runner.rb', line 79

def current_provider
  @current_provider || @provider_manager&.current_provider || "unknown"
end

#execute_step_with_enhanced_tui(runner, step_name) ⇒ Object

Enhanced step execution with TUI integration



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/aidp/harness/enhanced_runner.rb', line 182

def execute_step_with_enhanced_tui(runner, step_name)
  @current_step = step_name
  @tui.show_message("πŸ”„ Executing step: #{step_name}", :info)

  # Register step as a job
  step_job_id = "step_#{step_name}"
  step_job_data = {
    name: step_name,
    status: :running,
    progress: 0,
    provider: @current_provider || "unknown",
    message: "Starting execution..."
  }
  @tui.add_job(step_job_id, step_job_data)

  # Show step execution display
  @tui.show_step_execution(step_name, :starting, {provider: @current_provider})

  # Mark step as in progress
  runner.mark_step_in_progress(step_name)

  # Get current provider
  @current_provider = @provider_manager.current_provider

  # Execute the step with error handling and spinner
  start_time = Time.now

  # Show spinner while executing the step
  spinner_message = "Executing #{step_name}..."
  result = show_step_spinner(spinner_message) do
    @error_handler.execute_with_retry do
      step_options = @options.merge(user_input: @user_input)
      # Determine execution directory (workstream path if set)
      exec_dir = begin
        if @state_manager.respond_to?(:current_workstream_path)
          @state_manager.current_workstream_path
        else
          @project_dir
        end
      rescue
        @project_dir
      end
      # Execute step within the chosen directory for proper isolation
      Dir.chdir(exec_dir) do
        runner.run_step(step_name, step_options)
      end
    end
  end
  duration = Time.now - start_time

  # Update step job status
  if result && result[:status] == "completed"
    @tui.update_job(step_job_id, {
      status: :completed,
      progress: 100,
      message: "Completed successfully"
    })
    @tui.show_step_execution(step_name, :completed, {duration: duration})
    runner.mark_step_completed(step_name)
  else
    @tui.update_job(step_job_id, {
      status: :failed,
      message: result&.dig(:error) || "Step execution failed"
    })
    @tui.show_step_execution(step_name, :failed, {
      error: result&.dig(:error) || "Unknown error"
    })
  end

  # Check for conditions that require user interaction
  if @condition_detector.needs_user_feedback?(result)
    handle_user_feedback_request_with_tui(result)
  end

  # Check for rate limiting
  if @condition_detector.is_rate_limited?(result)
    handle_rate_limit(result)
  end

  # Remove job after a delay to show completion
  # UI delay to let user see completion status before removal
  Thread.new do
    @sleeper.sleep(2) # UI timing delay
    @tui.remove_job(step_job_id)
  end

  result
end

#execution_logObject

Get execution log



92
93
94
# File 'lib/aidp/harness/enhanced_runner.rb', line 92

def execution_log
  @execution_log || []
end

#handle_user_feedback_request_with_tui(result) ⇒ Object

Enhanced user feedback handling



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/aidp/harness/enhanced_runner.rb', line 272

def handle_user_feedback_request_with_tui(result)
  @state = STATES[:waiting_for_user]
  @workflow_controller.pause_workflow("Waiting for user feedback")
  @tui.show_message("⏸️ Waiting for user feedback", :warning)

  # Extract questions from result
  questions = @condition_detector.extract_questions(result)

  # Show input area
  @tui.show_input_area("Please provide feedback:")

  # Collect user input using enhanced TUI
  user_responses = {}
  questions.each_with_index do |question_data, index|
    question_number = question_data[:number] || (index + 1)
    prompt = "Question #{question_number}: #{question_data[:question]}"

    response = @tui.get_user_input(prompt)
    user_responses["question_#{question_number}"] = response
  end

  # Store user input
  @user_input.merge!(user_responses)
  user_responses.each do |key, value|
    @state_manager.add_user_input(key, value)
  end

  @state = STATES[:running]
  @workflow_controller.resume_workflow("User feedback collected")
  @tui.show_message("βœ… User feedback collected", :success)
end

#register_workflow_jobObject

Job monitoring integration



318
319
320
321
322
323
324
325
326
327
328
# File 'lib/aidp/harness/enhanced_runner.rb', line 318

def register_workflow_job
  job_data = {
    name: "Main Workflow",
    status: :running,
    progress: 0,
    provider: @current_provider || "unknown",
    message: "Starting workflow execution..."
  }

  @tui.add_job("main_workflow", job_data)
end

#runObject

Main execution method with enhanced TUI



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/aidp/harness/enhanced_runner.rb', line 100

def run
  @state = STATES[:running]
  @start_time = Time.now

  Aidp.logger.info("harness_runner", "Starting harness execution", mode: @mode, workflow_type: @workflow_type, steps_count: @selected_steps.size)

  @tui.show_message("πŸš€ Starting #{@mode.to_s.capitalize} Mode", :info)

  begin
    # Load existing state if resuming
    # Temporarily disabled to test
    # load_state if @state_manager.has_state?

    # Get the appropriate runner for the mode
    runner = get_mode_runner

    # Register main workflow job
    register_workflow_job

    # Show initial workflow status
    show_workflow_status(runner)

    # Show mode-specific feedback
    show_mode_specific_feedback

    # Main execution loop
    loop do
      break if should_stop?

      # Check for pause conditions
      if should_pause?
        handle_pause_condition
        next
      end

      # Get next step to execute with spinner
      next_step = show_step_spinner("Finding next step to execute...") do
        get_next_step(runner)
      end
      break unless next_step

      # Execute the step with enhanced TUI integration
      execute_step_with_enhanced_tui(runner, next_step)

      # Update state
      update_state
    end

    # Mark workflow as completed
    complete_workflow_job

    # Check completion criteria
    if all_steps_completed?(runner)
      completion_status = @completion_checker.completion_status
      if completion_status[:all_complete]
        @state = STATES[:completed]
        @workflow_controller.complete_workflow("All steps completed successfully")
        @tui.show_message("πŸŽ‰ Harness completed successfully - all criteria met", :success)
      else
        @tui.show_message("⚠️ Steps completed but completion criteria not met", :warning)
        handle_completion_criteria_not_met(completion_status)
      end
    end
  rescue Aidp::Errors::ConfigurationError
    # Configuration errors should crash immediately (crash-early principle)
    # Re-raise without catching
    raise
  rescue => e
    @state = STATES[:error]
    # Single error message - don't duplicate
    @tui.show_message("❌ Error: #{e.message}", :error)
  ensure
    # Save state before exiting
    save_state
    @tui.restore_screen
    cleanup
  end

  {status: @state, message: get_completion_message}
end

#show_workflow_status(runner) ⇒ Object

Enhanced workflow status display



305
306
307
308
309
310
311
312
313
314
315
# File 'lib/aidp/harness/enhanced_runner.rb', line 305

def show_workflow_status(runner)
  workflow_data = {
    workflow_type: @workflow_type,
    steps: @selected_steps || runner.all_steps,
    completed_steps: runner.progress.completed_steps.size,
    current_step: runner.progress.current_step,
    progress_percentage: calculate_progress_percentage(runner)
  }

  @tui.show_workflow_status(workflow_data)
end

#statusObject

Status methods



347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/aidp/harness/enhanced_runner.rb', line 347

def status
  {
    state: @state,
    mode: @mode,
    current_step: @current_step,
    current_provider: @current_provider,
    start_time: @start_time,
    duration: @start_time ? Time.now - @start_time : 0,
    user_input_count: @user_input.size,
    execution_log_count: @execution_log.size,
    jobs_count: @tui.instance_variable_get(:@jobs).size
  }
end

#stopObject

Control methods



340
341
342
343
344
# File 'lib/aidp/harness/enhanced_runner.rb', line 340

def stop
  @state = STATES[:stopped]
  @workflow_controller.stop_workflow("User requested stop")
  @tui.show_message("⏹️ Harness stopped by user", :warning)
end

#user_inputObject

Get user input



87
88
89
# File 'lib/aidp/harness/enhanced_runner.rb', line 87

def user_input
  @user_input || {}
end