aidp 0.12.1 → 0.13.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.
@@ -61,7 +61,7 @@ module Aidp
61
61
  end
62
62
 
63
63
  # Get provider info, refreshing if needed
64
- def get_info(force_refresh: false, max_age: 86400)
64
+ def info(force_refresh: false, max_age: 86400)
65
65
  existing_info = load_info
66
66
 
67
67
  # Refresh if forced, missing, or stale
@@ -142,27 +142,21 @@ module Aidp
142
142
  end
143
143
 
144
144
  def fetch_mcp_servers
145
- binary = get_binary_name
146
- return nil unless binary
145
+ # Use the provider class to fetch MCP servers
146
+ return [] unless provider_instance
147
147
 
148
- # Try different MCP list commands based on provider
149
- mcp_output = case @provider_name
150
- when "claude", "anthropic"
151
- execute_provider_command("mcp", "list")
152
- end
153
-
154
- return nil unless mcp_output
155
-
156
- parse_mcp_servers(mcp_output)
148
+ provider_instance.fetch_mcp_servers
149
+ rescue => e
150
+ warn "Failed to fetch MCP servers for #{@provider_name}: #{e.message}" if ENV["AIDP_DEBUG"]
151
+ []
157
152
  end
158
153
 
159
154
  def execute_provider_command(*args)
160
- binary = get_binary_name
161
- return nil unless binary
155
+ return nil unless binary_name
162
156
 
163
157
  # Try to find the binary
164
158
  path = begin
165
- Aidp::Util.which(binary)
159
+ Aidp::Util.which(binary_name)
166
160
  rescue
167
161
  nil
168
162
  end
@@ -171,7 +165,7 @@ module Aidp
171
165
  # Execute command with timeout
172
166
  begin
173
167
  r, w = IO.pipe
174
- pid = Process.spawn(binary, *args, out: w, err: w)
168
+ pid = Process.spawn(binary_name, *args, out: w, err: w)
175
169
  w.close
176
170
 
177
171
  # Wait with timeout
@@ -269,12 +263,12 @@ module Aidp
269
263
  servers
270
264
  end
271
265
 
272
- def get_binary_name
266
+ def binary_name
273
267
  case @provider_name
274
268
  when "claude", "anthropic"
275
269
  "claude"
276
270
  when "cursor"
277
- "cursor"
271
+ "cursor-agent" # Use cursor-agent CLI, not cursor IDE shortcut
278
272
  when "gemini"
279
273
  "gemini"
280
274
  when "codex"
@@ -297,8 +291,14 @@ module Aidp
297
291
  flags: {}
298
292
  }
299
293
 
300
- # Check for MCP support
301
- parsed[:mcp_support] = !!(help_text =~ /mcp|MCP|Model Context Protocol/i)
294
+ # Check for MCP support using provider class
295
+ provider_inst = provider_instance
296
+ parsed[:mcp_support] = if provider_inst
297
+ provider_inst.supports_mcp?
298
+ else
299
+ # Fallback to text-based detection
300
+ !!(help_text =~ /mcp|MCP|Model Context Protocol/i)
301
+ end
302
302
 
303
303
  # Extract permission modes
304
304
  if help_text =~ /--permission-mode\s+<mode>\s+.*?\(choices:\s*([^)]+)\)/m
@@ -342,6 +342,23 @@ module Aidp
342
342
  parsed
343
343
  end
344
344
 
345
+ # Get provider instance for MCP operations
346
+ def provider_instance
347
+ return @provider_instance if @provider_instance
348
+
349
+ # Load provider factory and get provider class
350
+ require_relative "provider_factory"
351
+
352
+ provider_class = Aidp::Harness::ProviderFactory::PROVIDER_CLASSES[@provider_name]
353
+ return nil unless provider_class
354
+
355
+ # Create provider instance
356
+ @provider_instance = provider_class.new
357
+ rescue => e
358
+ warn "Failed to create provider instance for #{@provider_name}: #{e.message}" if ENV["AIDP_DEBUG"]
359
+ nil
360
+ end
361
+
345
362
  def extract_flags(help_text, flags_hash)
346
363
  # Extract all flags with their descriptions
347
364
  help_text.scan(/^\s+(--[\w-]+(?:\s+<\w+>)?)\s+(.+?)(?=^\s+(?:--|\w|$))/m).each do |flag, desc|
@@ -49,7 +49,7 @@ module Aidp
49
49
 
50
50
  # Get current model
51
51
  def current_model
52
- @current_model ||= get_default_model(current_provider)
52
+ @current_model ||= default_model(current_provider)
53
53
  end
54
54
 
55
55
  # Get current provider and model combination
@@ -59,16 +59,21 @@ module Aidp
59
59
 
60
60
  # Get configured providers from configuration
61
61
  def configured_providers
62
- @configuration.configured_providers
62
+ # Handle both Configuration and ConfigManager instances
63
+ if @configuration.respond_to?(:configured_providers)
64
+ @configuration.configured_providers
65
+ else
66
+ @configuration.provider_names
67
+ end
63
68
  end
64
69
 
65
70
  # Switch to next available provider with sophisticated fallback logic
66
71
  def switch_provider(reason = "manual_switch", context = {})
67
72
  # Get fallback chain for current provider
68
- fallback_chain = get_fallback_chain(current_provider)
73
+ provider_fallback_chain = fallback_chain(current_provider)
69
74
 
70
75
  # Find next healthy provider in fallback chain
71
- next_provider = find_next_healthy_provider(fallback_chain, current_provider)
76
+ next_provider = find_next_healthy_provider(provider_fallback_chain, current_provider)
72
77
 
73
78
  if next_provider
74
79
  success = set_current_provider(next_provider, reason, context)
@@ -153,7 +158,7 @@ module Aidp
153
158
  return nil unless @model_switching_enabled
154
159
 
155
160
  # Get fallback chain for current provider's models
156
- model_chain = get_model_fallback_chain(current_provider)
161
+ model_chain = model_fallback_chain(current_provider)
157
162
 
158
163
  # Find next healthy model in fallback chain
159
164
  next_model = find_next_healthy_model(model_chain, current_model)
@@ -284,15 +289,15 @@ module Aidp
284
289
  update_sticky_session(provider_name) if context[:session_id]
285
290
 
286
291
  # Reset current model when switching providers
287
- @current_model = get_default_model(provider_name)
292
+ @current_model = default_model(provider_name)
288
293
 
289
294
  @current_provider = provider_name
290
295
  true
291
296
  end
292
297
 
293
298
  # Get available providers (not rate limited, healthy, and circuit breaker closed)
294
- def get_available_providers
295
- all_providers = @configuration.configured_providers
299
+ def available_providers
300
+ all_providers = configured_providers
296
301
  all_providers.select do |provider|
297
302
  !is_rate_limited?(provider) &&
298
303
  is_provider_healthy?(provider) &&
@@ -301,8 +306,8 @@ module Aidp
301
306
  end
302
307
 
303
308
  # Get available models for a provider
304
- def get_available_models(provider_name)
305
- models = get_provider_models(provider_name)
309
+ def available_models(provider_name)
310
+ models = provider_models(provider_name)
306
311
  models.select do |model|
307
312
  model_available?(provider_name, model) &&
308
313
  is_model_healthy?(provider_name, model) &&
@@ -321,18 +326,18 @@ module Aidp
321
326
 
322
327
  # Check if model is configured for provider
323
328
  def model_configured?(provider_name, model_name)
324
- models = get_provider_models(provider_name)
329
+ models = provider_models(provider_name)
325
330
  models.include?(model_name)
326
331
  end
327
332
 
328
333
  # Get models for a provider
329
- def get_provider_models(provider_name)
334
+ def provider_models(provider_name)
330
335
  @model_configs[provider_name] || []
331
336
  end
332
337
 
333
338
  # Get default model for provider
334
- def get_default_model(provider_name)
335
- models = get_provider_models(provider_name)
339
+ def default_model(provider_name)
340
+ models = provider_models(provider_name)
336
341
  return models.first if models.any?
337
342
 
338
343
  # Fallback to provider-specific defaults
@@ -349,18 +354,18 @@ module Aidp
349
354
  end
350
355
 
351
356
  # Get fallback chain for a provider
352
- def get_fallback_chain(provider_name)
357
+ def fallback_chain(provider_name)
353
358
  @fallback_chains[provider_name] || build_default_fallback_chain(provider_name)
354
359
  end
355
360
 
356
361
  # Get fallback chain for models within a provider
357
- def get_model_fallback_chain(provider_name)
362
+ def model_fallback_chain(provider_name)
358
363
  @model_fallback_chains[provider_name] || build_default_model_fallback_chain(provider_name)
359
364
  end
360
365
 
361
366
  # Build default model fallback chain
362
367
  def build_default_model_fallback_chain(provider_name)
363
- models = get_provider_models(provider_name)
368
+ models = provider_models(provider_name)
364
369
  @model_fallback_chains[provider_name] = models.dup
365
370
  models
366
371
  end
@@ -382,7 +387,7 @@ module Aidp
382
387
 
383
388
  # Find any available model for provider
384
389
  def find_any_available_model(provider_name)
385
- available_models = get_available_models(provider_name)
390
+ available_models = available_models(provider_name)
386
391
  return nil if available_models.empty?
387
392
 
388
393
  # Use weighted selection if weights are configured
@@ -396,7 +401,7 @@ module Aidp
396
401
 
397
402
  # Select model by load balancing
398
403
  def select_model_by_load_balancing(provider_name)
399
- available_models = get_available_models(provider_name)
404
+ available_models = available_models(provider_name)
400
405
  return nil if available_models.empty?
401
406
 
402
407
  # Calculate load for each model
@@ -429,7 +434,7 @@ module Aidp
429
434
 
430
435
  # Calculate model load
431
436
  def calculate_model_load(provider_name, model_name)
432
- metrics = get_model_metrics(provider_name, model_name)
437
+ metrics = model_metrics(provider_name, model_name)
433
438
  return 0 if metrics.empty?
434
439
 
435
440
  # Calculate load based on success rate, response time, and current usage
@@ -443,7 +448,7 @@ module Aidp
443
448
 
444
449
  # Calculate current usage for model
445
450
  def calculate_model_current_usage(provider_name, model_name)
446
- metrics = get_model_metrics(provider_name, model_name)
451
+ metrics = model_metrics(provider_name, model_name)
447
452
  return 0 if metrics.empty?
448
453
 
449
454
  last_used = metrics[:last_used]
@@ -462,7 +467,7 @@ module Aidp
462
467
 
463
468
  # Build default fallback chain
464
469
  def build_default_fallback_chain(provider_name)
465
- all_providers = @configuration.configured_providers
470
+ all_providers = configured_providers
466
471
  fallback_chain = all_providers.dup
467
472
  fallback_chain.delete(provider_name)
468
473
  fallback_chain.unshift(provider_name) # Put current provider first
@@ -487,25 +492,25 @@ module Aidp
487
492
 
488
493
  # Find any available provider
489
494
  def find_any_available_provider
490
- available_providers = get_available_providers
491
- return nil if available_providers.empty?
495
+ provider_list = available_providers
496
+ return nil if provider_list.empty?
492
497
 
493
498
  # Use weighted selection if weights are configured
494
499
  if @provider_weights.any?
495
- select_provider_by_weight(available_providers)
500
+ select_provider_by_weight(provider_list)
496
501
  else
497
502
  # Simple round-robin selection
498
- available_providers.first
503
+ provider_list.first
499
504
  end
500
505
  end
501
506
 
502
507
  # Select provider by load balancing
503
508
  def select_provider_by_load_balancing
504
- available_providers = get_available_providers
505
- return nil if available_providers.empty?
509
+ provider_list = available_providers
510
+ return nil if provider_list.empty?
506
511
 
507
512
  # Calculate load for each provider
508
- provider_loads = available_providers.map do |provider|
513
+ provider_loads = provider_list.map do |provider|
509
514
  load = calculate_provider_load(provider)
510
515
  [provider, load]
511
516
  end
@@ -533,12 +538,12 @@ module Aidp
533
538
 
534
539
  # Calculate provider load
535
540
  def calculate_provider_load(provider_name)
536
- metrics = get_metrics(provider_name)
537
- return 0 if metrics.empty?
541
+ provider_metrics = metrics(provider_name)
542
+ return 0 if provider_metrics.empty?
538
543
 
539
544
  # Calculate load based on success rate, response time, and current usage
540
- success_rate = metrics[:successful_requests].to_f / [metrics[:total_requests], 1].max
541
- avg_response_time = metrics[:total_duration] / [metrics[:successful_requests], 1].max
545
+ success_rate = provider_metrics[:successful_requests].to_f / [provider_metrics[:total_requests], 1].max
546
+ avg_response_time = provider_metrics[:total_duration] / [provider_metrics[:successful_requests], 1].max
542
547
  current_usage = calculate_current_usage(provider_name)
543
548
 
544
549
  # Load formula: higher is worse
@@ -548,10 +553,10 @@ module Aidp
548
553
  # Calculate current usage for provider
549
554
  def calculate_current_usage(provider_name)
550
555
  # Simple usage calculation based on recent activity
551
- metrics = get_metrics(provider_name)
552
- return 0 if metrics.empty?
556
+ provider_metrics = metrics(provider_name)
557
+ return 0 if provider_metrics.empty?
553
558
 
554
- last_used = metrics[:last_used]
559
+ last_used = provider_metrics[:last_used]
555
560
  return 0 unless last_used
556
561
 
557
562
  # Higher usage if used recently
@@ -960,12 +965,12 @@ module Aidp
960
965
  end
961
966
 
962
967
  # Get model metrics
963
- def get_model_metrics(provider_name, model_name)
968
+ def model_metrics(provider_name, model_name)
964
969
  @model_metrics[provider_name]&.dig(model_name) || {}
965
970
  end
966
971
 
967
972
  # Get all model metrics for provider
968
- def get_all_model_metrics(provider_name)
973
+ def all_model_metrics(provider_name)
969
974
  @model_metrics[provider_name] || {}
970
975
  end
971
976
 
@@ -976,7 +981,7 @@ module Aidp
976
981
  end
977
982
 
978
983
  # Get provider metrics
979
- def get_metrics(provider_name)
984
+ def metrics(provider_name)
980
985
  @provider_metrics[provider_name] || {}
981
986
  end
982
987
 
@@ -1098,9 +1103,9 @@ module Aidp
1098
1103
  # Summarize health and metrics for dashboard/CLI display
1099
1104
  def health_dashboard
1100
1105
  now = Time.now
1101
- statuses = get_provider_health_status
1106
+ statuses = provider_health_status
1102
1107
  metrics = all_metrics
1103
- configured = @configuration.configured_providers
1108
+ configured = configured_providers
1104
1109
  # Ensure fresh binary probe results in test mode so stubs of Aidp::Util.which take effect
1105
1110
  if defined?(RSpec) || ENV["RSPEC_RUNNING"]
1106
1111
  @binary_check_cache.clear
@@ -1210,7 +1215,7 @@ module Aidp
1210
1215
  current_provider: current_provider,
1211
1216
  current_model: current_model,
1212
1217
  current_provider_model: current_provider_model,
1213
- available_providers: get_available_providers,
1218
+ available_providers: available_providers,
1214
1219
  rate_limited_providers: @rate_limit_info.keys,
1215
1220
  unhealthy_providers: @provider_health.select { |_, health| health[:status] != "healthy" }.keys,
1216
1221
  circuit_breaker_open: @provider_health.select { |_, health| health[:circuit_breaker_open] }.keys,
@@ -1224,7 +1229,7 @@ module Aidp
1224
1229
  end
1225
1230
 
1226
1231
  # Get detailed provider health status
1227
- def get_provider_health_status
1232
+ def provider_health_status
1228
1233
  @provider_health.transform_values do |health|
1229
1234
  {
1230
1235
  status: health[:status],
@@ -1241,7 +1246,7 @@ module Aidp
1241
1246
  end
1242
1247
 
1243
1248
  # Get detailed model health status
1244
- def get_model_health_status(provider_name)
1249
+ def model_health_status(provider_name)
1245
1250
  @model_health[provider_name]&.transform_values do |health|
1246
1251
  {
1247
1252
  status: health[:status],
@@ -1256,7 +1261,7 @@ module Aidp
1256
1261
  end
1257
1262
 
1258
1263
  # Get all model health status
1259
- def get_all_model_health_status
1264
+ def all_model_health_status
1260
1265
  @model_health.transform_values do |provider_models|
1261
1266
  provider_models.transform_values do |health|
1262
1267
  {
@@ -1298,7 +1303,7 @@ module Aidp
1298
1303
  end
1299
1304
 
1300
1305
  # Get sticky session provider
1301
- def get_sticky_session_provider(session_id)
1306
+ def sticky_session_provider(session_id)
1302
1307
  return nil unless session_id
1303
1308
 
1304
1309
  # Find provider with recent session activity
@@ -1353,7 +1358,7 @@ module Aidp
1353
1358
  # Initialize fallback chains
1354
1359
  def initialize_fallback_chains
1355
1360
  @fallback_chains.clear
1356
- all_providers = @configuration.configured_providers
1361
+ all_providers = configured_providers
1357
1362
 
1358
1363
  all_providers.each do |provider|
1359
1364
  build_default_fallback_chain(provider)
@@ -1363,7 +1368,7 @@ module Aidp
1363
1368
  # Initialize provider health
1364
1369
  def initialize_provider_health
1365
1370
  @provider_health.clear
1366
- all_providers = @configuration.configured_providers
1371
+ all_providers = configured_providers
1367
1372
 
1368
1373
  all_providers.each do |provider|
1369
1374
  @provider_health[provider] = {
@@ -1380,21 +1385,21 @@ module Aidp
1380
1385
  # Initialize model configurations
1381
1386
  def initialize_model_configs
1382
1387
  @model_configs.clear
1383
- all_providers = @configuration.configured_providers
1388
+ all_providers = configured_providers
1384
1389
 
1385
1390
  all_providers.each do |provider|
1386
- @model_configs[provider] = get_default_models_for_provider(provider)
1391
+ @model_configs[provider] = @configuration.provider_models(provider)
1387
1392
  end
1388
1393
  end
1389
1394
 
1390
1395
  # Initialize model health
1391
1396
  def initialize_model_health
1392
1397
  @model_health.clear
1393
- all_providers = @configuration.configured_providers
1398
+ all_providers = configured_providers
1394
1399
 
1395
1400
  all_providers.each do |provider|
1396
1401
  @model_health[provider] = {}
1397
- models = get_default_models_for_provider(provider)
1402
+ models = @configuration.provider_models(provider)
1398
1403
 
1399
1404
  models.each do |model|
1400
1405
  @model_health[provider][model] = {
@@ -1410,7 +1415,7 @@ module Aidp
1410
1415
  end
1411
1416
 
1412
1417
  # Get default models for provider
1413
- def get_default_models_for_provider(provider_name)
1418
+ def default_models_for_provider(provider_name)
1414
1419
  case provider_name
1415
1420
  when "claude"
1416
1421
  ["claude-3-5-sonnet-20241022", "claude-3-5-haiku-20241022", "claude-3-opus-20240229"]
@@ -14,7 +14,7 @@ module Aidp
14
14
  else
15
15
  # ProviderConfig signature: usage_based_provider?(options)
16
16
  options = provider_name_or_options
17
- get_type(options) == "usage_based"
17
+ type(options) == "usage_based"
18
18
  end
19
19
  end
20
20
 
@@ -25,7 +25,7 @@ module Aidp
25
25
  get_provider_type(provider_name, options) == "subscription"
26
26
  else
27
27
  options = provider_name_or_options
28
- get_type(options) == "subscription"
28
+ type(options) == "subscription"
29
29
  end
30
30
  end
31
31
 
@@ -36,13 +36,13 @@ module Aidp
36
36
  get_provider_type(provider_name, options) == "passthrough"
37
37
  else
38
38
  options = provider_name_or_options
39
- get_type(options) == "passthrough"
39
+ type(options) == "passthrough"
40
40
  end
41
41
  end
42
42
 
43
43
  # Get provider type with fallback to subscription (ConfigManager signature)
44
44
  def get_provider_type(provider_name, options = {})
45
- provider_config = get_provider_config(provider_name, options)
45
+ provider_config = provider_config(provider_name, options)
46
46
  return "subscription" unless provider_config
47
47
 
48
48
  provider_config[:type] || provider_config["type"] || "subscription"
@@ -59,7 +59,7 @@ module Aidp
59
59
 
60
60
  if provider_name_or_options.is_a?(String) || provider_name_or_options.is_a?(Symbol)
61
61
  provider_name = provider_name_or_options
62
- provider_config = get_provider_config(provider_name, options)
62
+ provider_config = provider_config(provider_name, options)
63
63
  else
64
64
  options = provider_name_or_options
65
65
  provider_config = get_config(options)
@@ -75,7 +75,7 @@ module Aidp
75
75
 
76
76
  if provider_name_or_options.is_a?(String) || provider_name_or_options.is_a?(Symbol)
77
77
  provider_name = provider_name_or_options
78
- provider_config = get_provider_config(provider_name, options)
78
+ provider_config = provider_config(provider_name, options)
79
79
  else
80
80
  options = provider_name_or_options
81
81
  provider_config = get_config(options)
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "timeout"
4
4
  require "json"
5
- require_relative "configuration"
5
+ require_relative "config_manager"
6
6
  require_relative "state_manager"
7
7
  require_relative "condition_detector"
8
8
  require_relative "provider_manager"
@@ -49,12 +49,12 @@ module Aidp
49
49
  @workflow_type = options[:workflow_type]
50
50
 
51
51
  # Initialize components
52
- @configuration = Configuration.new(project_dir)
52
+ @config_manager = ConfigManager.new(project_dir)
53
53
  @state_manager = StateManager.new(project_dir, @mode)
54
54
  @condition_detector = ConditionDetector.new
55
- @provider_manager = ProviderManager.new(@configuration, prompt: @prompt)
55
+ @provider_manager = ProviderManager.new(@config_manager, prompt: @prompt)
56
56
  @user_interface = SimpleUserInterface.new
57
- @error_handler = ErrorHandler.new(@provider_manager, @configuration)
57
+ @error_handler = ErrorHandler.new(@provider_manager, @config_manager)
58
58
  @status_display = StatusDisplay.new
59
59
  @completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
60
60
  end
@@ -173,9 +173,9 @@ module Aidp
173
173
  {
174
174
  harness: status,
175
175
  configuration: {
176
- default_provider: @configuration.default_provider,
177
- fallback_providers: @configuration.fallback_providers,
178
- max_retries: @configuration.max_retries
176
+ default_provider: @config_manager.default_provider,
177
+ fallback_providers: @config_manager.fallback_providers,
178
+ max_retries: @config_manager.harness_config[:max_retries]
179
179
  },
180
180
  provider_manager: @provider_manager.status,
181
181
  error_stats: @error_handler.error_stats