aidp 0.1.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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +210 -0
  4. data/bin/aidp +5 -0
  5. data/lib/aidp/analyze/agent_personas.rb +71 -0
  6. data/lib/aidp/analyze/agent_tool_executor.rb +445 -0
  7. data/lib/aidp/analyze/data_retention_manager.rb +426 -0
  8. data/lib/aidp/analyze/database.rb +243 -0
  9. data/lib/aidp/analyze/dependencies.rb +335 -0
  10. data/lib/aidp/analyze/error_handler.rb +486 -0
  11. data/lib/aidp/analyze/export_manager.rb +425 -0
  12. data/lib/aidp/analyze/feature_analyzer.rb +397 -0
  13. data/lib/aidp/analyze/focus_guidance.rb +517 -0
  14. data/lib/aidp/analyze/incremental_analyzer.rb +543 -0
  15. data/lib/aidp/analyze/language_analysis_strategies.rb +897 -0
  16. data/lib/aidp/analyze/large_analysis_progress.rb +504 -0
  17. data/lib/aidp/analyze/memory_manager.rb +365 -0
  18. data/lib/aidp/analyze/parallel_processor.rb +460 -0
  19. data/lib/aidp/analyze/performance_optimizer.rb +694 -0
  20. data/lib/aidp/analyze/prioritizer.rb +402 -0
  21. data/lib/aidp/analyze/progress.rb +75 -0
  22. data/lib/aidp/analyze/progress_visualizer.rb +320 -0
  23. data/lib/aidp/analyze/report_generator.rb +582 -0
  24. data/lib/aidp/analyze/repository_chunker.rb +702 -0
  25. data/lib/aidp/analyze/ruby_maat_integration.rb +572 -0
  26. data/lib/aidp/analyze/runner.rb +245 -0
  27. data/lib/aidp/analyze/static_analysis_detector.rb +577 -0
  28. data/lib/aidp/analyze/steps.rb +53 -0
  29. data/lib/aidp/analyze/storage.rb +600 -0
  30. data/lib/aidp/analyze/tool_configuration.rb +456 -0
  31. data/lib/aidp/analyze/tool_modernization.rb +750 -0
  32. data/lib/aidp/execute/progress.rb +76 -0
  33. data/lib/aidp/execute/runner.rb +135 -0
  34. data/lib/aidp/execute/steps.rb +113 -0
  35. data/lib/aidp/shared/cli.rb +117 -0
  36. data/lib/aidp/shared/config.rb +35 -0
  37. data/lib/aidp/shared/project_detector.rb +119 -0
  38. data/lib/aidp/shared/providers/anthropic.rb +26 -0
  39. data/lib/aidp/shared/providers/base.rb +17 -0
  40. data/lib/aidp/shared/providers/cursor.rb +102 -0
  41. data/lib/aidp/shared/providers/gemini.rb +26 -0
  42. data/lib/aidp/shared/providers/macos_ui.rb +26 -0
  43. data/lib/aidp/shared/sync.rb +15 -0
  44. data/lib/aidp/shared/util.rb +41 -0
  45. data/lib/aidp/shared/version.rb +7 -0
  46. data/lib/aidp/shared/workspace.rb +21 -0
  47. data/lib/aidp.rb +53 -0
  48. data/templates/ANALYZE/01_REPOSITORY_ANALYSIS.md +100 -0
  49. data/templates/ANALYZE/02_ARCHITECTURE_ANALYSIS.md +151 -0
  50. data/templates/ANALYZE/03_TEST_ANALYSIS.md +182 -0
  51. data/templates/ANALYZE/04_FUNCTIONALITY_ANALYSIS.md +200 -0
  52. data/templates/ANALYZE/05_DOCUMENTATION_ANALYSIS.md +202 -0
  53. data/templates/ANALYZE/06_STATIC_ANALYSIS.md +233 -0
  54. data/templates/ANALYZE/07_REFACTORING_RECOMMENDATIONS.md +316 -0
  55. data/templates/COMMON/AGENT_BASE.md +129 -0
  56. data/templates/COMMON/CONVENTIONS.md +19 -0
  57. data/templates/COMMON/TEMPLATES/ADR_TEMPLATE.md +21 -0
  58. data/templates/COMMON/TEMPLATES/DOMAIN_CHARTER.md +27 -0
  59. data/templates/COMMON/TEMPLATES/EVENT_EXAMPLE.yaml +16 -0
  60. data/templates/COMMON/TEMPLATES/MERMAID_C4.md +46 -0
  61. data/templates/COMMON/TEMPLATES/OPENAPI_STUB.yaml +11 -0
  62. data/templates/EXECUTE/00_PRD.md +36 -0
  63. data/templates/EXECUTE/01_NFRS.md +27 -0
  64. data/templates/EXECUTE/02A_ARCH_GATE_QUESTIONS.md +13 -0
  65. data/templates/EXECUTE/02_ARCHITECTURE.md +42 -0
  66. data/templates/EXECUTE/03_ADR_FACTORY.md +22 -0
  67. data/templates/EXECUTE/04_DOMAIN_DECOMPOSITION.md +24 -0
  68. data/templates/EXECUTE/05_CONTRACTS.md +27 -0
  69. data/templates/EXECUTE/06_THREAT_MODEL.md +23 -0
  70. data/templates/EXECUTE/07_TEST_PLAN.md +24 -0
  71. data/templates/EXECUTE/08_TASKS.md +29 -0
  72. data/templates/EXECUTE/09_SCAFFOLDING_DEVEX.md +25 -0
  73. data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +30 -0
  74. data/templates/EXECUTE/11_STATIC_ANALYSIS.md +22 -0
  75. data/templates/EXECUTE/12_OBSERVABILITY_SLOS.md +21 -0
  76. data/templates/EXECUTE/13_DELIVERY_ROLLOUT.md +21 -0
  77. data/templates/EXECUTE/14_DOCS_PORTAL.md +23 -0
  78. data/templates/EXECUTE/15_POST_RELEASE.md +25 -0
  79. metadata +301 -0
@@ -0,0 +1,504 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+ require "time"
6
+ require "securerandom"
7
+
8
+ module Aidp
9
+ class LargeAnalysisProgress
10
+ # Progress tracking states
11
+ PROGRESS_STATES = %w[pending running paused completed failed cancelled].freeze
12
+
13
+ # Default configuration
14
+ DEFAULT_CONFIG = {
15
+ checkpoint_interval: 100, # Save progress every 100 items
16
+ max_checkpoints: 50, # Keep last 50 checkpoints
17
+ progress_file: ".aidp-large-analysis-progress.yml",
18
+ auto_save: true,
19
+ detailed_logging: false
20
+ }.freeze
21
+
22
+ def initialize(project_dir = Dir.pwd, config = {})
23
+ @project_dir = project_dir
24
+ @config = DEFAULT_CONFIG.merge(config)
25
+ @progress_file = File.join(@project_dir, @config[:progress_file])
26
+ @current_progress = load_progress || create_initial_progress
27
+ @checkpoints = []
28
+ @start_time = nil
29
+ @last_save_time = Time.now
30
+ end
31
+
32
+ # Start a large analysis job
33
+ def start_analysis(analysis_config)
34
+ @current_progress = {
35
+ id: generate_analysis_id,
36
+ state: "running",
37
+ config: analysis_config,
38
+ start_time: Time.now,
39
+ last_update: Time.now,
40
+ total_items: analysis_config[:total_items] || 0,
41
+ processed_items: 0,
42
+ failed_items: 0,
43
+ current_phase: "initialization",
44
+ phases: analysis_config[:phases] || [],
45
+ phase_progress: {},
46
+ checkpoints: [],
47
+ errors: [],
48
+ warnings: [],
49
+ statistics: {
50
+ items_per_second: 0,
51
+ estimated_completion: nil,
52
+ memory_usage: 0,
53
+ cpu_usage: 0
54
+ }
55
+ }
56
+
57
+ @start_time = @current_progress[:start_time]
58
+ save_progress
59
+
60
+ @current_progress
61
+ end
62
+
63
+ # Update progress for current item
64
+ def update_item_progress(item_index, item_data = {})
65
+ return unless @current_progress
66
+
67
+ @current_progress[:processed_items] += 1
68
+ @current_progress[:last_update] = Time.now
69
+
70
+ # Update statistics
71
+ update_statistics
72
+
73
+ # Check if checkpoint should be saved
74
+ save_checkpoint(item_index, item_data) if should_save_checkpoint?
75
+
76
+ # Auto-save if enabled
77
+ save_progress if @config[:auto_save] && should_auto_save?
78
+
79
+ @current_progress
80
+ end
81
+
82
+ # Update phase progress
83
+ def update_phase_progress(phase_name, phase_data = {})
84
+ return unless @current_progress
85
+
86
+ @current_progress[:current_phase] = phase_name
87
+ @current_progress[:phase_progress][phase_name] = {
88
+ start_time: Time.now,
89
+ items_processed: 0,
90
+ items_failed: 0,
91
+ data: phase_data
92
+ }
93
+
94
+ save_progress
95
+ @current_progress
96
+ end
97
+
98
+ # Mark item as failed
99
+ def mark_item_failed(item_index, error_data = {})
100
+ return unless @current_progress
101
+
102
+ @current_progress[:failed_items] += 1
103
+ @current_progress[:errors] << {
104
+ item_index: item_index,
105
+ timestamp: Time.now,
106
+ error: error_data[:error],
107
+ details: error_data[:details]
108
+ }
109
+
110
+ # Update current phase if applicable
111
+ if @current_progress[:current_phase] && @current_progress[:phase_progress][@current_progress[:current_phase]]
112
+ @current_progress[:phase_progress][@current_progress[:current_phase]][:items_failed] += 1
113
+ end
114
+
115
+ save_progress
116
+ @current_progress
117
+ end
118
+
119
+ # Pause analysis
120
+ def pause_analysis(reason = nil)
121
+ return unless @current_progress
122
+
123
+ @current_progress[:state] = "paused"
124
+ @current_progress[:pause_reason] = reason
125
+ @current_progress[:pause_time] = Time.now
126
+ @current_progress[:last_update] = Time.now
127
+
128
+ save_progress
129
+ @current_progress
130
+ end
131
+
132
+ # Resume analysis
133
+ def resume_analysis
134
+ return unless @current_progress
135
+
136
+ @current_progress[:state] = "running"
137
+ @current_progress[:resume_time] = Time.now
138
+ @current_progress[:last_update] = Time.now
139
+
140
+ # Calculate pause duration
141
+ if @current_progress[:pause_time]
142
+ pause_duration = @current_progress[:resume_time] - @current_progress[:pause_time]
143
+ @current_progress[:total_pause_time] ||= 0
144
+ @current_progress[:total_pause_time] += pause_duration
145
+ end
146
+
147
+ save_progress
148
+ @current_progress
149
+ end
150
+
151
+ # Complete analysis
152
+ def complete_analysis(completion_data = {})
153
+ return unless @current_progress
154
+
155
+ @current_progress[:state] = "completed"
156
+ @current_progress[:completion_time] = Time.now
157
+ @current_progress[:last_update] = Time.now
158
+ @current_progress[:completion_data] = completion_data
159
+
160
+ # Calculate final statistics
161
+ calculate_final_statistics
162
+
163
+ save_progress
164
+ @current_progress
165
+ end
166
+
167
+ # Fail analysis
168
+ def fail_analysis(error_data = {})
169
+ return unless @current_progress
170
+
171
+ @current_progress[:state] = "failed"
172
+ @current_progress[:failure_time] = Time.now
173
+ @current_progress[:last_update] = Time.now
174
+ @current_progress[:failure_data] = error_data
175
+
176
+ save_progress
177
+ @current_progress
178
+ end
179
+
180
+ # Cancel analysis
181
+ def cancel_analysis(reason = nil)
182
+ return unless @current_progress
183
+
184
+ @current_progress[:state] = "cancelled"
185
+ @current_progress[:cancellation_time] = Time.now
186
+ @current_progress[:last_update] = Time.now
187
+ @current_progress[:cancellation_reason] = reason
188
+
189
+ save_progress
190
+ @current_progress
191
+ end
192
+
193
+ # Get current progress
194
+ def get_progress
195
+ return nil unless @current_progress
196
+
197
+ # Update statistics before returning
198
+ update_statistics
199
+
200
+ {
201
+ id: @current_progress[:id],
202
+ state: @current_progress[:state],
203
+ progress_percentage: calculate_progress_percentage,
204
+ processed_items: @current_progress[:processed_items],
205
+ total_items: @current_progress[:total_items],
206
+ failed_items: @current_progress[:failed_items],
207
+ current_phase: @current_progress[:current_phase],
208
+ elapsed_time: calculate_elapsed_time,
209
+ estimated_remaining: calculate_estimated_remaining,
210
+ statistics: @current_progress[:statistics],
211
+ errors: @current_progress[:errors].last(10), # Last 10 errors
212
+ warnings: @current_progress[:warnings].last(10) # Last 10 warnings
213
+ }
214
+ end
215
+
216
+ # Get detailed progress report
217
+ def get_detailed_progress
218
+ return nil unless @current_progress
219
+
220
+ {
221
+ basic_progress: get_progress,
222
+ phase_progress: @current_progress[:phase_progress],
223
+ all_errors: @current_progress[:errors],
224
+ all_warnings: @current_progress[:warnings],
225
+ checkpoints: @current_progress[:checkpoints],
226
+ configuration: @current_progress[:config],
227
+ timing: {
228
+ start_time: @current_progress[:start_time],
229
+ last_update: @current_progress[:last_update],
230
+ elapsed_time: calculate_elapsed_time,
231
+ pause_time: @current_progress[:total_pause_time] || 0,
232
+ effective_time: calculate_effective_time
233
+ }
234
+ }
235
+ end
236
+
237
+ # Get progress history
238
+ def get_progress_history(limit = 10)
239
+ return [] unless File.exist?(@progress_file)
240
+
241
+ begin
242
+ progress_data = YAML.load_file(@progress_file)
243
+ history = progress_data[:history] || []
244
+ history.last(limit)
245
+ rescue
246
+ []
247
+ end
248
+ end
249
+
250
+ # Reset progress
251
+ def reset_progress
252
+ @current_progress = create_initial_progress
253
+ @checkpoints = []
254
+ @start_time = nil
255
+ @last_save_time = Time.now
256
+
257
+ # Clear progress file
258
+ File.delete(@progress_file) if File.exist?(@progress_file)
259
+
260
+ @current_progress
261
+ end
262
+
263
+ # Export progress data
264
+ def export_progress(format = "json")
265
+ return nil unless @current_progress
266
+
267
+ case format.downcase
268
+ when "json"
269
+ JSON.pretty_generate(@current_progress)
270
+ when "yaml"
271
+ YAML.dump(@current_progress)
272
+ else
273
+ raise "Unsupported export format: #{format}"
274
+ end
275
+ end
276
+
277
+ # Import progress data
278
+ def import_progress(data, format = "json")
279
+ parsed_data = case format.downcase
280
+ when "json"
281
+ JSON.parse(data)
282
+ when "yaml"
283
+ YAML.load(data)
284
+ else
285
+ raise "Unsupported import format: #{format}"
286
+ end
287
+
288
+ @current_progress = parsed_data
289
+ save_progress
290
+
291
+ {
292
+ success: true,
293
+ imported_progress: @current_progress
294
+ }
295
+ rescue => e
296
+ {
297
+ success: false,
298
+ error: e.message
299
+ }
300
+ end
301
+
302
+ private
303
+
304
+ def load_progress
305
+ return nil unless File.exist?(@progress_file)
306
+
307
+ begin
308
+ YAML.load_file(@progress_file)
309
+ rescue
310
+ nil
311
+ end
312
+ end
313
+
314
+ def save_progress
315
+ return unless @current_progress
316
+
317
+ # Add to history if this is a significant update
318
+ add_to_history if should_add_to_history?
319
+
320
+ # Save current progress
321
+ File.write(@progress_file, YAML.dump(@current_progress))
322
+ @last_save_time = Time.now
323
+ end
324
+
325
+ def create_initial_progress
326
+ {
327
+ id: generate_analysis_id,
328
+ state: "pending",
329
+ start_time: nil,
330
+ last_update: Time.now,
331
+ total_items: 0,
332
+ processed_items: 0,
333
+ failed_items: 0,
334
+ current_phase: "initialization",
335
+ phases: [],
336
+ phase_progress: {},
337
+ checkpoints: [],
338
+ errors: [],
339
+ warnings: [],
340
+ statistics: {
341
+ items_per_second: 0,
342
+ estimated_completion: nil,
343
+ memory_usage: 0,
344
+ cpu_usage: 0
345
+ }
346
+ }
347
+ end
348
+
349
+ def generate_analysis_id
350
+ timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
351
+ "analysis_#{timestamp}_#{SecureRandom.hex(4)}"
352
+ end
353
+
354
+ def should_save_checkpoint?
355
+ return false unless @current_progress
356
+
357
+ @current_progress[:processed_items] % @config[:checkpoint_interval] == 0
358
+ end
359
+
360
+ def save_checkpoint(item_index, item_data)
361
+ return unless @current_progress
362
+
363
+ checkpoint = {
364
+ timestamp: Time.now,
365
+ item_index: item_index,
366
+ processed_items: @current_progress[:processed_items],
367
+ failed_items: @current_progress[:failed_items],
368
+ current_phase: @current_progress[:current_phase],
369
+ data: item_data
370
+ }
371
+
372
+ @current_progress[:checkpoints] << checkpoint
373
+
374
+ # Keep only the last N checkpoints
375
+ return unless @current_progress[:checkpoints].length > @config[:max_checkpoints]
376
+
377
+ @current_progress[:checkpoints] = @current_progress[:checkpoints].last(@config[:max_checkpoints])
378
+ end
379
+
380
+ def should_auto_save?
381
+ return false unless @current_progress
382
+
383
+ (Time.now - @last_save_time) > 60 # Save every minute
384
+ end
385
+
386
+ def should_add_to_history?
387
+ return false unless @current_progress
388
+
389
+ # Add to history on significant events
390
+ %w[completed failed cancelled].include?(@current_progress[:state])
391
+ end
392
+
393
+ def add_to_history
394
+ return unless @current_progress
395
+
396
+ history_file = @progress_file.sub(".yml", "_history.yml")
397
+ history = []
398
+
399
+ if File.exist?(history_file)
400
+ begin
401
+ history_data = YAML.load_file(history_file)
402
+ history = history_data[:history] || []
403
+ rescue
404
+ history = []
405
+ end
406
+ end
407
+
408
+ # Add current progress to history
409
+ history << {
410
+ timestamp: Time.now,
411
+ progress: @current_progress.dup
412
+ }
413
+
414
+ # Keep only last 100 entries
415
+ history = history.last(100)
416
+
417
+ # Save history
418
+ File.write(history_file, YAML.dump({history: history}))
419
+ end
420
+
421
+ def update_statistics
422
+ return unless @current_progress && @start_time
423
+
424
+ elapsed_time = calculate_elapsed_time
425
+ return if elapsed_time <= 0
426
+
427
+ # Calculate items per second
428
+ @current_progress[:statistics][:items_per_second] =
429
+ @current_progress[:processed_items].to_f / elapsed_time
430
+
431
+ # Calculate estimated completion
432
+ if @current_progress[:statistics][:items_per_second] > 0
433
+ remaining_items = @current_progress[:total_items] - @current_progress[:processed_items]
434
+ estimated_seconds = remaining_items / @current_progress[:statistics][:items_per_second]
435
+ @current_progress[:statistics][:estimated_completion] = Time.now + estimated_seconds
436
+ end
437
+
438
+ # Update resource usage (simplified)
439
+ @current_progress[:statistics][:memory_usage] = get_memory_usage
440
+ @current_progress[:statistics][:cpu_usage] = get_cpu_usage
441
+ end
442
+
443
+ def calculate_final_statistics
444
+ return unless @current_progress
445
+
446
+ total_time = calculate_elapsed_time
447
+ effective_time = calculate_effective_time
448
+
449
+ @current_progress[:final_statistics] = {
450
+ total_time: total_time,
451
+ effective_time: effective_time,
452
+ pause_time: @current_progress[:total_pause_time] || 0,
453
+ average_items_per_second: @current_progress[:processed_items].to_f / effective_time,
454
+ success_rate: calculate_success_rate,
455
+ total_errors: @current_progress[:errors].length,
456
+ total_warnings: @current_progress[:warnings].length
457
+ }
458
+ end
459
+
460
+ def calculate_progress_percentage
461
+ return 0 unless @current_progress && @current_progress[:total_items] > 0
462
+
463
+ (@current_progress[:processed_items].to_f / @current_progress[:total_items] * 100).round(2)
464
+ end
465
+
466
+ def calculate_elapsed_time
467
+ return 0 unless @current_progress && @current_progress[:start_time]
468
+
469
+ end_time = @current_progress[:last_update] || Time.now
470
+ end_time - @current_progress[:start_time]
471
+ end
472
+
473
+ def calculate_effective_time
474
+ elapsed_time = calculate_elapsed_time
475
+ pause_time = @current_progress[:total_pause_time] || 0
476
+ elapsed_time - pause_time
477
+ end
478
+
479
+ def calculate_estimated_remaining
480
+ return nil unless @current_progress && @current_progress[:statistics][:items_per_second] > 0
481
+
482
+ remaining_items = @current_progress[:total_items] - @current_progress[:processed_items]
483
+ remaining_items / @current_progress[:statistics][:items_per_second]
484
+ end
485
+
486
+ def calculate_success_rate
487
+ return 0 unless @current_progress && @current_progress[:processed_items] > 0
488
+
489
+ successful_items = @current_progress[:processed_items] - @current_progress[:failed_items]
490
+ (successful_items.to_f / @current_progress[:processed_items] * 100).round(2)
491
+ end
492
+
493
+ def get_memory_usage
494
+ # Get current memory usage in MB
495
+ Process.getrusage(:SELF).maxrss / 1024.0
496
+ end
497
+
498
+ def get_cpu_usage
499
+ # Simplified CPU usage calculation
500
+ # In a real implementation, this would track CPU time
501
+ 0.5 # Return 50% as default
502
+ end
503
+ end
504
+ end