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
@@ -0,0 +1,373 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require_relative "config_schema"
5
+ require_relative "config_validator"
6
+
7
+ module Aidp
8
+ module Harness
9
+ # Enhanced configuration loader for harness
10
+ class ConfigLoader
11
+ def initialize(project_dir = Dir.pwd)
12
+ @project_dir = project_dir
13
+ @validator = ConfigValidator.new(project_dir)
14
+ @config_cache = nil
15
+ @last_loaded = nil
16
+ end
17
+
18
+ # Load and validate configuration with caching
19
+ def load_config(force_reload = false)
20
+ return @config_cache if @config_cache && !force_reload && !config_file_changed?
21
+
22
+ # Load and validate configuration
23
+ validation_result = @validator.load_and_validate
24
+
25
+ if validation_result[:valid]
26
+ @config_cache = @validator.get_validated_config
27
+ @last_loaded = Time.now
28
+
29
+ # Log warnings if any
30
+ unless validation_result[:warnings].empty?
31
+ log_warnings(validation_result[:warnings])
32
+ end
33
+
34
+ @config_cache
35
+ else
36
+ # Handle validation errors
37
+ handle_validation_errors(validation_result[:errors])
38
+ nil
39
+ end
40
+ end
41
+
42
+ # Get harness configuration with defaults
43
+ def get_harness_config(force_reload = false)
44
+ config = load_config(force_reload)
45
+ return nil unless config
46
+
47
+ config[:harness] || {}
48
+ end
49
+
50
+ # Get provider configuration with defaults
51
+ def get_provider_config(provider_name, force_reload = false)
52
+ config = load_config(force_reload)
53
+ return nil unless config
54
+
55
+ providers = config[:providers] || {}
56
+ providers[provider_name.to_sym] || providers[provider_name.to_s]
57
+ end
58
+
59
+ # Get all provider configurations
60
+ def get_all_provider_configs(force_reload = false)
61
+ config = load_config(force_reload)
62
+ return {} unless config
63
+
64
+ config[:providers] || {}
65
+ end
66
+
67
+ # Get configured provider names
68
+ def get_configured_providers(force_reload = false)
69
+ config = load_config(force_reload)
70
+ return [] unless config
71
+
72
+ providers = config[:providers] || {}
73
+ providers.keys.map(&:to_s)
74
+ end
75
+
76
+ # Check if configuration exists
77
+ def config_exists?
78
+ @validator.config_exists?
79
+ end
80
+
81
+ # Get configuration file path
82
+ def config_file_path
83
+ @validator.config_file_path
84
+ end
85
+
86
+ # Create example configuration
87
+ def create_example_config
88
+ @validator.create_example_config
89
+ end
90
+
91
+ # Fix configuration issues
92
+ def fix_config_issues
93
+ @validator.fix_common_issues
94
+ end
95
+
96
+ # Get configuration summary
97
+ def get_config_summary
98
+ @validator.get_summary
99
+ end
100
+
101
+ # Validate specific provider
102
+ def validate_provider(provider_name)
103
+ @validator.validate_provider(provider_name)
104
+ end
105
+
106
+ # Check if provider is configured
107
+ def provider_configured?(provider_name)
108
+ @validator.provider_configured?(provider_name)
109
+ end
110
+
111
+ # Get configuration with specific overrides
112
+ def get_config_with_overrides(overrides = {})
113
+ base_config = load_config
114
+ return nil unless base_config
115
+
116
+ merge_overrides(base_config, overrides)
117
+ end
118
+
119
+ # Get harness configuration with overrides
120
+ def get_harness_config_with_overrides(overrides = {})
121
+ harness_config = get_harness_config
122
+ return nil unless harness_config
123
+
124
+ harness_overrides = overrides[:harness] || overrides["harness"] || {}
125
+ deep_merge(harness_config, harness_overrides)
126
+ end
127
+
128
+ # Get provider configuration with overrides
129
+ def get_provider_config_with_overrides(provider_name, overrides = {})
130
+ provider_config = get_provider_config(provider_name)
131
+ return nil unless provider_config
132
+
133
+ provider_overrides = overrides[:providers]&.dig(provider_name.to_sym) ||
134
+ overrides[:providers]&.dig(provider_name.to_s) ||
135
+ overrides["providers"]&.dig(provider_name.to_s) ||
136
+ overrides["providers"]&.dig(provider_name.to_sym) ||
137
+ {}
138
+
139
+ deep_merge(provider_config, provider_overrides)
140
+ end
141
+
142
+ # Export configuration
143
+ def export_config(format = :yaml)
144
+ @validator.export_config(format)
145
+ end
146
+
147
+ # Reload configuration from file
148
+ def reload_config
149
+ @config_cache = nil
150
+ @last_loaded = nil
151
+ load_config(true)
152
+ end
153
+
154
+ # Check if configuration is valid
155
+ def config_valid?
156
+ validation_result = @validator.validate_existing
157
+ validation_result[:valid]
158
+ end
159
+
160
+ # Get validation errors
161
+ def get_validation_errors
162
+ validation_result = @validator.validate_existing
163
+ validation_result[:errors] || []
164
+ end
165
+
166
+ # Get validation warnings
167
+ def get_validation_warnings
168
+ validation_result = @validator.validate_existing
169
+ validation_result[:warnings] || []
170
+ end
171
+
172
+ # Get configuration for specific harness mode
173
+ def get_mode_config(mode, force_reload = false)
174
+ config = load_config(force_reload)
175
+ return nil unless config
176
+
177
+ case mode.to_s
178
+ when "analyze"
179
+ get_analyze_mode_config(config)
180
+ when "execute"
181
+ get_execute_mode_config(config)
182
+ else
183
+ config
184
+ end
185
+ end
186
+
187
+ # Get environment-specific configuration
188
+ def get_environment_config(environment = nil, force_reload = false)
189
+ environment ||= ENV["AIDP_ENV"] || "development"
190
+ config = load_config(force_reload)
191
+ return nil unless config
192
+
193
+ env_config = config[:environments]&.dig(environment.to_sym) ||
194
+ config[:environments]&.dig(environment.to_s) ||
195
+ config["environments"]&.dig(environment.to_s) ||
196
+ config["environments"]&.dig(environment.to_sym) ||
197
+ {}
198
+
199
+ merge_overrides(config, env_config)
200
+ end
201
+
202
+ # Get configuration for specific step
203
+ def get_step_config(step_name, force_reload = false)
204
+ config = load_config(force_reload)
205
+ return nil unless config
206
+
207
+ step_config = config[:steps]&.dig(step_name.to_sym) ||
208
+ config[:steps]&.dig(step_name.to_s) ||
209
+ config["steps"]&.dig(step_name.to_s) ||
210
+ config["steps"]&.dig(step_name.to_sym) ||
211
+ {}
212
+
213
+ merge_overrides(config, step_config)
214
+ end
215
+
216
+ # Get configuration with feature flags
217
+ def get_config_with_features(features = {}, force_reload = false)
218
+ config = load_config(force_reload)
219
+ return nil unless config
220
+
221
+ feature_overrides = {}
222
+
223
+ features.each do |feature, enabled|
224
+ if enabled
225
+ feature_config = config[:features]&.dig(feature.to_sym) ||
226
+ config[:features]&.dig(feature.to_s) ||
227
+ config["features"]&.dig(feature.to_s) ||
228
+ config["features"]&.dig(feature.to_sym) ||
229
+ {}
230
+ feature_overrides = deep_merge(feature_overrides, feature_config)
231
+ end
232
+ end
233
+
234
+ merge_overrides(config, feature_overrides)
235
+ end
236
+
237
+ # Get configuration for specific user
238
+ def get_user_config(user_id = nil, force_reload = false)
239
+ user_id ||= ENV["USER"] || "default"
240
+ config = load_config(force_reload)
241
+ return nil unless config
242
+
243
+ user_config = config[:users]&.dig(user_id.to_sym) ||
244
+ config[:users]&.dig(user_id.to_s) ||
245
+ config["users"]&.dig(user_id.to_s) ||
246
+ config["users"]&.dig(user_id.to_sym) ||
247
+ {}
248
+
249
+ merge_overrides(config, user_config)
250
+ end
251
+
252
+ # Get configuration with time-based overrides
253
+ def get_time_based_config(force_reload = false)
254
+ config = load_config(force_reload)
255
+ return nil unless config
256
+
257
+ time_overrides = {}
258
+ current_hour = Time.now.hour
259
+
260
+ # Check for time-based configurations
261
+ if config[:time_based]
262
+ time_config = config[:time_based]
263
+
264
+ # Check for hour-based overrides
265
+ time_config[:hours]&.each do |hour_range, hour_config|
266
+ if hour_in_range?(current_hour, hour_range)
267
+ time_overrides = deep_merge(time_overrides, hour_config)
268
+ end
269
+ end
270
+
271
+ # Check for day-based overrides
272
+ if time_config[:days]
273
+ current_day = Time.now.strftime("%A").downcase
274
+ day_config = time_config[:days][current_day.to_sym] || time_config[:days][current_day]
275
+ if day_config
276
+ time_overrides = deep_merge(time_overrides, day_config)
277
+ end
278
+ end
279
+ end
280
+
281
+ merge_overrides(config, time_overrides)
282
+ end
283
+
284
+ private
285
+
286
+ def config_file_changed?
287
+ return true unless @last_loaded && @validator.config_file_path
288
+
289
+ File.mtime(@validator.config_file_path) > @last_loaded
290
+ rescue
291
+ true
292
+ end
293
+
294
+ def handle_validation_errors(errors)
295
+ error_message = "Configuration validation failed:\n" + errors.join("\n")
296
+
297
+ # Log error
298
+ if defined?(Rails) && Rails.logger
299
+ Rails.logger.error(error_message)
300
+ else
301
+ warn(error_message)
302
+ end
303
+
304
+ # In development, try to fix common issues
305
+ if ENV["AIDP_ENV"] == "development" || ENV["RACK_ENV"] == "development"
306
+ if @validator.fix_common_issues
307
+ warn("Attempted to fix configuration issues. Please review the updated configuration file.")
308
+ end
309
+ end
310
+ end
311
+
312
+ def log_warnings(warnings)
313
+ warning_message = "Configuration warnings:\n" + warnings.join("\n")
314
+
315
+ # Log warnings
316
+ if defined?(Rails) && Rails.logger
317
+ Rails.logger.warn(warning_message)
318
+ else
319
+ warn(warning_message)
320
+ end
321
+ end
322
+
323
+ def merge_overrides(base_config, overrides)
324
+ return base_config if overrides.empty?
325
+
326
+ deep_merge(base_config, overrides)
327
+ end
328
+
329
+ def deep_merge(base, override)
330
+ result = base.dup
331
+
332
+ override.each do |key, value|
333
+ result[key] = if result[key].is_a?(Hash) && value.is_a?(Hash)
334
+ deep_merge(result[key], value)
335
+ else
336
+ value
337
+ end
338
+ end
339
+
340
+ result
341
+ end
342
+
343
+ def get_analyze_mode_config(config)
344
+ analyze_overrides = config[:analyze_mode] || config["analyze_mode"] || {}
345
+ merge_overrides(config, analyze_overrides)
346
+ end
347
+
348
+ def get_execute_mode_config(config)
349
+ execute_overrides = config[:execute_mode] || config["execute_mode"] || {}
350
+ merge_overrides(config, execute_overrides)
351
+ end
352
+
353
+ def hour_in_range?(hour, range)
354
+ case range
355
+ when Integer
356
+ hour == range
357
+ when Range
358
+ range.include?(hour)
359
+ when String
360
+ # Parse "9-17" format
361
+ if range.include?("-")
362
+ start_hour, end_hour = range.split("-").map(&:to_i)
363
+ hour.between?(start_hour, end_hour)
364
+ else
365
+ hour == range.to_i
366
+ end
367
+ else
368
+ false
369
+ end
370
+ end
371
+ end
372
+ end
373
+ end