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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +128 -151
  3. data/bin/aidp +1 -1
  4. data/lib/aidp/analysis/kb_inspector.rb +471 -0
  5. data/lib/aidp/analysis/seams.rb +159 -0
  6. data/lib/aidp/analysis/tree_sitter_grammar_loader.rb +480 -0
  7. data/lib/aidp/analysis/tree_sitter_scan.rb +686 -0
  8. data/lib/aidp/analyze/error_handler.rb +2 -78
  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/analyze/steps.rb +6 -0
  15. data/lib/aidp/cli/jobs_command.rb +103 -435
  16. data/lib/aidp/cli.rb +317 -191
  17. data/lib/aidp/config.rb +298 -10
  18. data/lib/aidp/debug_logger.rb +195 -0
  19. data/lib/aidp/debug_mixin.rb +187 -0
  20. data/lib/aidp/execute/progress.rb +9 -0
  21. data/lib/aidp/execute/runner.rb +221 -40
  22. data/lib/aidp/execute/steps.rb +17 -7
  23. data/lib/aidp/execute/workflow_selector.rb +211 -0
  24. data/lib/aidp/harness/completion_checker.rb +268 -0
  25. data/lib/aidp/harness/condition_detector.rb +1526 -0
  26. data/lib/aidp/harness/config_loader.rb +373 -0
  27. data/lib/aidp/harness/config_manager.rb +382 -0
  28. data/lib/aidp/harness/config_schema.rb +1006 -0
  29. data/lib/aidp/harness/config_validator.rb +355 -0
  30. data/lib/aidp/harness/configuration.rb +477 -0
  31. data/lib/aidp/harness/enhanced_runner.rb +494 -0
  32. data/lib/aidp/harness/error_handler.rb +616 -0
  33. data/lib/aidp/harness/provider_config.rb +423 -0
  34. data/lib/aidp/harness/provider_factory.rb +306 -0
  35. data/lib/aidp/harness/provider_manager.rb +1269 -0
  36. data/lib/aidp/harness/provider_type_checker.rb +88 -0
  37. data/lib/aidp/harness/runner.rb +411 -0
  38. data/lib/aidp/harness/state/errors.rb +28 -0
  39. data/lib/aidp/harness/state/metrics.rb +219 -0
  40. data/lib/aidp/harness/state/persistence.rb +128 -0
  41. data/lib/aidp/harness/state/provider_state.rb +132 -0
  42. data/lib/aidp/harness/state/ui_state.rb +68 -0
  43. data/lib/aidp/harness/state/workflow_state.rb +123 -0
  44. data/lib/aidp/harness/state_manager.rb +586 -0
  45. data/lib/aidp/harness/status_display.rb +888 -0
  46. data/lib/aidp/harness/ui/base.rb +16 -0
  47. data/lib/aidp/harness/ui/enhanced_tui.rb +545 -0
  48. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +252 -0
  49. data/lib/aidp/harness/ui/error_handler.rb +132 -0
  50. data/lib/aidp/harness/ui/frame_manager.rb +361 -0
  51. data/lib/aidp/harness/ui/job_monitor.rb +500 -0
  52. data/lib/aidp/harness/ui/navigation/main_menu.rb +311 -0
  53. data/lib/aidp/harness/ui/navigation/menu_formatter.rb +120 -0
  54. data/lib/aidp/harness/ui/navigation/menu_item.rb +142 -0
  55. data/lib/aidp/harness/ui/navigation/menu_state.rb +139 -0
  56. data/lib/aidp/harness/ui/navigation/submenu.rb +202 -0
  57. data/lib/aidp/harness/ui/navigation/workflow_selector.rb +176 -0
  58. data/lib/aidp/harness/ui/progress_display.rb +280 -0
  59. data/lib/aidp/harness/ui/question_collector.rb +141 -0
  60. data/lib/aidp/harness/ui/spinner_group.rb +184 -0
  61. data/lib/aidp/harness/ui/spinner_helper.rb +152 -0
  62. data/lib/aidp/harness/ui/status_manager.rb +312 -0
  63. data/lib/aidp/harness/ui/status_widget.rb +280 -0
  64. data/lib/aidp/harness/ui/workflow_controller.rb +312 -0
  65. data/lib/aidp/harness/user_interface.rb +2381 -0
  66. data/lib/aidp/provider_manager.rb +131 -7
  67. data/lib/aidp/providers/anthropic.rb +28 -109
  68. data/lib/aidp/providers/base.rb +170 -0
  69. data/lib/aidp/providers/cursor.rb +52 -183
  70. data/lib/aidp/providers/gemini.rb +24 -109
  71. data/lib/aidp/providers/macos_ui.rb +99 -5
  72. data/lib/aidp/providers/opencode.rb +194 -0
  73. data/lib/aidp/storage/csv_storage.rb +172 -0
  74. data/lib/aidp/storage/file_manager.rb +214 -0
  75. data/lib/aidp/storage/json_storage.rb +140 -0
  76. data/lib/aidp/version.rb +1 -1
  77. data/lib/aidp.rb +56 -35
  78. data/templates/ANALYZE/06a_tree_sitter_scan.md +217 -0
  79. data/templates/COMMON/AGENT_BASE.md +11 -0
  80. data/templates/EXECUTE/00_PRD.md +4 -4
  81. data/templates/EXECUTE/02_ARCHITECTURE.md +5 -4
  82. data/templates/EXECUTE/07_TEST_PLAN.md +4 -1
  83. data/templates/EXECUTE/08_TASKS.md +4 -4
  84. data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +4 -4
  85. data/templates/README.md +279 -0
  86. data/templates/aidp-development.yml.example +373 -0
  87. data/templates/aidp-minimal.yml.example +48 -0
  88. data/templates/aidp-production.yml.example +475 -0
  89. data/templates/aidp.yml.example +598 -0
  90. metadata +106 -64
  91. data/lib/aidp/analyze/agent_personas.rb +0 -71
  92. data/lib/aidp/analyze/agent_tool_executor.rb +0 -445
  93. data/lib/aidp/analyze/data_retention_manager.rb +0 -426
  94. data/lib/aidp/analyze/database.rb +0 -260
  95. data/lib/aidp/analyze/dependencies.rb +0 -335
  96. data/lib/aidp/analyze/export_manager.rb +0 -425
  97. data/lib/aidp/analyze/focus_guidance.rb +0 -517
  98. data/lib/aidp/analyze/incremental_analyzer.rb +0 -543
  99. data/lib/aidp/analyze/language_analysis_strategies.rb +0 -897
  100. data/lib/aidp/analyze/large_analysis_progress.rb +0 -504
  101. data/lib/aidp/analyze/memory_manager.rb +0 -365
  102. data/lib/aidp/analyze/metrics_storage.rb +0 -336
  103. data/lib/aidp/analyze/parallel_processor.rb +0 -460
  104. data/lib/aidp/analyze/performance_optimizer.rb +0 -694
  105. data/lib/aidp/analyze/repository_chunker.rb +0 -704
  106. data/lib/aidp/analyze/static_analysis_detector.rb +0 -577
  107. data/lib/aidp/analyze/storage.rb +0 -662
  108. data/lib/aidp/analyze/tool_configuration.rb +0 -456
  109. data/lib/aidp/analyze/tool_modernization.rb +0 -750
  110. data/lib/aidp/database/pg_adapter.rb +0 -148
  111. data/lib/aidp/database_config.rb +0 -69
  112. data/lib/aidp/database_connection.rb +0 -72
  113. data/lib/aidp/database_migration.rb +0 -158
  114. data/lib/aidp/job_manager.rb +0 -41
  115. data/lib/aidp/jobs/base_job.rb +0 -47
  116. data/lib/aidp/jobs/provider_execution_job.rb +0 -96
  117. data/lib/aidp/project_detector.rb +0 -117
  118. data/lib/aidp/providers/agent_supervisor.rb +0 -348
  119. data/lib/aidp/providers/supervised_base.rb +0 -317
  120. data/lib/aidp/providers/supervised_cursor.rb +0 -22
  121. data/lib/aidp/sync.rb +0 -13
  122. data/lib/aidp/workspace.rb +0 -19
@@ -0,0 +1,477 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../config"
4
+
5
+ module Aidp
6
+ module Harness
7
+ # Handles loading and validation of harness configuration from aidp.yml
8
+ class Configuration
9
+ def initialize(project_dir)
10
+ @project_dir = project_dir
11
+ @config = Aidp::Config.load_harness_config(project_dir)
12
+ validate_configuration!
13
+ end
14
+
15
+ # Get harness-specific configuration
16
+ def harness_config
17
+ @config[:harness]
18
+ end
19
+
20
+ # Get provider configuration
21
+ def provider_config(provider_name)
22
+ @config.dig(:providers, provider_name.to_sym) || {}
23
+ end
24
+
25
+ # Get all configured providers
26
+ def configured_providers
27
+ @config[:providers]&.keys&.map(&:to_s) || []
28
+ end
29
+
30
+ # Get default provider
31
+ def default_provider
32
+ harness_config[:default_provider]
33
+ end
34
+
35
+ # Get fallback providers
36
+ def fallback_providers
37
+ harness_config[:fallback_providers]
38
+ end
39
+
40
+ # Get maximum retries
41
+ def max_retries
42
+ harness_config[:max_retries]
43
+ end
44
+
45
+ # Check if restricted to non-BYOK providers
46
+ def restrict_to_non_byok?
47
+ harness_config[:restrict_to_non_byok]
48
+ end
49
+
50
+ # Get provider type (api, package, etc.)
51
+ def provider_type(provider_name)
52
+ provider_config(provider_name)[:type] || "unknown"
53
+ end
54
+
55
+ # Get maximum tokens for API providers
56
+ def max_tokens(provider_name)
57
+ provider_config(provider_name)[:max_tokens]
58
+ end
59
+
60
+ # Get default flags for a provider
61
+ def default_flags(provider_name)
62
+ provider_config(provider_name)[:default_flags] || []
63
+ end
64
+
65
+ # Get provider models configuration
66
+ def provider_models(provider_name)
67
+ provider_config(provider_name)[:models] || get_default_models_for_provider(provider_name)
68
+ end
69
+
70
+ # Get default model for provider
71
+ def default_model(provider_name)
72
+ models = provider_models(provider_name)
73
+ models.first || get_default_model_for_provider(provider_name)
74
+ end
75
+
76
+ # Get model configuration for provider
77
+ def model_config(provider_name, model_name)
78
+ models_config = provider_config(provider_name)[:models_config] || {}
79
+ models_config[model_name] || {}
80
+ end
81
+
82
+ # Get model-specific flags
83
+ def model_flags(provider_name, model_name)
84
+ model_config(provider_name, model_name)[:flags] || []
85
+ end
86
+
87
+ # Get model-specific max tokens
88
+ def model_max_tokens(provider_name, model_name)
89
+ model_config(provider_name, model_name)[:max_tokens] || max_tokens(provider_name)
90
+ end
91
+
92
+ # Get model-specific timeout
93
+ def model_timeout(provider_name, model_name)
94
+ model_config(provider_name, model_name)[:timeout] || get_default_timeout_for_provider(provider_name)
95
+ end
96
+
97
+ # Get provider weights for load balancing
98
+ def provider_weights
99
+ harness_config[:provider_weights] || {}
100
+ end
101
+
102
+ # Get model weights for load balancing
103
+ def model_weights(provider_name)
104
+ provider_config(provider_name)[:model_weights] || {}
105
+ end
106
+
107
+ # Get circuit breaker configuration
108
+ def circuit_breaker_config
109
+ harness_config[:circuit_breaker] || get_default_circuit_breaker_config
110
+ end
111
+
112
+ # Get retry configuration
113
+ def retry_config
114
+ harness_config[:retry] || get_default_retry_config
115
+ end
116
+
117
+ # Get rate limit configuration
118
+ def rate_limit_config
119
+ harness_config[:rate_limit] || get_default_rate_limit_config
120
+ end
121
+
122
+ # Get load balancing configuration
123
+ def load_balancing_config
124
+ harness_config[:load_balancing] || get_default_load_balancing_config
125
+ end
126
+
127
+ # Get model switching configuration
128
+ def model_switching_config
129
+ harness_config[:model_switching] || get_default_model_switching_config
130
+ end
131
+
132
+ # Get provider health check configuration
133
+ def health_check_config
134
+ harness_config[:health_check] || get_default_health_check_config
135
+ end
136
+
137
+ # Get metrics configuration
138
+ def metrics_config
139
+ harness_config[:metrics] || get_default_metrics_config
140
+ end
141
+
142
+ # Get session configuration
143
+ def session_config
144
+ harness_config[:session] || get_default_session_config
145
+ end
146
+
147
+ # Get provider priority
148
+ def provider_priority(provider_name)
149
+ provider_config(provider_name)[:priority] || 0
150
+ end
151
+
152
+ # Get provider cost configuration
153
+ def provider_cost_config(provider_name)
154
+ provider_config(provider_name)[:cost] || {}
155
+ end
156
+
157
+ # Get provider region configuration
158
+ def provider_regions(provider_name)
159
+ provider_config(provider_name)[:regions] || []
160
+ end
161
+
162
+ # Get provider authentication configuration
163
+ def provider_auth_config(provider_name)
164
+ provider_config(provider_name)[:auth] || {}
165
+ end
166
+
167
+ # Get provider endpoint configuration
168
+ def provider_endpoints(provider_name)
169
+ provider_config(provider_name)[:endpoints] || {}
170
+ end
171
+
172
+ # Get provider feature flags
173
+ def provider_features(provider_name)
174
+ provider_config(provider_name)[:features] || {}
175
+ end
176
+
177
+ # Get provider monitoring configuration
178
+ def provider_monitoring_config(provider_name)
179
+ provider_config(provider_name)[:monitoring] || {}
180
+ end
181
+
182
+ # Check if provider is configured
183
+ def provider_configured?(provider_name)
184
+ configured_providers.include?(provider_name.to_s)
185
+ end
186
+
187
+ # Get configuration path
188
+ def config_path
189
+ File.join(@project_dir, "aidp.yml")
190
+ end
191
+
192
+ # Get logging configuration
193
+ def logging_config
194
+ harness_config[:logging] || get_default_logging_config
195
+ end
196
+
197
+ # Get fallback configuration
198
+ def fallback_config
199
+ harness_config[:fallback] || get_default_fallback_config
200
+ end
201
+
202
+ # Check if configuration file exists
203
+ def config_exists?
204
+ Aidp::Config.config_exists?(@project_dir)
205
+ end
206
+
207
+ # Create example configuration
208
+ def create_example_config
209
+ Aidp::Config.create_example_config(@project_dir)
210
+ end
211
+
212
+ # Get raw configuration
213
+ def raw_config
214
+ @config.dup
215
+ end
216
+
217
+ # Validate model configuration
218
+ def validate_model_config(provider_name, model_name, model_config, errors)
219
+ # Validate model-specific fields
220
+ if model_config[:max_tokens] && !model_config[:max_tokens].is_a?(Integer)
221
+ errors << "Model '#{provider_name}:#{model_name}' max_tokens must be integer"
222
+ end
223
+
224
+ if model_config[:timeout] && !model_config[:timeout].is_a?(Integer)
225
+ errors << "Model '#{provider_name}:#{model_name}' timeout must be integer"
226
+ end
227
+
228
+ if model_config[:flags] && !model_config[:flags].is_a?(Array)
229
+ errors << "Model '#{provider_name}:#{model_name}' flags must be array"
230
+ end
231
+ end
232
+
233
+ # Get configuration summary
234
+ def configuration_summary
235
+ {
236
+ providers: configured_providers.size,
237
+ default_provider: default_provider,
238
+ fallback_providers: fallback_providers.size,
239
+ max_retries: max_retries,
240
+ restrict_to_non_byok: restrict_to_non_byok?,
241
+ load_balancing_enabled: load_balancing_config[:enabled],
242
+ model_switching_enabled: model_switching_config[:enabled],
243
+ circuit_breaker_enabled: circuit_breaker_config[:enabled],
244
+ health_check_enabled: health_check_config[:enabled],
245
+ metrics_enabled: metrics_config[:enabled]
246
+ }
247
+ end
248
+
249
+ # Validate provider configuration
250
+ def validate_provider_config(provider_name)
251
+ errors = []
252
+
253
+ unless provider_configured?(provider_name)
254
+ errors << "Provider '#{provider_name}' not configured"
255
+ return errors
256
+ end
257
+
258
+ # Validate provider type
259
+ provider_type = provider_type(provider_name)
260
+ unless %w[usage_based subscription passthrough].include?(provider_type)
261
+ errors << "Provider '#{provider_name}' has invalid type: #{provider_type}"
262
+ end
263
+
264
+ # Validate required fields based on type
265
+ case provider_type
266
+ when "usage_based"
267
+ unless max_tokens(provider_name)
268
+ errors << "Provider '#{provider_name}' missing max_tokens for usage_based type"
269
+ end
270
+ when "passthrough"
271
+ unless provider_config(provider_name)[:underlying_service]
272
+ errors << "Provider '#{provider_name}' missing underlying_service for passthrough type"
273
+ end
274
+ end
275
+
276
+ errors
277
+ end
278
+
279
+ private
280
+
281
+ def validate_configuration!
282
+ errors = Aidp::Config.validate_harness_config(@config, @project_dir)
283
+
284
+ # Additional harness-specific validation
285
+ unless harness_config[:default_provider]
286
+ errors << "Default provider not specified"
287
+ end
288
+
289
+ unless configured_providers.include?(default_provider)
290
+ errors << "Default provider '#{default_provider}' not configured"
291
+ end
292
+
293
+ # Validate fallback providers
294
+ fallback_providers.each do |provider|
295
+ unless configured_providers.include?(provider)
296
+ errors << "Fallback provider '#{provider}' not configured"
297
+ end
298
+ end
299
+
300
+ # Validate each provider configuration using config_validator
301
+ configured_providers.each do |provider|
302
+ require_relative "config_validator"
303
+ validator = ConfigValidator.new(@project_dir)
304
+ validation_result = validator.validate_provider(provider)
305
+ unless validation_result[:valid]
306
+ errors.concat(validation_result[:errors])
307
+ end
308
+ end
309
+
310
+ raise ConfigurationError, errors.join(", ") if errors.any?
311
+
312
+ true
313
+ end
314
+
315
+ # Default configuration methods
316
+ def get_default_models_for_provider(provider_name)
317
+ case provider_name
318
+ when "anthropic"
319
+ ["anthropic-3-5-sonnet-20241022", "anthropic-3-5-haiku-20241022", "anthropic-3-opus-20240229"]
320
+ when "cursor"
321
+ ["cursor-default", "cursor-fast", "cursor-precise"]
322
+ else
323
+ ["default"]
324
+ end
325
+ end
326
+
327
+ def get_default_model_for_provider(provider_name)
328
+ case provider_name
329
+ when "anthropic"
330
+ "anthropic-3-5-sonnet-20241022"
331
+ when "cursor"
332
+ "cursor-default"
333
+ else
334
+ "default"
335
+ end
336
+ end
337
+
338
+ def get_default_timeout_for_provider(provider_name)
339
+ 300 # 5 minutes - default timeout for all providers
340
+ end
341
+
342
+ def get_default_circuit_breaker_config
343
+ {
344
+ enabled: true,
345
+ failure_threshold: 5,
346
+ timeout: 300, # 5 minutes
347
+ half_open_max_calls: 3
348
+ }
349
+ end
350
+
351
+ def get_default_retry_config
352
+ {
353
+ enabled: true,
354
+ max_attempts: 3,
355
+ base_delay: 1.0,
356
+ max_delay: 60.0,
357
+ exponential_base: 2.0,
358
+ jitter: true
359
+ }
360
+ end
361
+
362
+ def get_default_rate_limit_config
363
+ {
364
+ enabled: true,
365
+ default_reset_time: 3600, # 1 hour
366
+ burst_limit: 10,
367
+ sustained_limit: 5
368
+ }
369
+ end
370
+
371
+ def get_default_load_balancing_config
372
+ {
373
+ enabled: true,
374
+ strategy: "weighted_round_robin", # weighted_round_robin, least_connections, random
375
+ health_check_interval: 30,
376
+ unhealthy_threshold: 3
377
+ }
378
+ end
379
+
380
+ def get_default_model_switching_config
381
+ {
382
+ enabled: true,
383
+ auto_switch_on_error: true,
384
+ auto_switch_on_rate_limit: true,
385
+ fallback_strategy: "sequential" # sequential, load_balanced, random
386
+ }
387
+ end
388
+
389
+ def get_default_health_check_config
390
+ {
391
+ enabled: true,
392
+ interval: 60, # 1 minute
393
+ timeout: 10,
394
+ failure_threshold: 3,
395
+ success_threshold: 2
396
+ }
397
+ end
398
+
399
+ def get_default_metrics_config
400
+ {
401
+ enabled: true,
402
+ retention_days: 30,
403
+ aggregation_interval: 300, # 5 minutes
404
+ export_interval: 3600 # 1 hour
405
+ }
406
+ end
407
+
408
+ def get_default_session_config
409
+ {
410
+ enabled: true,
411
+ timeout: 1800, # 30 minutes
412
+ sticky_sessions: true,
413
+ session_affinity: "provider_model" # provider, model, provider_model
414
+ }
415
+ end
416
+
417
+ def get_default_logging_config
418
+ {
419
+ log_level: :info,
420
+ retention_days: 30,
421
+ max_file_size: 10485760, # 10MB
422
+ max_files: 5,
423
+ format: :json,
424
+ include_stack_traces: true,
425
+ include_context: true
426
+ }
427
+ end
428
+
429
+ def get_default_fallback_config
430
+ {
431
+ strategies: {
432
+ rate_limit: {
433
+ action: :switch_provider,
434
+ priority: :high,
435
+ max_attempts: 3,
436
+ cooldown_period: 300
437
+ },
438
+ network_error: {
439
+ action: :switch_provider,
440
+ priority: :high,
441
+ max_attempts: 2,
442
+ cooldown_period: 60
443
+ },
444
+ server_error: {
445
+ action: :switch_provider,
446
+ priority: :medium,
447
+ max_attempts: 2,
448
+ cooldown_period: 120
449
+ },
450
+ timeout: {
451
+ action: :switch_model,
452
+ priority: :medium,
453
+ max_attempts: 2,
454
+ cooldown_period: 60
455
+ },
456
+ authentication: {
457
+ action: :escalate,
458
+ priority: :critical,
459
+ max_attempts: 0,
460
+ cooldown_period: 0
461
+ }
462
+ },
463
+ selection_strategies: {
464
+ health_based: :health_based,
465
+ load_balanced: :load_balanced,
466
+ circuit_breaker_aware: :circuit_breaker_aware,
467
+ performance_based: :performance_based,
468
+ round_robin: :round_robin
469
+ }
470
+ }
471
+ end
472
+
473
+ # Custom error class for configuration issues
474
+ class ConfigurationError < StandardError; end
475
+ end
476
+ end
477
+ end