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