aidp 0.7.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 (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 +0 -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
@@ -1,533 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
- require "yaml"
5
- require_relative "storage"
6
-
7
- module Aidp
8
- module Analyze
9
- class IncrementalAnalyzer
10
- # Analysis granularity levels
11
- GRANULARITY_LEVELS = %w[file directory component feature module].freeze
12
-
13
- def initialize(project_dir = Dir.pwd, config = {})
14
- @project_dir = project_dir
15
- @config = config
16
- @storage = config[:storage] || Aidp::AnalysisStorage.new(project_dir)
17
- @progress_file = config[:progress_file] || File.join(project_dir, ".aidp-incremental-progress.yml")
18
- end
19
-
20
- # Perform incremental analysis
21
- def analyze_incrementally(analysis_type, options = {})
22
- granularity = options[:granularity] || "file"
23
- force_full = options[:force_full] || false
24
-
25
- # Load previous analysis state
26
- previous_state = load_analysis_state(analysis_type)
27
-
28
- # Determine what needs to be analyzed
29
- analysis_plan = if force_full
30
- create_full_analysis_plan(analysis_type, granularity)
31
- else
32
- create_incremental_analysis_plan(analysis_type, granularity, previous_state)
33
- end
34
-
35
- # Execute analysis plan
36
- results = execute_analysis_plan(analysis_plan, options)
37
-
38
- # Update analysis state
39
- new_state = update_analysis_state(analysis_type, previous_state, results)
40
- save_analysis_state(analysis_type, new_state)
41
-
42
- {
43
- analysis_type: analysis_type,
44
- granularity: granularity,
45
- plan: analysis_plan,
46
- results: results,
47
- state: new_state,
48
- incremental: !force_full
49
- }
50
- end
51
-
52
- # Analyze specific components incrementally
53
- def analyze_components_incrementally(components, analysis_type, options = {})
54
- results = {}
55
-
56
- components.each do |component|
57
- component_result = analyze_component_incrementally(component, analysis_type, options)
58
- results[component] = component_result
59
- end
60
-
61
- {
62
- components: components,
63
- analysis_type: analysis_type,
64
- results: results,
65
- summary: generate_component_summary(results)
66
- }
67
- end
68
-
69
- # Analyze files incrementally
70
- def analyze_files_incrementally(files, analysis_type, options = {})
71
- results = {}
72
-
73
- files.each do |file|
74
- file_result = analyze_file_incrementally(file, analysis_type, options)
75
- results[file] = file_result
76
- end
77
-
78
- {
79
- files: files,
80
- analysis_type: analysis_type,
81
- results: results,
82
- summary: generate_file_summary(results)
83
- }
84
- end
85
-
86
- # Get incremental analysis status
87
- def get_incremental_status(analysis_type)
88
- state = load_analysis_state(analysis_type)
89
-
90
- {
91
- analysis_type: analysis_type,
92
- last_analysis: state[:last_analysis],
93
- total_components: state[:total_components] || 0,
94
- analyzed_components: state[:analyzed_components] || 0,
95
- pending_components: state[:pending_components] || 0,
96
- analysis_coverage: calculate_coverage(state),
97
- last_modified: state[:last_modified]
98
- }
99
- end
100
-
101
- # Get analysis recommendations
102
- def get_analysis_recommendations(analysis_type)
103
- state = load_analysis_state(analysis_type)
104
- recommendations = []
105
-
106
- # Check for outdated analysis
107
- if state[:last_analysis] && (Time.now - state[:last_analysis]) > 24 * 60 * 60 # 24 hours
108
- recommendations << {
109
- type: "outdated_analysis",
110
- priority: "medium",
111
- message: "Analysis is more than 24 hours old",
112
- action: "Consider running full analysis"
113
- }
114
- end
115
-
116
- # Check for low coverage
117
- coverage = calculate_coverage(state)
118
- if coverage < 0.8
119
- recommendations << {
120
- type: "low_coverage",
121
- priority: "high",
122
- message: "Analysis coverage is #{coverage * 100}%",
123
- action: "Run incremental analysis to improve coverage"
124
- }
125
- end
126
-
127
- # Check for pending components
128
- if state[:pending_components] && state[:pending_components] > 0
129
- recommendations << {
130
- type: "pending_components",
131
- priority: "medium",
132
- message: "#{state[:pending_components]} components pending analysis",
133
- action: "Run incremental analysis for pending components"
134
- }
135
- end
136
-
137
- recommendations
138
- end
139
-
140
- # Reset incremental analysis state
141
- def reset_incremental_state(analysis_type)
142
- state_file = get_state_file_path(analysis_type)
143
- File.delete(state_file) if File.exist?(state_file)
144
-
145
- {
146
- analysis_type: analysis_type,
147
- reset: true,
148
- timestamp: Time.now
149
- }
150
- end
151
-
152
- # Get analysis history
153
- def get_analysis_history(analysis_type, limit = 10)
154
- state = load_analysis_state(analysis_type)
155
- history = state[:history] || []
156
-
157
- history.last(limit).map do |entry|
158
- {
159
- timestamp: entry[:timestamp],
160
- type: entry[:type],
161
- components_analyzed: entry[:components_analyzed],
162
- duration: entry[:duration],
163
- coverage: entry[:coverage]
164
- }
165
- end
166
- end
167
-
168
- private
169
-
170
- def load_analysis_state(analysis_type)
171
- state_file = get_state_file_path(analysis_type)
172
- return create_initial_state(analysis_type) unless File.exist?(state_file)
173
-
174
- YAML.load_file(state_file) || create_initial_state(analysis_type)
175
- end
176
-
177
- def save_analysis_state(analysis_type, state)
178
- state_file = get_state_file_path(analysis_type)
179
- state[:last_modified] = Time.now
180
-
181
- File.write(state_file, YAML.dump(state))
182
- end
183
-
184
- def get_state_file_path(analysis_type)
185
- File.join(@project_dir, ".aidp-#{analysis_type}-state.yml")
186
- end
187
-
188
- def create_initial_state(analysis_type)
189
- {
190
- analysis_type: analysis_type,
191
- created_at: Time.now,
192
- last_analysis: nil,
193
- total_components: 0,
194
- analyzed_components: 0,
195
- pending_components: 0,
196
- components: {},
197
- history: []
198
- }
199
- end
200
-
201
- def create_full_analysis_plan(analysis_type, granularity)
202
- components = discover_components(granularity)
203
-
204
- {
205
- type: "full",
206
- granularity: granularity,
207
- components: components,
208
- total_components: components.length,
209
- estimated_duration: estimate_analysis_duration(components, analysis_type)
210
- }
211
- end
212
-
213
- def create_incremental_analysis_plan(analysis_type, granularity, previous_state)
214
- all_components = discover_components(granularity)
215
- analyzed_components = previous_state[:components] || {}
216
-
217
- # Identify components that need analysis
218
- components_to_analyze = []
219
-
220
- all_components.each do |component|
221
- component_info = analyzed_components[component]
222
-
223
- if !component_info || needs_reanalysis?(component, component_info, analysis_type)
224
- components_to_analyze << component
225
- end
226
- end
227
-
228
- {
229
- type: "incremental",
230
- granularity: granularity,
231
- components: components_to_analyze,
232
- total_components: all_components.length,
233
- components_to_analyze: components_to_analyze.length,
234
- estimated_duration: estimate_analysis_duration(components_to_analyze, analysis_type)
235
- }
236
- end
237
-
238
- def discover_components(granularity)
239
- case granularity
240
- when "file"
241
- discover_files
242
- when "directory"
243
- discover_directories
244
- when "component"
245
- discover_components_by_structure
246
- when "feature"
247
- discover_features
248
- when "module"
249
- discover_modules
250
- else
251
- discover_files # Default to file-level
252
- end
253
- end
254
-
255
- def discover_files
256
- files = []
257
-
258
- Dir.glob(File.join(@project_dir, "**", "*.rb")).each do |file|
259
- relative_path = file.sub(@project_dir + "/", "")
260
- files << relative_path unless relative_path.start_with?(".")
261
- end
262
-
263
- files
264
- end
265
-
266
- def discover_directories
267
- directories = []
268
-
269
- Dir.glob(File.join(@project_dir, "**", "*/")).each do |dir|
270
- relative_path = dir.sub(@project_dir + "/", "").chomp("/")
271
- directories << relative_path unless relative_path.start_with?(".")
272
- end
273
-
274
- directories
275
- end
276
-
277
- def discover_components_by_structure
278
- components = []
279
-
280
- # Look for common component patterns
281
- component_patterns = [
282
- "app/models/**/*.rb",
283
- "app/controllers/**/*.rb",
284
- "app/services/**/*.rb",
285
- "lib/**/*.rb",
286
- "spec/**/*.rb"
287
- ]
288
-
289
- component_patterns.each do |pattern|
290
- Dir.glob(File.join(@project_dir, pattern)).each do |file|
291
- relative_path = file.sub(@project_dir + "/", "")
292
- components << relative_path
293
- end
294
- end
295
-
296
- components
297
- end
298
-
299
- def discover_features
300
- features = []
301
-
302
- # Look for feature directories
303
- feature_dirs = [
304
- "app/features",
305
- "features",
306
- "app/views",
307
- "app/controllers"
308
- ]
309
-
310
- feature_dirs.each do |dir|
311
- full_path = File.join(@project_dir, dir)
312
- next unless Dir.exist?(full_path)
313
-
314
- Dir.entries(full_path).each do |entry|
315
- next if entry.start_with?(".")
316
-
317
- feature_path = File.join(dir, entry)
318
- features << feature_path if Dir.exist?(File.join(@project_dir, feature_path))
319
- end
320
- end
321
-
322
- features
323
- end
324
-
325
- def discover_modules
326
- modules = []
327
-
328
- # Look for module files
329
- Dir.glob(File.join(@project_dir, "**", "*.rb")).each do |file|
330
- content = File.read(file)
331
- if content.include?("module ") || content.include?("class ")
332
- relative_path = file.sub(@project_dir + "/", "")
333
- modules << relative_path
334
- end
335
- end
336
-
337
- modules
338
- end
339
-
340
- def needs_reanalysis?(component, component_info, analysis_type)
341
- return true unless component_info[:last_analysis]
342
-
343
- # Check if component has been modified since last analysis
344
- component_path = File.join(@project_dir, component)
345
- return true unless File.exist?(component_path)
346
-
347
- last_modified = File.mtime(component_path)
348
- last_analysis = component_info[:last_analysis]
349
-
350
- # Reanalyze if component was modified after last analysis
351
- last_modified > last_analysis
352
- end
353
-
354
- def execute_analysis_plan(plan, options)
355
- results = {
356
- plan: plan,
357
- start_time: Time.now,
358
- results: {},
359
- errors: []
360
- }
361
-
362
- plan[:components].each do |component|
363
- component_result = analyze_component(component, plan[:analysis_type], options)
364
- results[:results][component] = component_result
365
- end
366
-
367
- results[:end_time] = Time.now
368
- results[:duration] = results[:end_time] - results[:start_time]
369
-
370
- results
371
- end
372
-
373
- def analyze_component(component, analysis_type, options)
374
- # This is a placeholder for actual analysis logic
375
- # In a real implementation, this would call the appropriate analysis tools
376
-
377
- {
378
- component: component,
379
- analysis_type: analysis_type,
380
- analyzed_at: Time.now,
381
- status: "completed",
382
- metrics: generate_component_metrics(component, analysis_type),
383
- findings: generate_component_findings(component, analysis_type)
384
- }
385
- end
386
-
387
- def analyze_component_incrementally(component, analysis_type, options)
388
- component_info = get_component_info(component)
389
-
390
- if needs_reanalysis?(component, component_info, analysis_type)
391
- result = analyze_component(component, analysis_type, options)
392
- update_component_info(component, result)
393
- result
394
- else
395
- {
396
- component: component,
397
- analysis_type: analysis_type,
398
- status: "skipped",
399
- reason: "No changes detected",
400
- last_analysis: component_info[:last_analysis]
401
- }
402
- end
403
- end
404
-
405
- def analyze_file_incrementally(file, analysis_type, options)
406
- file_info = get_file_info(file)
407
-
408
- if needs_reanalysis?(file, file_info, analysis_type)
409
- result = analyze_component(file, analysis_type, options)
410
- update_file_info(file, result)
411
- result
412
- else
413
- {
414
- file: file,
415
- analysis_type: analysis_type,
416
- status: "skipped",
417
- reason: "No changes detected",
418
- last_analysis: file_info[:last_analysis]
419
- }
420
- end
421
- end
422
-
423
- def update_analysis_state(analysis_type, previous_state, results)
424
- new_state = previous_state.dup
425
- new_state[:last_analysis] = Time.now
426
- new_state[:total_components] = results[:plan][:total_components]
427
-
428
- # Update component information
429
- results[:results].each do |component, result|
430
- new_state[:components][component] = {
431
- last_analysis: Time.now,
432
- analysis_type: analysis_type,
433
- status: result[:status],
434
- metrics: result[:metrics]
435
- }
436
- end
437
-
438
- new_state[:analyzed_components] = new_state[:components].length
439
- new_state[:pending_components] = new_state[:total_components] - new_state[:analyzed_components]
440
-
441
- # Add to history
442
- new_state[:history] ||= []
443
- new_state[:history] << {
444
- timestamp: Time.now,
445
- type: results[:plan][:type],
446
- components_analyzed: results[:results].length,
447
- duration: results[:duration],
448
- coverage: calculate_coverage(new_state)
449
- }
450
-
451
- new_state
452
- end
453
-
454
- def calculate_coverage(state)
455
- return 0.0 if state[:total_components] == 0
456
-
457
- state[:analyzed_components].to_f / state[:total_components]
458
- end
459
-
460
- def estimate_analysis_duration(components, analysis_type)
461
- # Simple estimation based on component count
462
- base_duration_per_component = case analysis_type
463
- when "static_analysis"
464
- 30 # seconds
465
- when "security_analysis"
466
- 60 # seconds
467
- when "performance_analysis"
468
- 45 # seconds
469
- else
470
- 30 # seconds
471
- end
472
-
473
- components.length * base_duration_per_component
474
- end
475
-
476
- def generate_component_metrics(component, analysis_type)
477
- # Placeholder for actual metrics generation
478
- {
479
- complexity: rand(1..10),
480
- lines_of_code: rand(10..500),
481
- maintainability_index: rand(50..100)
482
- }
483
- end
484
-
485
- def generate_component_findings(component, analysis_type)
486
- # Placeholder for actual findings generation
487
- []
488
- end
489
-
490
- def get_component_info(component)
491
- state = load_analysis_state("general")
492
- state[:components][component] || {}
493
- end
494
-
495
- def update_component_info(component, result)
496
- state = load_analysis_state("general")
497
- state[:components][component] = {
498
- last_analysis: Time.now,
499
- status: result[:status],
500
- metrics: result[:metrics]
501
- }
502
- save_analysis_state("general", state)
503
- end
504
-
505
- def get_file_info(file)
506
- get_component_info(file)
507
- end
508
-
509
- def update_file_info(file, result)
510
- update_component_info(file, result)
511
- end
512
-
513
- def generate_component_summary(results)
514
- total_components = results.length
515
- analyzed_components = results.count { |_, result| result[:status] == "completed" }
516
- skipped_components = results.count { |_, result| result[:status] == "skipped" }
517
- failed_components = results.count { |_, result| result[:status] == "failed" }
518
-
519
- {
520
- total_components: total_components,
521
- analyzed_components: analyzed_components,
522
- skipped_components: skipped_components,
523
- failed_components: failed_components,
524
- success_rate: (total_components > 0) ? (analyzed_components.to_f / total_components * 100).round(2) : 0
525
- }
526
- end
527
-
528
- def generate_file_summary(results)
529
- generate_component_summary(results)
530
- end
531
- end
532
- end
533
- end