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,355 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require_relative "config_schema"
5
+
6
+ module Aidp
7
+ module Harness
8
+ # Configuration validator for harness
9
+ class ConfigValidator
10
+ def initialize(project_dir = Dir.pwd)
11
+ @project_dir = project_dir
12
+ @config_file = find_config_file
13
+ @config = nil
14
+ @validation_result = nil
15
+ end
16
+
17
+ # Load and validate configuration
18
+ def load_and_validate
19
+ unless @config_file
20
+ @validation_result = {
21
+ valid: false,
22
+ errors: ["No configuration file found"],
23
+ warnings: []
24
+ }
25
+ return @validation_result
26
+ end
27
+
28
+ load_config
29
+ validate_config
30
+ @validation_result
31
+ end
32
+
33
+ # Validate existing configuration
34
+ def validate_existing
35
+ return {valid: false, errors: ["No configuration file found"], warnings: []} unless @config_file
36
+
37
+ load_config
38
+ validate_config
39
+ @validation_result
40
+ end
41
+
42
+ # Get configuration with defaults applied
43
+ def get_validated_config
44
+ return nil unless @validation_result&.dig(:valid)
45
+
46
+ ConfigSchema.apply_defaults(@config)
47
+ end
48
+
49
+ # Check if configuration is valid
50
+ def valid?
51
+ @validation_result&.dig(:valid) || false
52
+ end
53
+
54
+ # Get validation errors
55
+ def errors
56
+ @validation_result&.dig(:errors) || []
57
+ end
58
+
59
+ # Get validation warnings
60
+ def warnings
61
+ @validation_result&.dig(:warnings) || []
62
+ end
63
+
64
+ # Get configuration file path
65
+ def config_file_path
66
+ @config_file
67
+ end
68
+
69
+ # Check if configuration file exists
70
+ def config_exists?
71
+ !@config_file.nil?
72
+ end
73
+
74
+ # Create example configuration file
75
+ def create_example_config
76
+ return false if config_exists?
77
+
78
+ example_config = ConfigSchema.generate_example
79
+ config_path = File.join(@project_dir, "aidp.yml")
80
+
81
+ File.write(config_path, YAML.dump(example_config))
82
+ true
83
+ end
84
+
85
+ # Fix common configuration issues
86
+ def fix_common_issues
87
+ return false unless @config_file && @config
88
+
89
+ original_config = @config.dup
90
+
91
+ # Fix string/symbol key inconsistencies
92
+ @config = normalize_keys(@config)
93
+
94
+ # Apply missing defaults
95
+ @config = ConfigSchema.apply_defaults(@config)
96
+
97
+ # Fix common validation issues
98
+ fix_validation_issues
99
+
100
+ # Check if any changes were made
101
+ if @config != original_config
102
+ # Write fixed configuration back to file
103
+ File.write(@config_file, YAML.dump(@config))
104
+ true
105
+ else
106
+ false
107
+ end
108
+ end
109
+
110
+ # Get configuration summary
111
+ def get_summary
112
+ return {error: "No configuration file found"} unless @config_file
113
+
114
+ load_config
115
+ summary = {
116
+ config_file: @config_file,
117
+ valid: valid?,
118
+ errors_count: errors.size,
119
+ warnings_count: warnings.size,
120
+ harness_configured: !(@config[:harness] || @config["harness"]).nil?,
121
+ providers_count: 0,
122
+ providers: []
123
+ }
124
+
125
+ providers_config = @config[:providers] || @config["providers"] || {}
126
+ summary[:providers_count] = providers_config.size
127
+ summary[:providers] = providers_config.keys.map(&:to_s)
128
+
129
+ summary
130
+ end
131
+
132
+ # Validate specific provider configuration
133
+ def validate_provider(provider_name)
134
+ return {valid: false, errors: ["No configuration file found"], warnings: []} unless @config_file
135
+
136
+ load_config
137
+ providers_config = @config[:providers] || @config["providers"] || {}
138
+ provider_config = providers_config[provider_name] || providers_config[provider_name.to_sym]
139
+
140
+ return {valid: false, errors: ["Provider '#{provider_name}' not found"], warnings: []} unless provider_config
141
+
142
+ # Create a minimal config with harness section and just this provider for validation
143
+ test_config = {
144
+ harness: {
145
+ max_retries: 2,
146
+ default_provider: provider_name,
147
+ fallback_providers: [provider_name]
148
+ },
149
+ providers: {
150
+ provider_name => provider_config
151
+ }
152
+ }
153
+
154
+ ConfigSchema.validate(test_config)
155
+ end
156
+
157
+ # Get provider configuration with defaults
158
+ def get_provider_config(provider_name)
159
+ return nil unless @config_file
160
+
161
+ load_config
162
+ providers_config = @config[:providers] || @config["providers"] || {}
163
+ provider_config = providers_config[provider_name] || providers_config[provider_name.to_sym]
164
+
165
+ return nil unless provider_config
166
+
167
+ # Apply defaults for this provider
168
+ providers_schema = ConfigSchema::SCHEMA[:providers][:pattern_properties][/^[a-zA-Z0-9_-]+$/]
169
+ ConfigSchema.apply_section_defaults(provider_config, providers_schema)
170
+ end
171
+
172
+ # Check if provider is properly configured
173
+ def provider_configured?(provider_name)
174
+ return false unless @config_file
175
+
176
+ load_config
177
+ providers_config = @config[:providers] || @config["providers"] || {}
178
+ provider_config = providers_config[provider_name] || providers_config[provider_name.to_sym]
179
+
180
+ return false unless provider_config
181
+
182
+ # Basic validation
183
+ provider_type = provider_config[:type] || provider_config["type"]
184
+ return false unless provider_type
185
+
186
+ # For usage-based providers, check for required fields
187
+ if provider_type == "usage_based"
188
+ max_tokens = provider_config[:max_tokens] || provider_config["max_tokens"]
189
+ return false unless max_tokens&.positive?
190
+ end
191
+
192
+ true
193
+ end
194
+
195
+ # Get harness configuration with defaults
196
+ def get_harness_config
197
+ return nil unless @config_file
198
+
199
+ load_config
200
+ harness_config = @config[:harness] || @config["harness"] || {}
201
+
202
+ # Apply defaults
203
+ harness_schema = ConfigSchema::SCHEMA[:harness]
204
+ ConfigSchema.apply_section_defaults(harness_config, harness_schema)
205
+ end
206
+
207
+ # Export configuration to different formats
208
+ def export_config(format = :yaml)
209
+ return nil unless @config_file
210
+
211
+ load_config
212
+ validate_config
213
+ validated_config = get_validated_config
214
+ return nil unless validated_config
215
+
216
+ case format
217
+ when :yaml
218
+ YAML.dump(validated_config)
219
+ when :json
220
+ require "json"
221
+ JSON.pretty_generate(validated_config)
222
+ when :ruby
223
+ "CONFIG = #{validated_config.inspect}"
224
+ else
225
+ raise ArgumentError, "Unsupported format: #{format}"
226
+ end
227
+ end
228
+
229
+ # Validate configuration data (public method for external use)
230
+ def validate_config(config_data = nil)
231
+ if config_data
232
+ # Validate provided configuration data
233
+ @config = config_data
234
+ end
235
+ return unless @config
236
+
237
+ # Don't override validation result if it was already set due to loading errors
238
+ return if @validation_result && !@validation_result[:valid]
239
+
240
+ @validation_result = ConfigSchema.validate(@config)
241
+ end
242
+
243
+ private
244
+
245
+ def find_config_file
246
+ # Try new aidp.yml format first, then fall back to .aidp.yml
247
+ config_file = File.join(@project_dir, "aidp.yml")
248
+ legacy_config_file = File.join(@project_dir, ".aidp.yml")
249
+
250
+ if File.exist?(config_file)
251
+ config_file
252
+ elsif File.exist?(legacy_config_file)
253
+ legacy_config_file
254
+ end
255
+ end
256
+
257
+ def load_config
258
+ return unless @config_file
259
+
260
+ begin
261
+ @config = YAML.load_file(@config_file) || {}
262
+ rescue => e
263
+ @config = {}
264
+ @validation_result = {
265
+ valid: false,
266
+ errors: ["Failed to load configuration file: #{e.message}"],
267
+ warnings: []
268
+ }
269
+ end
270
+ end
271
+
272
+ def normalize_keys(hash)
273
+ return hash unless hash.is_a?(Hash)
274
+
275
+ hash.each_with_object({}) do |(key, value), result|
276
+ new_key = key.is_a?(String) ? key.to_sym : key
277
+ new_value = value.is_a?(Hash) ? normalize_keys(value) : value
278
+ result[new_key] = new_value
279
+ end
280
+ end
281
+
282
+ def fix_validation_issues
283
+ return unless @config
284
+
285
+ # Fix common issues that can be automatically corrected
286
+
287
+ # Ensure harness section exists
288
+ unless @config.key?(:harness)
289
+ @config[:harness] = {}
290
+ end
291
+
292
+ # Ensure providers section exists
293
+ unless @config.key?(:providers)
294
+ @config[:providers] = {}
295
+ end
296
+
297
+ # Fix string/symbol key inconsistencies
298
+ @config = normalize_keys(@config)
299
+
300
+ # Ensure default_provider is set if not specified
301
+ unless @config[:harness][:default_provider]
302
+ available_providers = @config[:providers].keys.map(&:to_s)
303
+ if available_providers.include?("cursor")
304
+ @config[:harness][:default_provider] = "cursor"
305
+ elsif available_providers.any?
306
+ @config[:harness][:default_provider] = available_providers.first
307
+ end
308
+ end
309
+
310
+ # Ensure fallback_providers is an array
311
+ unless @config[:harness][:fallback_providers].is_a?(Array)
312
+ @config[:harness][:fallback_providers] = []
313
+ end
314
+
315
+ # Fix provider configurations
316
+ @config[:providers].each do |_provider_name, provider_config|
317
+ # Ensure type is specified
318
+ unless provider_config[:type]
319
+ provider_config[:type] = "subscription" # Default to subscription
320
+ end
321
+
322
+ # Ensure default_flags is an array
323
+ unless provider_config[:default_flags].is_a?(Array)
324
+ provider_config[:default_flags] = []
325
+ end
326
+
327
+ # Ensure models is an array
328
+ unless provider_config[:models].is_a?(Array)
329
+ provider_config[:models] = []
330
+ end
331
+
332
+ # Ensure model_weights is a hash
333
+ unless provider_config[:model_weights].is_a?(Hash)
334
+ provider_config[:model_weights] = {}
335
+ end
336
+
337
+ # Ensure models_config is a hash
338
+ unless provider_config[:models_config].is_a?(Hash)
339
+ provider_config[:models_config] = {}
340
+ end
341
+
342
+ # Ensure features is a hash
343
+ unless provider_config[:features].is_a?(Hash)
344
+ provider_config[:features] = {}
345
+ end
346
+
347
+ # Ensure monitoring is a hash
348
+ unless provider_config[:monitoring].is_a?(Hash)
349
+ provider_config[:monitoring] = {}
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
355
+ end