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,445 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
- require "json"
5
- require "timeout"
6
-
7
- module Aidp
8
- class AgentToolExecutor
9
- # Default timeout for tool execution (5 minutes)
10
- DEFAULT_TIMEOUT = 300
11
-
12
- # Default environment variables for tool execution
13
- DEFAULT_ENV = {
14
- "LANG" => "en_US.UTF-8",
15
- "LC_ALL" => "en_US.UTF-8"
16
- }.freeze
17
-
18
- def initialize(project_dir = Dir.pwd, config = {})
19
- @project_dir = project_dir
20
- @config = config
21
- @timeout = config[:timeout] || DEFAULT_TIMEOUT
22
- @env = DEFAULT_ENV.merge(config[:env] || {})
23
- @execution_log = []
24
- end
25
-
26
- # Execute a static analysis tool
27
- def execute_tool(tool_name, options = {})
28
- execution_id = generate_execution_id
29
- start_time = Time.now
30
-
31
- log_execution_start(execution_id, tool_name, options)
32
-
33
- begin
34
- result = execute_tool_with_timeout(tool_name, options)
35
- execution_time = Time.now - start_time
36
-
37
- log_execution_success(execution_id, tool_name, execution_time, result)
38
- result
39
- rescue => e
40
- execution_time = Time.now - start_time
41
- log_execution_error(execution_id, tool_name, execution_time, e)
42
- raise
43
- end
44
- end
45
-
46
- # Execute multiple tools in parallel
47
- def execute_tools_parallel(tools, options = {})
48
- results = {}
49
- threads = []
50
-
51
- tools.each do |tool_name, tool_options|
52
- thread = Thread.new do
53
- results[tool_name] = execute_tool(tool_name, tool_options)
54
- rescue => e
55
- results[tool_name] = {error: e.message, status: "failed"}
56
- end
57
- threads << thread
58
- end
59
-
60
- # Wait for all threads to complete
61
- threads.each(&:join)
62
-
63
- results
64
- end
65
-
66
- # Execute tools in sequence based on dependencies
67
- def execute_tools_sequence(tools, dependencies = {})
68
- results = {}
69
- executed = Set.new
70
-
71
- tools.each do |tool_name|
72
- # Check if dependencies are satisfied
73
- tool_deps = dependencies[tool_name] || []
74
- unless tool_deps.all? { |dep| executed.include?(dep) }
75
- raise "Dependencies not satisfied for #{tool_name}: #{tool_deps}"
76
- end
77
-
78
- results[tool_name] = execute_tool(tool_name)
79
- executed.add(tool_name)
80
- end
81
-
82
- results
83
- end
84
-
85
- # Get tool execution status
86
- def get_execution_status(execution_id)
87
- execution = @execution_log.find { |log| log[:execution_id] == execution_id }
88
- return nil unless execution
89
-
90
- {
91
- execution_id: execution_id,
92
- tool_name: execution[:tool_name],
93
- status: execution[:status],
94
- start_time: execution[:start_time],
95
- end_time: execution[:end_time],
96
- duration: execution[:duration],
97
- error: execution[:error]
98
- }
99
- end
100
-
101
- # Get execution history
102
- def get_execution_history(limit = 50)
103
- @execution_log.last(limit).map do |log|
104
- {
105
- execution_id: log[:execution_id],
106
- tool_name: log[:tool_name],
107
- status: log[:status],
108
- start_time: log[:start_time],
109
- duration: log[:duration],
110
- error: log[:error]
111
- }
112
- end
113
- end
114
-
115
- # Validate tool configuration
116
- def validate_tool_config(tool_name, options = {})
117
- errors = []
118
-
119
- # Check if tool is available
120
- errors << "Tool '#{tool_name}' is not available" unless tool_available?(tool_name)
121
-
122
- # Validate tool-specific options
123
- tool_errors = validate_tool_options(tool_name, options)
124
- errors.concat(tool_errors)
125
-
126
- errors
127
- end
128
-
129
- # Get available tools
130
- def get_available_tools
131
- available_tools = []
132
-
133
- # Check for Ruby tools
134
- available_tools.concat(check_ruby_tools) if ruby_project?
135
-
136
- # Check for JavaScript tools
137
- available_tools.concat(check_javascript_tools) if javascript_project?
138
-
139
- # Check for Python tools
140
- available_tools.concat(check_python_tools) if python_project?
141
-
142
- # Check for Java tools
143
- available_tools.concat(check_java_tools) if java_project?
144
-
145
- # Check for Go tools
146
- available_tools.concat(check_go_tools) if go_project?
147
-
148
- # Check for Rust tools
149
- available_tools.concat(check_rust_tools) if rust_project?
150
-
151
- available_tools
152
- end
153
-
154
- # Get tool execution statistics
155
- def get_execution_statistics
156
- return {} if @execution_log.empty?
157
-
158
- total_executions = @execution_log.length
159
- successful_executions = @execution_log.count { |log| log[:status] == "success" }
160
- failed_executions = @execution_log.count { |log| log[:status] == "error" }
161
-
162
- average_duration = @execution_log.sum { |log| log[:duration] || 0 } / total_executions
163
-
164
- {
165
- total_executions: total_executions,
166
- successful_executions: successful_executions,
167
- failed_executions: failed_executions,
168
- success_rate: (successful_executions.to_f / total_executions * 100).round(2),
169
- average_duration: average_duration.round(2),
170
- tools_used: @execution_log.map { |log| log[:tool_name] }.uniq
171
- }
172
- end
173
-
174
- private
175
-
176
- def execute_tool_with_timeout(tool_name, options)
177
- command = build_tool_command(tool_name, options)
178
- working_dir = options[:working_dir] || @project_dir
179
-
180
- Timeout.timeout(@timeout) do
181
- execute_command(command, working_dir, options)
182
- end
183
- end
184
-
185
- def execute_command(command, working_dir, options)
186
- stdout, stderr, status = Open3.capture3(@env, command, chdir: working_dir)
187
-
188
- {
189
- command: command,
190
- stdout: stdout,
191
- stderr: stderr,
192
- exit_code: status.exitstatus,
193
- success: status.success?,
194
- working_dir: working_dir,
195
- options: options
196
- }
197
- end
198
-
199
- def build_tool_command(tool_name, options)
200
- case tool_name
201
- when "rubocop"
202
- build_rubocop_command(options)
203
- when "reek"
204
- build_reek_command(options)
205
- when "brakeman"
206
- build_brakeman_command(options)
207
- when "bundler-audit"
208
- build_bundler_audit_command(options)
209
- when "eslint"
210
- build_eslint_command(options)
211
- when "flake8"
212
- build_flake8_command(options)
213
- when "bandit"
214
- build_bandit_command(options)
215
- when "golangci-lint"
216
- build_golangci_lint_command(options)
217
- when "clippy"
218
- build_clippy_command(options)
219
- else
220
- # Generic command building
221
- build_generic_command(tool_name, options)
222
- end
223
- end
224
-
225
- def build_rubocop_command(options)
226
- command = "bundle exec rubocop"
227
- command += " --format #{options[:format] || "json"}"
228
- command += " --out #{options[:output_file]}" if options[:output_file]
229
- command += " #{options[:paths] || "."}"
230
- command
231
- end
232
-
233
- def build_reek_command(options)
234
- command = "bundle exec reek"
235
- command += " --format #{options[:format] || "json"}"
236
- command += " --output #{options[:output_file]}" if options[:output_file]
237
- command += " #{options[:paths] || "."}"
238
- command
239
- end
240
-
241
- def build_brakeman_command(options)
242
- command = "bundle exec brakeman"
243
- command += " --format #{options[:format] || "json"}"
244
- command += " --output #{options[:output_file]}" if options[:output_file]
245
- command += " --quiet" if options[:quiet]
246
- command
247
- end
248
-
249
- def build_bundler_audit_command(options)
250
- command = "bundle exec bundle-audit"
251
- command += " --output #{options[:output_file]}" if options[:output_file]
252
- command += " --update" if options[:update]
253
- command
254
- end
255
-
256
- def build_eslint_command(options)
257
- command = "npx eslint"
258
- command += " --format #{options[:format] || "json"}"
259
- command += " --output-file #{options[:output_file]}" if options[:output_file]
260
- command += " #{options[:paths] || "."}"
261
- command
262
- end
263
-
264
- def build_flake8_command(options)
265
- command = "flake8"
266
- command += " --format #{options[:format] || "json"}"
267
- command += " --output-file #{options[:output_file]}" if options[:output_file]
268
- command += " #{options[:paths] || "."}"
269
- command
270
- end
271
-
272
- def build_bandit_command(options)
273
- command = "bandit"
274
- command += " -f #{options[:format] || "json"}"
275
- command += " -o #{options[:output_file]}" if options[:output_file]
276
- command += " -r #{options[:paths] || "."}"
277
- command
278
- end
279
-
280
- def build_golangci_lint_command(options)
281
- command = "golangci-lint run"
282
- command += " --out-format #{options[:format] || "json"}"
283
- command += " --out #{options[:output_file]}" if options[:output_file]
284
- command += " #{options[:paths] || "."}"
285
- command
286
- end
287
-
288
- def build_clippy_command(options)
289
- command = "cargo clippy"
290
- command += " --message-format #{options[:format] || "json"}"
291
- command += " --output-file #{options[:output_file]}" if options[:output_file]
292
- command
293
- end
294
-
295
- def build_generic_command(tool_name, options)
296
- command = tool_name
297
- command += " #{options[:args]}" if options[:args]
298
- command += " #{options[:paths] || "."}" unless options[:args]&.include?(".")
299
- command
300
- end
301
-
302
- def tool_available?(tool_name)
303
- case tool_name
304
- when /^bundle exec/
305
- # Ruby tool - check if bundle is available
306
- system("bundle", "--version", out: File::NULL, err: File::NULL)
307
- when /^npx/
308
- # Node.js tool - check if npm is available
309
- system("npm", "--version", out: File::NULL, err: File::NULL)
310
- when /^cargo/
311
- # Rust tool - check if cargo is available
312
- system("cargo", "--version", out: File::NULL, err: File::NULL)
313
- when /^go/
314
- # Go tool - check if go is available
315
- system("go", "version", out: File::NULL, err: File::NULL)
316
- else
317
- # Generic tool - check if command is available
318
- system("which", tool_name.split(" ").first, out: File::NULL, err: File::NULL)
319
- end
320
- end
321
-
322
- def validate_tool_options(tool_name, options)
323
- errors = []
324
-
325
- case tool_name
326
- when "rubocop"
327
- errors << "Invalid format" unless %w[json text html].include?(options[:format])
328
- when "eslint"
329
- errors << "Invalid format" unless %w[json text html].include?(options[:format])
330
- when "flake8"
331
- errors << "Invalid format" unless %w[json text html].include?(options[:format])
332
- end
333
-
334
- errors
335
- end
336
-
337
- def ruby_project?
338
- File.exist?(File.join(@project_dir, "Gemfile"))
339
- end
340
-
341
- def javascript_project?
342
- File.exist?(File.join(@project_dir, "package.json"))
343
- end
344
-
345
- def python_project?
346
- File.exist?(File.join(@project_dir, "requirements.txt")) || File.exist?(File.join(@project_dir, "setup.py"))
347
- end
348
-
349
- def java_project?
350
- File.exist?(File.join(@project_dir, "pom.xml")) || File.exist?(File.join(@project_dir, "build.gradle"))
351
- end
352
-
353
- def go_project?
354
- File.exist?(File.join(@project_dir, "go.mod"))
355
- end
356
-
357
- def rust_project?
358
- File.exist?(File.join(@project_dir, "Cargo.toml"))
359
- end
360
-
361
- def check_ruby_tools
362
- tools = []
363
- tools << "rubocop" if system("bundle", "exec", "rubocop", "--version", out: File::NULL, err: File::NULL)
364
- tools << "reek" if system("bundle", "exec", "reek", "--version", out: File::NULL, err: File::NULL)
365
- tools << "brakeman" if system("bundle", "exec", "brakeman", "--version", out: File::NULL, err: File::NULL)
366
- tools << "bundler-audit" if system("bundle", "exec", "bundle-audit", "--version", out: File::NULL,
367
- err: File::NULL)
368
- tools
369
- end
370
-
371
- def check_javascript_tools
372
- tools = []
373
- tools << "eslint" if system("npx", "eslint", "--version", out: File::NULL, err: File::NULL)
374
- tools << "prettier" if system("npx", "prettier", "--version", out: File::NULL, err: File::NULL)
375
- tools
376
- end
377
-
378
- def check_python_tools
379
- tools = []
380
- tools << "flake8" if system("flake8", "--version", out: File::NULL, err: File::NULL)
381
- tools << "bandit" if system("bandit", "--version", out: File::NULL, err: File::NULL)
382
- tools
383
- end
384
-
385
- def check_java_tools
386
- tools = []
387
- # Java tools typically require specific setup, so we'll check for common ones
388
- tools << "checkstyle" if File.exist?(File.join(@project_dir, "checkstyle.xml"))
389
- tools << "pmd" if File.exist?(File.join(@project_dir, "pmd.xml"))
390
- tools
391
- end
392
-
393
- def check_go_tools
394
- tools = []
395
- tools << "golangci-lint" if system("golangci-lint", "--version", out: File::NULL, err: File::NULL)
396
- tools << "gosec" if system("gosec", "--version", out: File::NULL, err: File::NULL)
397
- tools
398
- end
399
-
400
- def check_rust_tools
401
- tools = []
402
- tools << "clippy" if system("cargo", "clippy", "--version", out: File::NULL, err: File::NULL)
403
- tools << "cargo-audit" if system("cargo", "audit", "--version", out: File::NULL, err: File::NULL)
404
- tools
405
- end
406
-
407
- def generate_execution_id
408
- "exec_#{Time.now.to_i}_#{rand(1000)}"
409
- end
410
-
411
- def log_execution_start(execution_id, tool_name, options)
412
- @execution_log << {
413
- execution_id: execution_id,
414
- tool_name: tool_name,
415
- status: "running",
416
- start_time: Time.now,
417
- options: options
418
- }
419
- end
420
-
421
- def log_execution_success(execution_id, tool_name, duration, result)
422
- log_entry = @execution_log.find { |log| log[:execution_id] == execution_id }
423
- return unless log_entry
424
-
425
- log_entry.merge!(
426
- status: "success",
427
- end_time: Time.now,
428
- duration: duration,
429
- result: result
430
- )
431
- end
432
-
433
- def log_execution_error(execution_id, tool_name, duration, error)
434
- log_entry = @execution_log.find { |log| log[:execution_id] == execution_id }
435
- return unless log_entry
436
-
437
- log_entry.merge!(
438
- status: "error",
439
- end_time: Time.now,
440
- duration: duration,
441
- error: error.message
442
- )
443
- end
444
- end
445
- end