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
@@ -1,425 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
- require "csv"
5
- require "yaml"
6
-
7
- module Aidp
8
- class ExportManager
9
- # Supported export formats
10
- SUPPORTED_FORMATS = %w[json csv yaml xml].freeze
11
-
12
- def initialize(project_dir = Dir.pwd, config = {})
13
- @project_dir = project_dir
14
- @config = config
15
- @output_dir = config[:output_dir] || File.join(project_dir, "exports")
16
- end
17
-
18
- # Export analysis data to JSON format
19
- def export_to_json(data, options = {})
20
- export_data(data, "json", options) do |formatted_data|
21
- JSON.pretty_generate(formatted_data)
22
- end
23
- end
24
-
25
- # Export analysis data to CSV format
26
- def export_to_csv(data, options = {})
27
- export_data(data, "csv", options) do |formatted_data|
28
- generate_csv_content(formatted_data, options)
29
- end
30
- end
31
-
32
- # Export analysis data to YAML format
33
- def export_to_yaml(data, options = {})
34
- export_data(data, "yaml", options) do |formatted_data|
35
- YAML.dump(formatted_data)
36
- end
37
- end
38
-
39
- # Export analysis data to XML format
40
- def export_to_xml(data, options = {})
41
- export_data(data, "xml", options) do |formatted_data|
42
- generate_xml_content(formatted_data, options)
43
- end
44
- end
45
-
46
- # Export analysis data to multiple formats
47
- def export_to_multiple_formats(data, formats, options = {})
48
- results = {}
49
-
50
- formats.each do |format|
51
- case format.downcase
52
- when "json"
53
- results[:json] = export_to_json(data, options)
54
- when "csv"
55
- results[:csv] = export_to_csv(data, options)
56
- when "yaml"
57
- results[:yaml] = export_to_yaml(data, options)
58
- when "xml"
59
- results[:xml] = export_to_xml(data, options)
60
- else
61
- results[format] = {error: "Unsupported format: #{format}"}
62
- end
63
- end
64
-
65
- results
66
- end
67
-
68
- # Export specific analysis components
69
- def export_analysis_component(component_name, data, format, options = {})
70
- component_data = extract_component_data(component_name, data)
71
-
72
- case format.downcase
73
- when "json"
74
- export_to_json(component_data, options.merge(component: component_name))
75
- when "csv"
76
- export_to_csv(component_data, options.merge(component: component_name))
77
- when "yaml"
78
- export_to_yaml(component_data, options.merge(component: component_name))
79
- when "xml"
80
- export_to_xml(component_data, options.merge(component: component_name))
81
- else
82
- {error: "Unsupported format: #{format}"}
83
- end
84
- end
85
-
86
- # Export metrics data
87
- def export_metrics(metrics_data, format, options = {})
88
- formatted_metrics = format_metrics_data(metrics_data)
89
-
90
- case format.downcase
91
- when "json"
92
- export_to_json(formatted_metrics, options.merge(type: "metrics"))
93
- when "csv"
94
- export_to_csv(formatted_metrics, options.merge(type: "metrics"))
95
- when "yaml"
96
- export_to_yaml(formatted_metrics, options.merge(type: "metrics"))
97
- when "xml"
98
- export_to_xml(formatted_metrics, options.merge(type: "metrics"))
99
- else
100
- {error: "Unsupported format: #{format}"}
101
- end
102
- end
103
-
104
- # Export comparison data
105
- def export_comparison(before_data, after_data, format, options = {})
106
- comparison_data = prepare_comparison_data(before_data, after_data)
107
-
108
- case format.downcase
109
- when "json"
110
- export_to_json(comparison_data, options.merge(type: "comparison"))
111
- when "csv"
112
- export_to_csv(comparison_data, options.merge(type: "comparison"))
113
- when "yaml"
114
- export_to_yaml(comparison_data, options.merge(type: "comparison"))
115
- when "xml"
116
- export_to_xml(comparison_data, options.merge(type: "comparison"))
117
- else
118
- {error: "Unsupported format: #{format}"}
119
- end
120
- end
121
-
122
- # Generate export summary
123
- def generate_export_summary(exports)
124
- {
125
- total_exports: exports.length,
126
- successful_exports: exports.count { |_, result| result[:success] },
127
- failed_exports: exports.count { |_, result| !result[:success] },
128
- formats_used: exports.keys.uniq,
129
- files_generated: exports.values.filter_map { |result| result[:path] },
130
- generated_at: Time.now
131
- }
132
- end
133
-
134
- private
135
-
136
- def export_data(data, format, options)
137
- timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
138
- component = options[:component] || "analysis"
139
- type = options[:type] || "data"
140
-
141
- filename = options[:filename] || "#{component}_#{type}_#{timestamp}.#{format}"
142
- output_path = File.join(@output_dir, filename)
143
-
144
- # Ensure output directory exists
145
- FileUtils.mkdir_p(@output_dir)
146
-
147
- # Format and write data
148
- formatted_data = format_export_data(data, options)
149
- content = yield(formatted_data)
150
-
151
- File.write(output_path, content)
152
-
153
- {
154
- success: true,
155
- path: output_path,
156
- format: format,
157
- filename: filename,
158
- size: File.size(output_path),
159
- generated_at: Time.now
160
- }
161
- rescue => e
162
- {
163
- success: false,
164
- error: e.message,
165
- format: format,
166
- generated_at: Time.now
167
- }
168
- end
169
-
170
- def format_export_data(data, options)
171
- formatted = {
172
- metadata: {
173
- exported_at: Time.now.iso8601,
174
- project_name: File.basename(@project_dir),
175
- project_path: @project_dir,
176
- export_type: options[:type] || "analysis",
177
- component: options[:component]
178
- },
179
- data: data
180
- }
181
-
182
- # Add configuration if requested
183
- formatted[:config] = @config if options[:include_config]
184
-
185
- formatted
186
- end
187
-
188
- def generate_csv_content(data, options)
189
- # Flatten nested data for CSV export
190
- flattened_data = flatten_data_for_csv(data)
191
-
192
- return "" if flattened_data.empty?
193
-
194
- # Generate CSV content
195
- CSV.generate do |csv|
196
- # Add headers
197
- headers = flattened_data.first.keys
198
- csv << headers
199
-
200
- # Add data rows
201
- flattened_data.each do |row|
202
- csv << headers.map { |header| row[header] }
203
- end
204
- end
205
- end
206
-
207
- def flatten_data_for_csv(data)
208
- flattened = []
209
-
210
- if data[:data].is_a?(Array)
211
- # Handle array data
212
- data[:data].each_with_index do |item, index|
213
- flattened_item = flatten_hash(item)
214
- flattened_item["index"] = index
215
- flattened << flattened_item
216
- end
217
- elsif data[:data].is_a?(Hash)
218
- # Handle hash data
219
- flattened << flatten_hash(data[:data])
220
- end
221
-
222
- flattened
223
- end
224
-
225
- def flatten_hash(hash, prefix = "")
226
- flattened = {}
227
-
228
- hash.each do |key, value|
229
- new_key = prefix.empty? ? key.to_s : "#{prefix}_#{key}"
230
-
231
- case value
232
- when Hash
233
- flattened.merge!(flatten_hash(value, new_key))
234
- when Array
235
- if value.all?(Hash)
236
- # Array of hashes - create separate rows
237
- value.each_with_index do |item, index|
238
- item_flattened = flatten_hash(item, "#{new_key}_#{index}")
239
- flattened.merge!(item_flattened)
240
- end
241
- else
242
- # Simple array - join with semicolon
243
- flattened[new_key] = value.join("; ")
244
- end
245
- else
246
- flattened[new_key] = value
247
- end
248
- end
249
-
250
- flattened
251
- end
252
-
253
- def generate_xml_content(data, options)
254
- require "rexml/document"
255
-
256
- doc = REXML::Document.new
257
- doc.add_element("analysis_export")
258
-
259
- # Add metadata
260
- metadata_elem = doc.root.add_element("metadata")
261
- data[:metadata].each do |key, value|
262
- elem = metadata_elem.add_element(key.to_s)
263
- elem.text = value.to_s
264
- end
265
-
266
- # Add data
267
- data_elem = doc.root.add_element("data")
268
- add_xml_element(data_elem, data[:data])
269
-
270
- # Format XML
271
- formatter = REXML::Formatters::Pretty.new(2)
272
- formatter.compact = true
273
- output = ""
274
- formatter.write(doc, output)
275
-
276
- output
277
- end
278
-
279
- def add_xml_element(parent, data)
280
- case data
281
- when Hash
282
- data.each do |key, value|
283
- elem = parent.add_element(key.to_s)
284
- add_xml_element(elem, value)
285
- end
286
- when Array
287
- data.each_with_index do |item, index|
288
- elem = parent.add_element("item_#{index}")
289
- add_xml_element(elem, item)
290
- end
291
- else
292
- parent.text = data.to_s
293
- end
294
- end
295
-
296
- def extract_component_data(component_name, data)
297
- case component_name
298
- when "repository_analysis"
299
- data[:repository_analysis] || {}
300
- when "architecture_analysis"
301
- data[:architecture_analysis] || {}
302
- when "static_analysis"
303
- data[:static_analysis] || {}
304
- when "security_analysis"
305
- data[:security_analysis] || {}
306
- when "performance_analysis"
307
- data[:performance_analysis] || {}
308
- when "test_coverage"
309
- data[:test_coverage] || {}
310
- when "refactoring_recommendations"
311
- data[:refactoring_recommendations] || {}
312
- when "modernization_recommendations"
313
- data[:modernization_recommendations] || {}
314
- else
315
- data[component_name.to_sym] || {}
316
- end
317
- end
318
-
319
- def format_metrics_data(metrics_data)
320
- formatted = {
321
- metrics: {},
322
- summary: {},
323
- trends: {}
324
- }
325
-
326
- if metrics_data.is_a?(Hash)
327
- metrics_data.each do |category, metrics|
328
- if metrics.is_a?(Hash)
329
- formatted[:metrics][category] = metrics
330
- else
331
- formatted[:summary][category] = metrics
332
- end
333
- end
334
- end
335
-
336
- formatted
337
- end
338
-
339
- def prepare_comparison_data(before_data, after_data)
340
- {
341
- before: before_data,
342
- after: after_data,
343
- changes: calculate_changes(before_data, after_data),
344
- improvements: identify_improvements(before_data, after_data),
345
- regressions: identify_regressions(before_data, after_data)
346
- }
347
- end
348
-
349
- def calculate_changes(before_data, after_data)
350
- changes = {}
351
-
352
- # Compare metrics
353
- before_metrics = extract_metrics(before_data)
354
- after_metrics = extract_metrics(after_data)
355
-
356
- all_metrics = (before_metrics.keys + after_metrics.keys).uniq
357
-
358
- all_metrics.each do |metric|
359
- before_value = before_metrics[metric]
360
- after_value = after_metrics[metric]
361
-
362
- next unless before_value && after_value
363
-
364
- changes[metric] = {
365
- before: before_value,
366
- after: after_value,
367
- change: after_value - before_value,
368
- percentage_change: ((after_value - before_value) / before_value * 100).round(2)
369
- }
370
- end
371
-
372
- changes
373
- end
374
-
375
- def identify_improvements(before_data, after_data)
376
- improvements = []
377
-
378
- changes = calculate_changes(before_data, after_data)
379
- changes.each do |metric, change|
380
- next unless change[:change] > 0
381
-
382
- improvements << {
383
- metric: metric,
384
- improvement: change[:change],
385
- percentage: change[:percentage_change]
386
- }
387
- end
388
-
389
- improvements
390
- end
391
-
392
- def identify_regressions(before_data, after_data)
393
- regressions = []
394
-
395
- changes = calculate_changes(before_data, after_data)
396
- changes.each do |metric, change|
397
- next unless change[:change] < 0
398
-
399
- regressions << {
400
- metric: metric,
401
- regression: change[:change].abs,
402
- percentage: change[:percentage_change].abs
403
- }
404
- end
405
-
406
- regressions
407
- end
408
-
409
- def extract_metrics(data)
410
- metrics = {}
411
-
412
- if data.is_a?(Hash)
413
- data.each do |key, value|
414
- if value.is_a?(Numeric)
415
- metrics[key] = value
416
- elsif value.is_a?(Hash)
417
- metrics.merge!(extract_metrics(value))
418
- end
419
- end
420
- end
421
-
422
- metrics
423
- end
424
- end
425
- end