aidp 0.1.0 → 0.5.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +59 -4
  3. data/bin/aidp +2 -2
  4. data/lib/aidp/analyze/agent_personas.rb +1 -1
  5. data/lib/aidp/analyze/data_retention_manager.rb +2 -2
  6. data/lib/aidp/analyze/database.rb +99 -82
  7. data/lib/aidp/analyze/error_handler.rb +12 -76
  8. data/lib/aidp/analyze/focus_guidance.rb +2 -2
  9. data/lib/aidp/analyze/large_analysis_progress.rb +2 -2
  10. data/lib/aidp/analyze/metrics_storage.rb +336 -0
  11. data/lib/aidp/analyze/prioritizer.rb +4 -4
  12. data/lib/aidp/analyze/repository_chunker.rb +15 -13
  13. data/lib/aidp/analyze/ruby_maat_integration.rb +6 -102
  14. data/lib/aidp/analyze/runner.rb +107 -191
  15. data/lib/aidp/analyze/steps.rb +29 -30
  16. data/lib/aidp/analyze/storage.rb +234 -172
  17. data/lib/aidp/cli/jobs_command.rb +489 -0
  18. data/lib/aidp/cli/terminal_io.rb +52 -0
  19. data/lib/aidp/cli.rb +227 -0
  20. data/lib/aidp/config.rb +33 -0
  21. data/lib/aidp/core_ext/class_attribute.rb +36 -0
  22. data/lib/aidp/database/pg_adapter.rb +148 -0
  23. data/lib/aidp/database_config.rb +69 -0
  24. data/lib/aidp/database_connection.rb +72 -0
  25. data/lib/aidp/database_migration.rb +158 -0
  26. data/lib/aidp/execute/runner.rb +65 -92
  27. data/lib/aidp/execute/steps.rb +81 -82
  28. data/lib/aidp/job_manager.rb +41 -0
  29. data/lib/aidp/jobs/base_job.rb +47 -0
  30. data/lib/aidp/jobs/provider_execution_job.rb +96 -0
  31. data/lib/aidp/project_detector.rb +117 -0
  32. data/lib/aidp/provider_manager.rb +25 -0
  33. data/lib/aidp/providers/agent_supervisor.rb +348 -0
  34. data/lib/aidp/providers/anthropic.rb +187 -0
  35. data/lib/aidp/providers/base.rb +162 -0
  36. data/lib/aidp/providers/cursor.rb +304 -0
  37. data/lib/aidp/providers/gemini.rb +187 -0
  38. data/lib/aidp/providers/macos_ui.rb +24 -0
  39. data/lib/aidp/providers/supervised_base.rb +317 -0
  40. data/lib/aidp/providers/supervised_cursor.rb +22 -0
  41. data/lib/aidp/sync.rb +13 -0
  42. data/lib/aidp/util.rb +39 -0
  43. data/lib/aidp/{shared/version.rb → version.rb} +1 -3
  44. data/lib/aidp/workspace.rb +19 -0
  45. data/lib/aidp.rb +36 -45
  46. data/templates/ANALYZE/01_REPOSITORY_ANALYSIS.md +4 -4
  47. metadata +89 -45
  48. data/lib/aidp/shared/cli.rb +0 -117
  49. data/lib/aidp/shared/config.rb +0 -35
  50. data/lib/aidp/shared/project_detector.rb +0 -119
  51. data/lib/aidp/shared/providers/anthropic.rb +0 -26
  52. data/lib/aidp/shared/providers/base.rb +0 -17
  53. data/lib/aidp/shared/providers/cursor.rb +0 -102
  54. data/lib/aidp/shared/providers/gemini.rb +0 -26
  55. data/lib/aidp/shared/providers/macos_ui.rb +0 -26
  56. data/lib/aidp/shared/sync.rb +0 -15
  57. data/lib/aidp/shared/util.rb +0 -41
  58. data/lib/aidp/shared/workspace.rb +0 -21
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module Aidp
6
- module Shared
7
- module Providers
8
- class Anthropic < Base
9
- def self.available?
10
- !!Aidp::Shared::Util.which("claude")
11
- end
12
-
13
- def name = "anthropic"
14
-
15
- def send(prompt:, session: nil)
16
- raise "claude CLI not available" unless self.class.available?
17
-
18
- # Use Claude CLI for non-interactive mode
19
- cmd = ["claude", "compose", "--prompt", prompt]
20
- system(*cmd)
21
- :ok
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aidp
4
- module Shared
5
- module Providers
6
- class Base
7
- def name = raise(NotImplementedError)
8
-
9
- # Send a composed prompt string to the provider.
10
- # Return :ok when command completed successfully,
11
- # Return :interactive when starting an interactive session (for gate steps),
12
- # or return a string if we captured output and the caller should write to a file.
13
- def send(prompt:, session: nil) = raise(NotImplementedError)
14
- end
15
- end
16
- end
17
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
- require "timeout"
5
- require_relative "base"
6
- require_relative "../util"
7
-
8
- module Aidp
9
- module Shared
10
- module Providers
11
- class Cursor < Base
12
- def self.available?
13
- !!Aidp::Shared::Util.which("cursor-agent")
14
- end
15
-
16
- def name = "cursor"
17
-
18
- def send(prompt:, session: nil)
19
- raise "cursor-agent not available" unless self.class.available?
20
-
21
- # Always use non-interactive mode with -p flag
22
- cmd = ["cursor-agent", "-p"]
23
- puts "📝 Sending prompt to cursor-agent"
24
-
25
- # Enable debug output if requested
26
- if ENV["AIDP_DEBUG"]
27
- puts "🔍 Debug mode enabled - showing cursor-agent output"
28
- end
29
-
30
- # Setup logging if log file is specified
31
- log_file = ENV["AIDP_LOG_FILE"]
32
- if log_file
33
- puts "📝 Logging to: #{log_file}"
34
- end
35
-
36
- Open3.popen3(*cmd) do |stdin, stdout, stderr, wait|
37
- # Send the prompt to stdin
38
- stdin.puts prompt
39
- stdin.close
40
-
41
- # Log the prompt if debugging
42
- if ENV["AIDP_DEBUG"] || log_file
43
- prompt_log = "📝 Sending prompt to cursor-agent:\n#{prompt}"
44
- puts prompt_log if ENV["AIDP_DEBUG"]
45
- File.write(log_file, "#{Time.now.iso8601} #{prompt_log}\n", mode: "a") if log_file
46
- end
47
-
48
- # Handle debug output and logging
49
- if ENV["AIDP_DEBUG"] || log_file
50
- # Start threads to capture and display output in real-time
51
- stdout_thread = Thread.new do
52
- stdout.each_line do |line|
53
- output = "📤 cursor-agent: #{line.chomp}"
54
- puts output if ENV["AIDP_DEBUG"]
55
- File.write(log_file, "#{Time.now.iso8601} #{output}\n", mode: "a") if log_file
56
- end
57
- end
58
-
59
- stderr_thread = Thread.new do
60
- stderr.each_line do |line|
61
- output = "❌ cursor-agent error: #{line.chomp}"
62
- puts output if ENV["AIDP_DEBUG"]
63
- File.write(log_file, "#{Time.now.iso8601} #{output}\n", mode: "a") if log_file
64
- end
65
- end
66
- end
67
-
68
- # Wait for completion with a reasonable timeout
69
- begin
70
- Timeout.timeout(300) do # 5 minutes timeout
71
- result = wait.value
72
-
73
- # Stop debug threads
74
- if ENV["AIDP_DEBUG"]
75
- stdout_thread&.kill
76
- stderr_thread&.kill
77
- end
78
-
79
- return :ok if result.success?
80
- raise "cursor-agent failed with exit code #{result.exitstatus}"
81
- end
82
- rescue Timeout::Error
83
- # Stop debug threads
84
- if ENV["AIDP_DEBUG"]
85
- stdout_thread&.kill
86
- stderr_thread&.kill
87
- end
88
-
89
- # Kill the process if it's taking too long
90
- begin
91
- Process.kill("TERM", wait.pid)
92
- rescue
93
- nil
94
- end
95
- raise Timeout::Error, "cursor-agent timed out after 5 minutes"
96
- end
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module Aidp
6
- module Shared
7
- module Providers
8
- class Gemini < Base
9
- def self.available?
10
- !!Aidp::Shared::Util.which("gemini")
11
- end
12
-
13
- def name = "gemini"
14
-
15
- def send(prompt:, session: nil)
16
- raise "gemini CLI not available" unless self.class.available?
17
-
18
- # Use Gemini CLI for non-interactive mode
19
- cmd = ["gemini", "chat", "--prompt", prompt]
20
- system(*cmd)
21
- :ok
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module Aidp
6
- module Shared
7
- module Providers
8
- class MacOSUI < Base
9
- def self.available?
10
- RUBY_PLATFORM.include?("darwin")
11
- end
12
-
13
- def name = "macos"
14
-
15
- def send(prompt:, session: nil)
16
- raise "macOS UI not available on this platform" unless self.class.available?
17
-
18
- # Use macOS UI for interactive mode
19
- cmd = ["osascript", "-e", "display dialog \"#{prompt}\" with title \"Aidp\" buttons {\"OK\"} default button \"OK\""]
20
- system(*cmd)
21
- :ok
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
-
5
- module Aidp
6
- module Shared
7
- # Synchronization utilities
8
- class Sync
9
- def self.ensure_workspace_sync
10
- # Placeholder for workspace synchronization logic
11
- true
12
- end
13
- end
14
- end
15
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
-
5
- module Aidp
6
- module Shared
7
- # Utility functions shared between execute and analyze modes
8
- class Util
9
- def self.which(cmd)
10
- exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
11
- ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
12
- exts.each do |ext|
13
- exe = File.join(path, "#{cmd}#{ext}")
14
- return exe if File.executable?(exe) && !File.directory?(exe)
15
- end
16
- end
17
- nil
18
- end
19
-
20
- def self.ensure_dirs(output_files, project_dir)
21
- output_files.each do |file|
22
- dir = File.dirname(File.join(project_dir, file))
23
- FileUtils.mkdir_p(dir) unless dir == "."
24
- end
25
- end
26
-
27
- def self.safe_file_write(path, content)
28
- FileUtils.mkdir_p(File.dirname(path))
29
- File.write(path, content)
30
- end
31
-
32
- def self.project_root?(dir = Dir.pwd)
33
- File.exist?(File.join(dir, ".git")) ||
34
- File.exist?(File.join(dir, "package.json")) ||
35
- File.exist?(File.join(dir, "Gemfile")) ||
36
- File.exist?(File.join(dir, "pom.xml")) ||
37
- File.exist?(File.join(dir, "build.gradle"))
38
- end
39
- end
40
- end
41
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
- require "digest"
5
-
6
- module Aidp
7
- module Shared
8
- # Workspace management utilities
9
- class Workspace
10
- def self.current
11
- Dir.pwd
12
- end
13
-
14
- def self.ensure_project_root
15
- unless Aidp::Shared::Util.project_root?
16
- raise "Not in a project root directory. Please run from a directory with .git, package.json, Gemfile, etc."
17
- end
18
- end
19
- end
20
- end
21
- end