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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/aidp/analyze/error_handler.rb +4 -2
  3. data/lib/aidp/{analysis → analyze}/kb_inspector.rb +106 -89
  4. data/lib/aidp/analyze/prioritizer.rb +3 -2
  5. data/lib/aidp/analyze/ruby_maat_integration.rb +20 -3
  6. data/lib/aidp/analyze/runner.rb +27 -9
  7. data/lib/aidp/{analysis → analyze}/seams.rb +1 -1
  8. data/lib/aidp/analyze/steps.rb +7 -7
  9. data/lib/aidp/{analysis → analyze}/tree_sitter_grammar_loader.rb +22 -5
  10. data/lib/aidp/{analysis → analyze}/tree_sitter_scan.rb +32 -15
  11. data/lib/aidp/cli/first_run_wizard.rb +37 -28
  12. data/lib/aidp/cli/jobs_command.rb +37 -18
  13. data/lib/aidp/cli/terminal_io.rb +3 -3
  14. data/lib/aidp/cli.rb +131 -63
  15. data/lib/aidp/execute/runner.rb +27 -9
  16. data/lib/aidp/execute/steps.rb +18 -18
  17. data/lib/aidp/execute/workflow_selector.rb +36 -21
  18. data/lib/aidp/harness/enhanced_runner.rb +3 -3
  19. data/lib/aidp/harness/provider_factory.rb +3 -1
  20. data/lib/aidp/harness/provider_manager.rb +34 -15
  21. data/lib/aidp/harness/runner.rb +24 -5
  22. data/lib/aidp/harness/simple_user_interface.rb +19 -4
  23. data/lib/aidp/harness/status_display.rb +121 -104
  24. data/lib/aidp/harness/ui/enhanced_tui.rb +33 -5
  25. data/lib/aidp/harness/ui/error_handler.rb +3 -2
  26. data/lib/aidp/harness/ui/frame_manager.rb +52 -32
  27. data/lib/aidp/harness/ui/navigation/main_menu.rb +23 -14
  28. data/lib/aidp/harness/ui/progress_display.rb +28 -5
  29. data/lib/aidp/harness/ui/status_widget.rb +17 -8
  30. data/lib/aidp/harness/ui/workflow_controller.rb +25 -9
  31. data/lib/aidp/harness/user_interface.rb +341 -328
  32. data/lib/aidp/provider_manager.rb +10 -6
  33. data/lib/aidp/providers/anthropic.rb +3 -3
  34. data/lib/aidp/providers/base.rb +20 -1
  35. data/lib/aidp/providers/cursor.rb +6 -8
  36. data/lib/aidp/providers/gemini.rb +3 -3
  37. data/lib/aidp/providers/github_copilot.rb +264 -0
  38. data/lib/aidp/providers/opencode.rb +6 -8
  39. data/lib/aidp/version.rb +1 -1
  40. data/lib/aidp.rb +4 -4
  41. metadata +6 -6
  42. data/lib/aidp/analyze/progress_visualizer.rb +0 -314
@@ -24,9 +24,24 @@ module Aidp
24
24
 
25
25
  private
26
26
 
27
+ # Helper method for consistent message display using TTY::Prompt
28
+ def display_message(message, type: :info)
29
+ color = case type
30
+ when :error then :red
31
+ when :success then :green
32
+ when :warning then :yellow
33
+ when :info then :blue
34
+ when :highlight then :cyan
35
+ when :muted then :bright_black
36
+ else :white
37
+ end
38
+
39
+ @prompt.say(message, color: color)
40
+ end
41
+
27
42
  def select_workflow_interactive
28
- puts "\n🚀 Welcome to AI Dev Pipeline!"
29
- puts "Let's set up your development workflow.\n\n"
43
+ display_message("\n🚀 Welcome to AI Dev Pipeline!", type: :highlight)
44
+ display_message("Let's set up your development workflow.\n\n")
30
45
 
31
46
  # Step 1: Collect project information
32
47
  collect_project_info
@@ -45,7 +60,7 @@ module Aidp
45
60
  end
46
61
 
47
62
  def select_workflow_with_defaults
48
- puts "\n🚀 Starting harness with default workflow configuration..."
63
+ display_message("\n🚀 Starting harness with default workflow configuration...", type: :highlight)
49
64
 
50
65
  # Use default project information
51
66
  @user_input = {
@@ -71,7 +86,7 @@ module Aidp
71
86
  private
72
87
 
73
88
  def collect_project_info
74
- puts "📋 First, tell us about your project:\n"
89
+ display_message("📋 First, tell us about your project:\n", type: :highlight)
75
90
 
76
91
  @user_input[:project_description] = prompt_required(
77
92
  "What do you want to build? (Be specific about features and goals)"
@@ -91,17 +106,17 @@ module Aidp
91
106
  end
92
107
 
93
108
  def choose_workflow_type
94
- puts "\n🎯 Choose your development approach:\n"
95
- puts "1. 🔬 Exploration/Experiment - Quick prototype or proof of concept"
96
- puts " • Fast iteration, minimal documentation"
97
- puts " • Focus on core functionality and validation"
98
- puts " • Steps: PRD → Tasks → Implementation"
99
- puts ""
100
- puts "2. 🏗️ Full Development - Production-ready feature or system"
101
- puts " • Comprehensive planning and documentation"
102
- puts " • You can customize which steps to include"
103
- puts " • Full enterprise workflow available"
104
- puts ""
109
+ display_message("\n🎯 Choose your development approach:\n", type: :highlight)
110
+ display_message("1. 🔬 Exploration/Experiment - Quick prototype or proof of concept")
111
+ display_message(" • Fast iteration, minimal documentation", type: :muted)
112
+ display_message(" • Focus on core functionality and validation", type: :muted)
113
+ display_message(" • Steps: PRD → Tasks → Implementation", type: :muted)
114
+ display_message("")
115
+ display_message("2. 🏗️ Full Development - Production-ready feature or system")
116
+ display_message(" • Comprehensive planning and documentation", type: :muted)
117
+ display_message(" • You can customize which steps to include", type: :muted)
118
+ display_message(" • Full enterprise workflow available", type: :muted)
119
+ display_message("")
105
120
 
106
121
  choice = prompt_choice("Which approach fits your project?", ["1", "2", "exploration", "full"])
107
122
 
@@ -111,7 +126,7 @@ module Aidp
111
126
  when "2", "full"
112
127
  :full
113
128
  else
114
- puts "Invalid choice. Defaulting to exploration workflow."
129
+ display_message("Invalid choice. Defaulting to exploration workflow.", type: :warning)
115
130
  :exploration
116
131
  end
117
132
  end
@@ -137,8 +152,8 @@ module Aidp
137
152
  end
138
153
 
139
154
  def full_workflow_steps
140
- puts "\n🛠️ Customize your full development workflow:\n"
141
- puts "Select the steps you want to include (enter numbers separated by commas):\n"
155
+ display_message("\n🛠️ Customize your full development workflow:\n", type: :highlight)
156
+ display_message("Select the steps you want to include (enter numbers separated by commas):\n")
142
157
 
143
158
  available_steps = {
144
159
  "1" => "00_PRD - Product Requirements Document",
@@ -155,8 +170,8 @@ module Aidp
155
170
  "12" => "13_DELIVERY_ROLLOUT - Deployment Planning"
156
171
  }
157
172
 
158
- available_steps.each { |num, desc| puts " #{num}. #{desc}" }
159
- puts ""
173
+ available_steps.each { |num, desc| display_message(" #{num}. #{desc}") }
174
+ display_message("")
160
175
 
161
176
  selected = prompt_required("Enter step numbers (e.g., 1,3,5,9,10): ")
162
177
  selected_numbers = selected.split(",").map(&:strip).map(&:to_i)
@@ -193,7 +208,7 @@ module Aidp
193
208
  input = @prompt.ask("#{question}:")
194
209
 
195
210
  if input.nil? || input.strip.empty?
196
- puts "❌ This field is required. Please provide an answer."
211
+ display_message("❌ This field is required. Please provide an answer.", type: :error)
197
212
  next
198
213
  end
199
214
 
@@ -50,7 +50,7 @@ module Aidp
50
50
  @configuration = Configuration.new(project_dir)
51
51
  @state_manager = StateManager.new(project_dir, @mode)
52
52
  @condition_detector = ConditionDetector.new
53
- @provider_manager = ProviderManager.new(@configuration)
53
+ @provider_manager = ProviderManager.new(@configuration, prompt: TTY::Prompt.new)
54
54
  @error_handler = ErrorHandler.new(@provider_manager, @configuration)
55
55
  @completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
56
56
  end
@@ -312,9 +312,9 @@ module Aidp
312
312
  def get_mode_runner
313
313
  case @mode
314
314
  when :analyze
315
- Aidp::Analyze::Runner.new(@project_dir, self)
315
+ Aidp::Analyze::Runner.new(@project_dir, self, prompt: TTY::Prompt.new)
316
316
  when :execute
317
- Aidp::Execute::Runner.new(@project_dir, self)
317
+ Aidp::Execute::Runner.new(@project_dir, self, prompt: TTY::Prompt.new)
318
318
  else
319
319
  raise ArgumentError, "Unsupported mode: #{@mode}"
320
320
  end
@@ -7,6 +7,7 @@ require_relative "../providers/anthropic"
7
7
  require_relative "../providers/gemini"
8
8
  require_relative "../providers/macos_ui"
9
9
  require_relative "../providers/opencode"
10
+ require_relative "../providers/github_copilot"
10
11
 
11
12
  module Aidp
12
13
  module Harness
@@ -17,7 +18,8 @@ module Aidp
17
18
  "anthropic" => Aidp::Providers::Anthropic,
18
19
  "gemini" => Aidp::Providers::Gemini,
19
20
  "macos" => Aidp::Providers::MacOSUI,
20
- "opencode" => Aidp::Providers::Opencode
21
+ "opencode" => Aidp::Providers::Opencode,
22
+ "github_copilot" => Aidp::Providers::GithubCopilot
21
23
  }.freeze
22
24
 
23
25
  def initialize(config_manager = nil)
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "tty-prompt"
3
4
  require_relative "provider_factory"
4
5
 
5
6
  module Aidp
6
7
  module Harness
7
8
  # Manages provider switching and fallback logic
8
9
  class ProviderManager
9
- def initialize(configuration)
10
+ def initialize(configuration, prompt: TTY::Prompt.new)
10
11
  @configuration = configuration
12
+ @prompt = prompt
11
13
  @current_provider = nil
12
14
  @current_model = nil
13
15
  @provider_history = []
@@ -1199,20 +1201,37 @@ module Aidp
1199
1201
  [delay, 60].min # Cap at 60 seconds
1200
1202
  end
1201
1203
 
1204
+ private
1205
+
1206
+ def display_message(message, type: :info)
1207
+ color = case type
1208
+ when :error then :red
1209
+ when :success then :green
1210
+ when :warning then :yellow
1211
+ when :info then :blue
1212
+ when :highlight then :cyan
1213
+ when :muted then :bright_black
1214
+ else :white
1215
+ end
1216
+ @prompt.say(message, color: color)
1217
+ end
1218
+
1219
+ public
1220
+
1202
1221
  # Log provider switch
1203
1222
  def log_provider_switch(from_provider, to_provider, reason, context)
1204
- puts "🔄 Provider switch: #{from_provider} → #{to_provider} (#{reason})"
1223
+ display_message("🔄 Provider switch: #{from_provider} → #{to_provider} (#{reason})", type: :info)
1205
1224
  if context.any?
1206
- puts " Context: #{context.inspect}"
1225
+ display_message(" Context: #{context.inspect}", type: :muted)
1207
1226
  end
1208
1227
  end
1209
1228
 
1210
1229
  # Log no providers available
1211
1230
  def log_no_providers_available(reason, context)
1212
- puts "❌ No providers available for switching (#{reason})"
1213
- puts " All providers are rate limited, unhealthy, or circuit breaker open"
1231
+ display_message("❌ No providers available for switching (#{reason})", type: :error)
1232
+ display_message(" All providers are rate limited, unhealthy, or circuit breaker open", type: :warning)
1214
1233
  if context.any?
1215
- puts " Context: #{context.inspect}"
1234
+ display_message(" Context: #{context.inspect}", type: :muted)
1216
1235
  end
1217
1236
  end
1218
1237
 
@@ -1220,26 +1239,26 @@ module Aidp
1220
1239
  def log_circuit_breaker_event(provider_name, event)
1221
1240
  case event
1222
1241
  when "opened"
1223
- puts "🔴 Circuit breaker opened for provider: #{provider_name}"
1242
+ display_message("🔴 Circuit breaker opened for provider: #{provider_name}", type: :error)
1224
1243
  when "reset"
1225
- puts "🟢 Circuit breaker reset for provider: #{provider_name}"
1244
+ display_message("🟢 Circuit breaker reset for provider: #{provider_name}", type: :success)
1226
1245
  end
1227
1246
  end
1228
1247
 
1229
1248
  # Log model switch
1230
1249
  def log_model_switch(from_model, to_model, reason, context)
1231
- puts "🔄 Model switch: #{from_model} → #{to_model} (#{reason})"
1250
+ display_message("🔄 Model switch: #{from_model} → #{to_model} (#{reason})", type: :info)
1232
1251
  if context.any?
1233
- puts " Context: #{context.inspect}"
1252
+ display_message(" Context: #{context.inspect}", type: :muted)
1234
1253
  end
1235
1254
  end
1236
1255
 
1237
1256
  # Log no models available
1238
1257
  def log_no_models_available(provider_name, reason, context)
1239
- puts "❌ No models available for provider #{provider_name} (#{reason})"
1240
- puts " All models are rate limited, unhealthy, or circuit breaker open"
1258
+ display_message("❌ No models available for provider #{provider_name} (#{reason})", type: :error)
1259
+ display_message(" All models are rate limited, unhealthy, or circuit breaker open", type: :warning)
1241
1260
  if context.any?
1242
- puts " Context: #{context.inspect}"
1261
+ display_message(" Context: #{context.inspect}", type: :muted)
1243
1262
  end
1244
1263
  end
1245
1264
 
@@ -1247,9 +1266,9 @@ module Aidp
1247
1266
  def log_model_circuit_breaker_event(provider_name, model_name, event)
1248
1267
  case event
1249
1268
  when "opened"
1250
- puts "🔴 Circuit breaker opened for model: #{provider_name}:#{model_name}"
1269
+ display_message("🔴 Circuit breaker opened for model: #{provider_name}:#{model_name}", type: :error)
1251
1270
  when "reset"
1252
- puts "🟢 Circuit breaker reset for model: #{provider_name}:#{model_name}"
1271
+ display_message("🟢 Circuit breaker reset for model: #{provider_name}:#{model_name}", type: :success)
1253
1272
  end
1254
1273
  end
1255
1274
 
@@ -27,6 +27,9 @@ module Aidp
27
27
  error: "error"
28
28
  }.freeze
29
29
 
30
+ # Public accessors for testing and integration
31
+ attr_reader :current_provider, :current_step, :user_input, :execution_log, :provider_manager
32
+
30
33
  def initialize(project_dir, mode = :analyze, options = {})
31
34
  @project_dir = project_dir
32
35
  @mode = mode.to_sym
@@ -37,6 +40,7 @@ module Aidp
37
40
  @current_provider = nil
38
41
  @user_input = options[:user_input] || {} # Include user input from workflow selection
39
42
  @execution_log = []
43
+ @prompt = options[:prompt] || TTY::Prompt.new
40
44
 
41
45
  # Store workflow configuration
42
46
  @selected_steps = options[:selected_steps]
@@ -46,7 +50,7 @@ module Aidp
46
50
  @configuration = Configuration.new(project_dir)
47
51
  @state_manager = StateManager.new(project_dir, @mode)
48
52
  @condition_detector = ConditionDetector.new
49
- @provider_manager = ProviderManager.new(@configuration)
53
+ @provider_manager = ProviderManager.new(@configuration, prompt: @prompt)
50
54
  @user_interface = SimpleUserInterface.new
51
55
  @error_handler = ErrorHandler.new(@provider_manager, @configuration)
52
56
  @status_display = StatusDisplay.new
@@ -96,8 +100,8 @@ module Aidp
96
100
  log_execution("Harness completed successfully - all criteria met", completion_status)
97
101
  else
98
102
  log_execution("Steps completed but completion criteria not met", completion_status)
99
- puts "\n⚠️ All steps completed but some completion criteria not met:"
100
- puts completion_status[:summary]
103
+ display_message("\n⚠️ All steps completed but some completion criteria not met:", type: :warning)
104
+ display_message(completion_status[:summary], type: :info)
101
105
 
102
106
  # Ask user if they want to continue anyway
103
107
  if @user_interface.get_confirmation("Continue anyway? This may indicate issues that should be addressed.", default: false)
@@ -181,9 +185,9 @@ module Aidp
181
185
  def get_mode_runner
182
186
  case @mode
183
187
  when :analyze
184
- Aidp::Analyze::Runner.new(@project_dir, self)
188
+ Aidp::Analyze::Runner.new(@project_dir, self, prompt: TTY::Prompt.new)
185
189
  when :execute
186
- Aidp::Execute::Runner.new(@project_dir, self)
190
+ Aidp::Execute::Runner.new(@project_dir, self, prompt: TTY::Prompt.new)
187
191
  else
188
192
  raise ArgumentError, "Unsupported mode: #{@mode}"
189
193
  end
@@ -406,6 +410,21 @@ module Aidp
406
410
  "Harness finished in state: #{@state}"
407
411
  end
408
412
  end
413
+
414
+ private
415
+
416
+ def display_message(message, type: :info)
417
+ color = case type
418
+ when :error then :red
419
+ when :success then :green
420
+ when :warning then :yellow
421
+ when :info then :blue
422
+ when :highlight then :cyan
423
+ when :muted then :bright_black
424
+ else :white
425
+ end
426
+ @prompt.say(message, color: color)
427
+ end
409
428
  end
410
429
  end
411
430
  end
@@ -26,10 +26,25 @@ module Aidp
26
26
 
27
27
  private
28
28
 
29
+ # Helper method for consistent message display using TTY::Prompt
30
+ def display_message(message, type: :info)
31
+ color = case type
32
+ when :error then :red
33
+ when :success then :green
34
+ when :warning then :yellow
35
+ when :info then :blue
36
+ when :highlight then :cyan
37
+ when :muted then :bright_black
38
+ else :white
39
+ end
40
+
41
+ @prompt.say(message, color: color)
42
+ end
43
+
29
44
  def show_context(context)
30
- puts "\n🤖 Agent needs feedback"
31
- puts "Context: #{context[:description]}" if context[:description]
32
- puts ""
45
+ display_message("\n🤖 Agent needs feedback", type: :info)
46
+ display_message("Context: #{context[:description]}", type: :info) if context[:description]
47
+ display_message("", type: :info)
33
48
  end
34
49
 
35
50
  def ask_question(question_data)
@@ -39,7 +54,7 @@ module Aidp
39
54
  required = question_data[:required] != false
40
55
  options = question_data[:options]
41
56
 
42
- puts "\n#{question}"
57
+ display_message("\n#{question}", type: :info)
43
58
 
44
59
  case type
45
60
  when "text"