aidp 0.7.0 → 0.8.1

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -214
  3. data/bin/aidp +1 -1
  4. data/lib/aidp/analysis/kb_inspector.rb +38 -23
  5. data/lib/aidp/analysis/seams.rb +2 -31
  6. data/lib/aidp/analysis/tree_sitter_grammar_loader.rb +1 -13
  7. data/lib/aidp/analysis/tree_sitter_scan.rb +3 -20
  8. data/lib/aidp/analyze/error_handler.rb +2 -75
  9. data/lib/aidp/analyze/json_file_storage.rb +292 -0
  10. data/lib/aidp/analyze/progress.rb +12 -0
  11. data/lib/aidp/analyze/progress_visualizer.rb +12 -17
  12. data/lib/aidp/analyze/ruby_maat_integration.rb +13 -31
  13. data/lib/aidp/analyze/runner.rb +256 -87
  14. data/lib/aidp/cli/jobs_command.rb +100 -432
  15. data/lib/aidp/cli.rb +309 -239
  16. data/lib/aidp/config.rb +298 -10
  17. data/lib/aidp/debug_logger.rb +195 -0
  18. data/lib/aidp/debug_mixin.rb +187 -0
  19. data/lib/aidp/execute/progress.rb +9 -0
  20. data/lib/aidp/execute/runner.rb +221 -40
  21. data/lib/aidp/execute/steps.rb +17 -7
  22. data/lib/aidp/execute/workflow_selector.rb +211 -0
  23. data/lib/aidp/harness/completion_checker.rb +268 -0
  24. data/lib/aidp/harness/condition_detector.rb +1526 -0
  25. data/lib/aidp/harness/config_loader.rb +373 -0
  26. data/lib/aidp/harness/config_manager.rb +382 -0
  27. data/lib/aidp/harness/config_schema.rb +1006 -0
  28. data/lib/aidp/harness/config_validator.rb +355 -0
  29. data/lib/aidp/harness/configuration.rb +477 -0
  30. data/lib/aidp/harness/enhanced_runner.rb +494 -0
  31. data/lib/aidp/harness/error_handler.rb +616 -0
  32. data/lib/aidp/harness/provider_config.rb +423 -0
  33. data/lib/aidp/harness/provider_factory.rb +306 -0
  34. data/lib/aidp/harness/provider_manager.rb +1269 -0
  35. data/lib/aidp/harness/provider_type_checker.rb +88 -0
  36. data/lib/aidp/harness/runner.rb +411 -0
  37. data/lib/aidp/harness/state/errors.rb +28 -0
  38. data/lib/aidp/harness/state/metrics.rb +219 -0
  39. data/lib/aidp/harness/state/persistence.rb +128 -0
  40. data/lib/aidp/harness/state/provider_state.rb +132 -0
  41. data/lib/aidp/harness/state/ui_state.rb +68 -0
  42. data/lib/aidp/harness/state/workflow_state.rb +123 -0
  43. data/lib/aidp/harness/state_manager.rb +586 -0
  44. data/lib/aidp/harness/status_display.rb +888 -0
  45. data/lib/aidp/harness/ui/base.rb +16 -0
  46. data/lib/aidp/harness/ui/enhanced_tui.rb +545 -0
  47. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +252 -0
  48. data/lib/aidp/harness/ui/error_handler.rb +132 -0
  49. data/lib/aidp/harness/ui/frame_manager.rb +361 -0
  50. data/lib/aidp/harness/ui/job_monitor.rb +500 -0
  51. data/lib/aidp/harness/ui/navigation/main_menu.rb +311 -0
  52. data/lib/aidp/harness/ui/navigation/menu_formatter.rb +120 -0
  53. data/lib/aidp/harness/ui/navigation/menu_item.rb +142 -0
  54. data/lib/aidp/harness/ui/navigation/menu_state.rb +139 -0
  55. data/lib/aidp/harness/ui/navigation/submenu.rb +202 -0
  56. data/lib/aidp/harness/ui/navigation/workflow_selector.rb +176 -0
  57. data/lib/aidp/harness/ui/progress_display.rb +280 -0
  58. data/lib/aidp/harness/ui/question_collector.rb +141 -0
  59. data/lib/aidp/harness/ui/spinner_group.rb +184 -0
  60. data/lib/aidp/harness/ui/spinner_helper.rb +152 -0
  61. data/lib/aidp/harness/ui/status_manager.rb +312 -0
  62. data/lib/aidp/harness/ui/status_widget.rb +280 -0
  63. data/lib/aidp/harness/ui/workflow_controller.rb +312 -0
  64. data/lib/aidp/harness/user_interface.rb +2381 -0
  65. data/lib/aidp/provider_manager.rb +131 -7
  66. data/lib/aidp/providers/anthropic.rb +28 -103
  67. data/lib/aidp/providers/base.rb +170 -0
  68. data/lib/aidp/providers/cursor.rb +52 -181
  69. data/lib/aidp/providers/gemini.rb +24 -107
  70. data/lib/aidp/providers/macos_ui.rb +99 -5
  71. data/lib/aidp/providers/opencode.rb +194 -0
  72. data/lib/aidp/storage/csv_storage.rb +172 -0
  73. data/lib/aidp/storage/file_manager.rb +214 -0
  74. data/lib/aidp/storage/json_storage.rb +140 -0
  75. data/lib/aidp/version.rb +1 -1
  76. data/lib/aidp.rb +54 -39
  77. data/templates/COMMON/AGENT_BASE.md +11 -0
  78. data/templates/EXECUTE/00_PRD.md +4 -4
  79. data/templates/EXECUTE/02_ARCHITECTURE.md +5 -4
  80. data/templates/EXECUTE/07_TEST_PLAN.md +4 -1
  81. data/templates/EXECUTE/08_TASKS.md +4 -4
  82. data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +4 -4
  83. data/templates/README.md +279 -0
  84. data/templates/aidp-development.yml.example +373 -0
  85. data/templates/aidp-minimal.yml.example +48 -0
  86. data/templates/aidp-production.yml.example +475 -0
  87. data/templates/aidp.yml.example +598 -0
  88. metadata +93 -69
  89. data/lib/aidp/analyze/agent_personas.rb +0 -71
  90. data/lib/aidp/analyze/agent_tool_executor.rb +0 -439
  91. data/lib/aidp/analyze/data_retention_manager.rb +0 -421
  92. data/lib/aidp/analyze/database.rb +0 -260
  93. data/lib/aidp/analyze/dependencies.rb +0 -335
  94. data/lib/aidp/analyze/export_manager.rb +0 -418
  95. data/lib/aidp/analyze/focus_guidance.rb +0 -517
  96. data/lib/aidp/analyze/incremental_analyzer.rb +0 -533
  97. data/lib/aidp/analyze/language_analysis_strategies.rb +0 -897
  98. data/lib/aidp/analyze/large_analysis_progress.rb +0 -499
  99. data/lib/aidp/analyze/memory_manager.rb +0 -339
  100. data/lib/aidp/analyze/metrics_storage.rb +0 -336
  101. data/lib/aidp/analyze/parallel_processor.rb +0 -454
  102. data/lib/aidp/analyze/performance_optimizer.rb +0 -691
  103. data/lib/aidp/analyze/repository_chunker.rb +0 -697
  104. data/lib/aidp/analyze/static_analysis_detector.rb +0 -577
  105. data/lib/aidp/analyze/storage.rb +0 -655
  106. data/lib/aidp/analyze/tool_configuration.rb +0 -441
  107. data/lib/aidp/analyze/tool_modernization.rb +0 -750
  108. data/lib/aidp/database/pg_adapter.rb +0 -148
  109. data/lib/aidp/database_config.rb +0 -69
  110. data/lib/aidp/database_connection.rb +0 -72
  111. data/lib/aidp/job_manager.rb +0 -41
  112. data/lib/aidp/jobs/base_job.rb +0 -45
  113. data/lib/aidp/jobs/provider_execution_job.rb +0 -83
  114. data/lib/aidp/project_detector.rb +0 -117
  115. data/lib/aidp/providers/agent_supervisor.rb +0 -348
  116. data/lib/aidp/providers/supervised_base.rb +0 -317
  117. data/lib/aidp/providers/supervised_cursor.rb +0 -22
  118. data/lib/aidp/sync.rb +0 -13
  119. data/lib/aidp/workspace.rb +0 -19
@@ -1,348 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "timeout"
4
- require "open3"
5
-
6
- module Aidp
7
- module Providers
8
- # Supervisor for managing agent execution with progressive warnings instead of hard timeouts
9
- class AgentSupervisor
10
- # Execution states
11
- STATES = {
12
- idle: "⏳",
13
- starting: "🚀",
14
- running: "🔄",
15
- warning: "⚠️",
16
- user_aborted: "🛑",
17
- completed: "✅",
18
- failed: "❌"
19
- }.freeze
20
-
21
- attr_reader :state, :start_time, :end_time, :duration, :output, :error_output, :exit_code
22
-
23
- def initialize(command, timeout_seconds: 300, debug: false)
24
- @command = command
25
- @timeout_seconds = timeout_seconds
26
- @debug = debug
27
- @state = :idle
28
- @start_time = nil
29
- @end_time = nil
30
- @duration = 0
31
- @output = ""
32
- @error_output = ""
33
- @exit_code = nil
34
- @process_pid = nil
35
- @output_count = 0
36
- @last_output_time = nil
37
- @supervisor_thread = nil
38
- @output_threads = []
39
- @warning_shown = false
40
- @user_aborted = false
41
- end
42
-
43
- # Execute the command with supervision
44
- def execute(input = nil)
45
- @state = :starting
46
- @start_time = Time.now
47
- @last_output_time = @start_time
48
-
49
- puts "🚀 Starting agent execution (will warn at #{@timeout_seconds}s)"
50
-
51
- begin
52
- # Start the process
53
- Open3.popen3(*@command) do |stdin, stdout, stderr, wait|
54
- @process_pid = wait.pid
55
- @state = :running
56
-
57
- # Send input if provided
58
- if input
59
- stdin.puts input
60
- stdin.close
61
- end
62
-
63
- # Start timeout thread that will warn but not kill
64
- timeout_thread = Thread.new do
65
- sleep @timeout_seconds
66
- if @state == :running && !@warning_shown
67
- show_timeout_warning
68
- end
69
- end
70
-
71
- # Start supervisor thread
72
- start_supervisor_thread(wait)
73
-
74
- # Start output collection threads
75
- start_output_threads(stdout, stderr)
76
-
77
- # Wait for completion
78
- result = wait_for_completion(wait)
79
-
80
- # Kill timeout thread since we're done
81
- timeout_thread.kill
82
-
83
- # Clean up threads
84
- cleanup_threads
85
-
86
- @end_time = Time.now
87
- @duration = @end_time - @start_time
88
-
89
- return result
90
- end
91
- rescue => e
92
- @state = :failed
93
- @end_time = Time.now
94
- @duration = @end_time - @start_time if @start_time
95
- puts "❌ Agent execution failed: #{e.message}"
96
- raise
97
- end
98
- end
99
-
100
- # Get current execution status
101
- def status
102
- elapsed = @start_time ? Time.now - @start_time : 0
103
- minutes = (elapsed / 60).to_i
104
- seconds = (elapsed % 60).to_i
105
- time_str = (minutes > 0) ? "#{minutes}m #{seconds}s" : "#{seconds}s"
106
-
107
- case @state
108
- when :idle
109
- "⏳ Idle"
110
- when :starting
111
- "🚀 Starting..."
112
- when :running
113
- output_info = (@output_count > 0) ? " (#{@output_count} outputs)" : ""
114
- "🔄 Running #{time_str}#{output_info}"
115
- when :warning
116
- "⚠️ Taking longer than expected #{time_str}"
117
- when :user_aborted
118
- "🛑 Aborted by user after #{time_str}"
119
- when :completed
120
- "✅ Completed in #{time_str}"
121
- when :failed
122
- "❌ Failed after #{time_str}"
123
- end
124
- end
125
-
126
- # Check if execution is still active
127
- def active?
128
- [:starting, :running, :warning].include?(@state)
129
- end
130
-
131
- # Check if execution completed successfully
132
- def success?
133
- @state == :completed && @exit_code == 0
134
- end
135
-
136
- # Show timeout warning and give user control
137
- def show_timeout_warning
138
- return if @warning_shown
139
- @warning_shown = true
140
- @state = :warning
141
-
142
- puts "\n⚠️ Agent has been running for #{@timeout_seconds} seconds"
143
- puts " This is longer than expected, but the agent may still be working."
144
- puts " You can:"
145
- puts " 1. Continue waiting (press Enter)"
146
- puts " 2. Abort execution (type 'abort' and press Enter)"
147
- puts " 3. Wait 5 more minutes (type 'wait' and press Enter)"
148
-
149
- begin
150
- Timeout.timeout(30) do
151
- response = gets&.chomp&.downcase
152
- case response
153
- when "abort"
154
- puts "🛑 Aborting execution..."
155
- @user_aborted = true
156
- @state = :user_aborted
157
- kill!
158
- when "wait"
159
- puts "⏰ Will warn again in 5 minutes..."
160
- @warning_shown = false
161
- @state = :running
162
- # Start another warning thread for 5 more minutes
163
- Thread.new do
164
- sleep 300 # 5 minutes
165
- if @state == :running && !@warning_shown
166
- show_timeout_warning
167
- end
168
- end
169
- else
170
- puts "🔄 Continuing to wait..."
171
- @state = :running
172
- end
173
- end
174
- rescue Timeout::Error
175
- puts "⏰ No response received, continuing to wait..."
176
- @state = :running
177
- rescue Interrupt
178
- puts "\n🛑 User interrupted, aborting..."
179
- @user_aborted = true
180
- @state = :user_aborted
181
- kill!
182
- end
183
- end
184
-
185
- # Force kill the process
186
- def kill!
187
- return unless @process_pid && active?
188
-
189
- puts "💀 Force killing agent process (PID: #{@process_pid})"
190
-
191
- begin
192
- # Try graceful termination first
193
- Process.kill("TERM", @process_pid)
194
- sleep 1
195
-
196
- # Force kill if still running
197
- if process_running?(@process_pid)
198
- Process.kill("KILL", @process_pid)
199
- sleep 1
200
- end
201
-
202
- # Double-check and force kill again if needed
203
- if process_running?(@process_pid)
204
- puts "⚠️ Process still running, using SIGKILL..."
205
- Process.kill("KILL", @process_pid)
206
- sleep 1
207
- end
208
-
209
- @state = :user_aborted
210
- rescue Errno::ESRCH
211
- # Process already dead
212
- @state = :user_aborted
213
- rescue => e
214
- puts "⚠️ Error killing process: #{e.message}"
215
- # Try one more time with KILL
216
- begin
217
- Process.kill("KILL", @process_pid) if process_running?(@process_pid)
218
- rescue Errno::ESRCH
219
- # Process already terminated
220
- end
221
- end
222
- end
223
-
224
- private
225
-
226
- def start_supervisor_thread(wait)
227
- @supervisor_thread = Thread.new do
228
- loop do
229
- sleep 10 # Check every 10 seconds
230
-
231
- # Check if process is done
232
- if wait.value
233
- break
234
- end
235
-
236
- # Check for stuck condition (no output for 3 minutes)
237
- if @last_output_time && Time.now - @last_output_time > 180
238
- puts "⚠️ Agent appears stuck (no output for 3+ minutes)"
239
- # Don't kill, just warn
240
- end
241
- end
242
- rescue => e
243
- puts "⚠️ Supervisor thread error: #{e.message}" if @debug
244
- end
245
-
246
- @supervisor_thread
247
- end
248
-
249
- def start_output_threads(stdout, stderr)
250
- # Stdout thread
251
- @output_threads << Thread.new do
252
- stdout.each_line do |line|
253
- @output += line
254
- @output_count += 1
255
- @last_output_time = Time.now
256
-
257
- if @debug
258
- puts "📤 #{line.chomp}"
259
- end
260
- end
261
- rescue IOError => e
262
- puts "📤 stdout closed: #{e.message}" if @debug
263
- rescue => e
264
- puts "⚠️ stdout thread error: #{e.message}" if @debug
265
- end
266
-
267
- # Stderr thread
268
- @output_threads << Thread.new do
269
- stderr.each_line do |line|
270
- @error_output += line
271
- @output_count += 1
272
- @last_output_time = Time.now
273
-
274
- if @debug
275
- puts "❌ #{line.chomp}"
276
- end
277
- end
278
- rescue IOError => e
279
- puts "❌ stderr closed: #{e.message}" if @debug
280
- rescue => e
281
- puts "⚠️ stderr thread error: #{e.message}" if @debug
282
- end
283
- end
284
-
285
- def wait_for_completion(wait)
286
- # Wait for process to complete
287
- exit_status = wait.value
288
- @exit_code = exit_status.exitstatus
289
-
290
- # Update duration
291
- @duration = Time.now - @start_time
292
-
293
- if @user_aborted || @state == :user_aborted
294
- # Process was killed by user
295
- {
296
- success: false,
297
- state: @state,
298
- output: @output,
299
- error_output: @error_output,
300
- exit_code: @exit_code,
301
- duration: @duration,
302
- reason: "user_aborted"
303
- }
304
- elsif exit_status.success?
305
- @state = :completed
306
- {
307
- success: true,
308
- state: @state,
309
- output: @output,
310
- error_output: @error_output,
311
- exit_code: @exit_code,
312
- duration: @duration
313
- }
314
- else
315
- @state = :failed
316
- {
317
- success: false,
318
- state: @state,
319
- output: @output,
320
- error_output: @error_output,
321
- exit_code: @exit_code,
322
- duration: @duration,
323
- reason: "non_zero_exit"
324
- }
325
- end
326
- end
327
-
328
- def cleanup_threads
329
- # Wait for output threads to finish (with timeout)
330
- @output_threads.each do |thread|
331
- thread.join(5) # Wait up to 5 seconds
332
- rescue => e
333
- puts "⚠️ Error joining thread: #{e.message}" if @debug
334
- end
335
-
336
- # Kill supervisor thread
337
- @supervisor_thread&.kill
338
- end
339
-
340
- def process_running?(pid)
341
- Process.kill(0, pid)
342
- true
343
- rescue Errno::ESRCH
344
- false
345
- end
346
- end
347
- end
348
- end
@@ -1,317 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "agent_supervisor"
4
-
5
- module Aidp
6
- module Providers
7
- # Base class for providers that use the agent supervisor
8
- class SupervisedBase
9
- # Timeout constants are now configurable via environment variables for flexibility
10
- DEFAULT_TIMEOUT = Integer(ENV.fetch("AIDP_DEFAULT_TIMEOUT", "300")) # 5 minutes for general operations
11
- QUICK_MODE_TIMEOUT = Integer(ENV.fetch("AIDP_QUICK_MODE_TIMEOUT", "120")) # 2 minutes for testing
12
- REPOSITORY_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_REPOSITORY_ANALYSIS_TIMEOUT", "180")) # 3 minutes
13
- ARCHITECTURE_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_ARCHITECTURE_ANALYSIS_TIMEOUT", "600")) # 10 minutes
14
- TEST_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_TEST_ANALYSIS_TIMEOUT", "300")) # 5 minutes
15
- FUNCTIONALITY_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_FUNCTIONALITY_ANALYSIS_TIMEOUT", "600")) # 10 minutes
16
- DOCUMENTATION_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_DOCUMENTATION_ANALYSIS_TIMEOUT", "300")) # 5 minutes
17
- STATIC_ANALYSIS_TIMEOUT = Integer(ENV.fetch("AIDP_STATIC_ANALYSIS_TIMEOUT", "450")) # 7.5 minutes
18
- REFACTORING_RECOMMENDATIONS_TIMEOUT = Integer(ENV.fetch("AIDP_REFACTORING_RECOMMENDATIONS_TIMEOUT", "600")) # 10 minutes
19
- ADAPTIVE_TIMEOUT_BUFFER = Float(ENV.fetch("AIDP_ADAPTIVE_TIMEOUT_BUFFER", "1.2")) # 20% buffer for adaptive timeouts
20
- attr_reader :name, :last_execution_result, :metrics
21
-
22
- def initialize
23
- @last_execution_result = nil
24
- @metrics = {
25
- total_executions: 0,
26
- successful_executions: 0,
27
- timeout_count: 0,
28
- failure_count: 0,
29
- average_duration: 0.0,
30
- total_duration: 0.0
31
- }
32
- @job_context = nil
33
- end
34
-
35
- # Abstract method - must be implemented by subclasses
36
- def command
37
- raise NotImplementedError, "#{self.class} must implement #command"
38
- end
39
-
40
- # Abstract method - must be implemented by subclasses
41
- def provider_name
42
- raise NotImplementedError, "#{self.class} must implement #provider_name"
43
- end
44
-
45
- # Set job context for background execution
46
- def set_job_context(job_id:, execution_id:, job_manager:)
47
- @job_context = {
48
- job_id: job_id,
49
- execution_id: execution_id,
50
- job_manager: job_manager
51
- }
52
- end
53
-
54
- # Execute with supervision and recovery
55
- def send(prompt:, session: nil)
56
- timeout_seconds = calculate_timeout
57
- debug = ENV["AIDP_DEBUG"] == "1"
58
-
59
- log_info("Executing with #{provider_name} provider (timeout: #{timeout_seconds}s)")
60
-
61
- # Create supervisor
62
- supervisor = AgentSupervisor.new(
63
- command,
64
- timeout_seconds: timeout_seconds,
65
- debug: debug
66
- )
67
-
68
- begin
69
- # Execute with supervision
70
- result = supervisor.execute(prompt)
71
-
72
- # Update metrics
73
- update_metrics(supervisor, result)
74
-
75
- # Store result for debugging
76
- @last_execution_result = result
77
-
78
- if result[:success]
79
- log_info("#{provider_name} completed successfully in #{format_duration(result[:duration])}")
80
- result[:output]
81
- else
82
- handle_execution_failure(result, supervisor)
83
- end
84
- rescue => e
85
- log_error("#{provider_name} execution error: #{e.message}")
86
-
87
- # Try to kill the process if it's still running
88
- supervisor.kill! if supervisor.active?
89
-
90
- raise
91
- end
92
- end
93
-
94
- # Get execution statistics
95
- def stats
96
- @metrics.dup
97
- end
98
-
99
- # Reset statistics
100
- def reset_stats!
101
- @metrics = {
102
- total_executions: 0,
103
- successful_executions: 0,
104
- timeout_count: 0,
105
- failure_count: 0,
106
- average_duration: 0.0,
107
- total_duration: 0.0
108
- }
109
- end
110
-
111
- # Check if provider supports activity monitoring
112
- def supports_activity_monitoring?
113
- true # Supervised providers always support activity monitoring
114
- end
115
-
116
- # Get activity summary for metrics (compatibility with old interface)
117
- def activity_summary
118
- return {} unless @last_execution_result
119
-
120
- {
121
- provider: provider_name,
122
- step_name: ENV["AIDP_CURRENT_STEP"],
123
- start_time: @last_execution_result[:start_time],
124
- end_time: @last_execution_result[:end_time],
125
- duration: @last_execution_result[:duration],
126
- final_state: @last_execution_result[:state],
127
- stuck_detected: false, # Supervisor handles this differently
128
- output_count: @last_execution_result[:output_count] || 0
129
- }
130
- end
131
-
132
- # Compatibility methods for old activity monitoring interface
133
- def setup_activity_monitoring(step_name, callback = nil, timeout = nil)
134
- # No-op for supervised providers - supervisor handles this
135
- end
136
-
137
- def record_activity(message = nil)
138
- # No-op for supervised providers - supervisor handles this
139
- end
140
-
141
- def mark_completed
142
- # No-op for supervised providers - supervisor handles this
143
- end
144
-
145
- def mark_failed(message = nil)
146
- # No-op for supervised providers - supervisor handles this
147
- end
148
-
149
- private
150
-
151
- def calculate_timeout
152
- # Priority order for timeout calculation:
153
- # 1. Quick mode (for testing)
154
- # 2. Environment variable override
155
- # 3. Adaptive timeout based on step type
156
- # 4. Default timeout
157
-
158
- if ENV["AIDP_QUICK_MODE"]
159
- log_info("Quick mode enabled - #{QUICK_MODE_TIMEOUT / 60} minute timeout")
160
- return QUICK_MODE_TIMEOUT
161
- end
162
-
163
- provider_timeout_var = "AIDP_#{provider_name.upcase}_TIMEOUT"
164
- if ENV[provider_timeout_var]
165
- return ENV[provider_timeout_var].to_i
166
- end
167
-
168
- # Adaptive timeout based on step type
169
- step_timeout = get_adaptive_timeout
170
- if step_timeout
171
- log_info("Using adaptive timeout: #{step_timeout} seconds")
172
- return step_timeout
173
- end
174
-
175
- # Default timeout for interactive use
176
- log_info("Using default timeout: #{DEFAULT_TIMEOUT / 60} minutes")
177
- DEFAULT_TIMEOUT
178
- end
179
-
180
- def get_adaptive_timeout
181
- # Try to get timeout recommendations from metrics storage
182
- begin
183
- require_relative "../analyze/metrics_storage"
184
- storage = Aidp::Analyze::MetricsStorage.new(Dir.pwd)
185
- recommendations = storage.calculate_timeout_recommendations
186
-
187
- # Get current step name from environment or context
188
- step_name = ENV["AIDP_CURRENT_STEP"] || "unknown"
189
-
190
- if recommendations[step_name]
191
- recommended = recommendations[step_name][:recommended_timeout]
192
- # Add buffer for safety
193
- return (recommended * ADAPTIVE_TIMEOUT_BUFFER).ceil
194
- end
195
- rescue => e
196
- log_warning("Could not get adaptive timeout: #{e.message}") if ENV["AIDP_DEBUG"]
197
- end
198
-
199
- # Fallback timeouts based on step type patterns
200
- step_name = ENV["AIDP_CURRENT_STEP"] || ""
201
-
202
- case step_name
203
- when /REPOSITORY_ANALYSIS/
204
- REPOSITORY_ANALYSIS_TIMEOUT
205
- when /ARCHITECTURE_ANALYSIS/
206
- ARCHITECTURE_ANALYSIS_TIMEOUT
207
- when /TEST_ANALYSIS/
208
- TEST_ANALYSIS_TIMEOUT
209
- when /FUNCTIONALITY_ANALYSIS/
210
- FUNCTIONALITY_ANALYSIS_TIMEOUT
211
- when /DOCUMENTATION_ANALYSIS/
212
- DOCUMENTATION_ANALYSIS_TIMEOUT
213
- when /STATIC_ANALYSIS/
214
- STATIC_ANALYSIS_TIMEOUT
215
- when /REFACTORING_RECOMMENDATIONS/
216
- REFACTORING_RECOMMENDATIONS_TIMEOUT
217
- else
218
- nil # Use default
219
- end
220
- end
221
-
222
- def update_metrics(supervisor, result)
223
- @metrics[:total_executions] += 1
224
- @metrics[:total_duration] += supervisor.duration
225
- @metrics[:average_duration] = @metrics[:total_duration] / @metrics[:total_executions]
226
-
227
- case result[:state]
228
- when :completed
229
- @metrics[:successful_executions] += 1
230
- when :timeout
231
- @metrics[:timeout_count] += 1
232
- when :failed, :killed
233
- @metrics[:failure_count] += 1
234
- end
235
-
236
- # Log metrics update if in job context
237
- if @job_context
238
- @job_context[:job_manager].log_message(
239
- @job_context[:job_id],
240
- @job_context[:execution_id],
241
- "Updated execution metrics",
242
- "debug",
243
- @metrics
244
- )
245
- end
246
- end
247
-
248
- def handle_execution_failure(result, supervisor)
249
- case result[:reason]
250
- when "user_aborted"
251
- message = "#{provider_name} was aborted by user after #{format_duration(result[:duration])}"
252
- log_error(message)
253
- raise Interrupt, message
254
- when "non_zero_exit"
255
- error_msg = result[:error_output].empty? ? "Unknown error" : result[:error_output].strip
256
- message = "#{provider_name} failed with exit code #{result[:exit_code]}: #{error_msg}"
257
- log_error(message)
258
- raise message
259
- else
260
- message = "#{provider_name} failed: #{result[:reason] || "Unknown error"}"
261
- log_error(message)
262
- raise message
263
- end
264
- end
265
-
266
- def format_duration(seconds)
267
- minutes = (seconds / 60).to_i
268
- secs = (seconds % 60).to_i
269
-
270
- if minutes > 0
271
- "#{minutes}m #{secs}s"
272
- else
273
- "#{secs}s"
274
- end
275
- end
276
-
277
- def log_info(message)
278
- if @job_context
279
- @job_context[:job_manager].log_message(
280
- @job_context[:job_id],
281
- @job_context[:execution_id],
282
- message,
283
- "info"
284
- )
285
- else
286
- puts message
287
- end
288
- end
289
-
290
- def log_warning(message)
291
- if @job_context
292
- @job_context[:job_manager].log_message(
293
- @job_context[:job_id],
294
- @job_context[:execution_id],
295
- message,
296
- "warning"
297
- )
298
- else
299
- puts "⚠️ #{message}"
300
- end
301
- end
302
-
303
- def log_error(message)
304
- if @job_context
305
- @job_context[:job_manager].log_message(
306
- @job_context[:job_id],
307
- @job_context[:execution_id],
308
- message,
309
- "error"
310
- )
311
- else
312
- puts "❌ #{message}"
313
- end
314
- end
315
- end
316
- end
317
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "supervised_base"
4
- require_relative "../util"
5
-
6
- module Aidp
7
- module Providers
8
- class SupervisedCursor < SupervisedBase
9
- def self.available?
10
- !!Aidp::Util.which("cursor-agent")
11
- end
12
-
13
- def provider_name
14
- "cursor"
15
- end
16
-
17
- def command
18
- ["cursor-agent", "-p"]
19
- end
20
- end
21
- end
22
- end
data/lib/aidp/sync.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
-
5
- module Aidp
6
- # Synchronization utilities
7
- class Sync
8
- def self.ensure_workspace_sync
9
- # Placeholder for workspace synchronization logic
10
- true
11
- end
12
- end
13
- end