aidp 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/bin/aidp +2 -2
- data/lib/aidp/analyze/data_retention_manager.rb +2 -2
- data/lib/aidp/analyze/large_analysis_progress.rb +2 -2
- data/lib/aidp/analyze/prioritizer.rb +2 -2
- data/lib/aidp/analyze/repository_chunker.rb +15 -13
- data/lib/aidp/analyze/storage.rb +1 -1
- data/lib/aidp/cli.rb +168 -0
- data/lib/aidp/config.rb +33 -0
- data/lib/aidp/project_detector.rb +117 -0
- data/lib/aidp/providers/anthropic.rb +24 -0
- data/lib/aidp/providers/base.rb +15 -0
- data/lib/aidp/providers/cursor.rb +100 -0
- data/lib/aidp/providers/gemini.rb +24 -0
- data/lib/aidp/providers/macos_ui.rb +24 -0
- data/lib/aidp/sync.rb +13 -0
- data/lib/aidp/util.rb +39 -0
- data/lib/aidp/{shared/version.rb → version.rb} +1 -3
- data/lib/aidp/workspace.rb +19 -0
- data/lib/aidp.rb +13 -13
- metadata +27 -20
- data/lib/aidp/shared/cli.rb +0 -117
- data/lib/aidp/shared/config.rb +0 -35
- data/lib/aidp/shared/project_detector.rb +0 -119
- data/lib/aidp/shared/providers/anthropic.rb +0 -26
- data/lib/aidp/shared/providers/base.rb +0 -17
- data/lib/aidp/shared/providers/cursor.rb +0 -102
- data/lib/aidp/shared/providers/gemini.rb +0 -26
- data/lib/aidp/shared/providers/macos_ui.rb +0 -26
- data/lib/aidp/shared/sync.rb +0 -15
- data/lib/aidp/shared/util.rb +0 -41
- data/lib/aidp/shared/workspace.rb +0 -21
data/lib/aidp/util.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Aidp
|
6
|
+
# Utility functions shared between execute and analyze modes
|
7
|
+
class Util
|
8
|
+
def self.which(cmd)
|
9
|
+
exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
|
10
|
+
ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
|
11
|
+
exts.each do |ext|
|
12
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
13
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.ensure_dirs(output_files, project_dir)
|
20
|
+
output_files.each do |file|
|
21
|
+
dir = File.dirname(File.join(project_dir, file))
|
22
|
+
FileUtils.mkdir_p(dir) unless dir == "."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.safe_file_write(path, content)
|
27
|
+
FileUtils.mkdir_p(File.dirname(path))
|
28
|
+
File.write(path, content)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.project_root?(dir = Dir.pwd)
|
32
|
+
File.exist?(File.join(dir, ".git")) ||
|
33
|
+
File.exist?(File.join(dir, "package.json")) ||
|
34
|
+
File.exist?(File.join(dir, "Gemfile")) ||
|
35
|
+
File.exist?(File.join(dir, "pom.xml")) ||
|
36
|
+
File.exist?(File.join(dir, "build.gradle"))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "digest"
|
5
|
+
|
6
|
+
module Aidp
|
7
|
+
# Workspace management utilities
|
8
|
+
class Workspace
|
9
|
+
def self.current
|
10
|
+
Dir.pwd
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.ensure_project_root
|
14
|
+
unless Aidp::Util.project_root?
|
15
|
+
raise "Not in a project root directory. Please run from a directory with .git, package.json, Gemfile, etc."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/aidp.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Shared modules
|
4
|
-
require "aidp/
|
5
|
-
require "aidp/
|
6
|
-
require "aidp/
|
7
|
-
require "aidp/
|
8
|
-
require "aidp/
|
9
|
-
require "aidp/
|
10
|
-
require "aidp/
|
11
|
-
require "aidp/
|
12
|
-
require "aidp/
|
13
|
-
require "aidp/
|
14
|
-
require "aidp/
|
15
|
-
require "aidp/
|
4
|
+
require "aidp/version"
|
5
|
+
require "aidp/config"
|
6
|
+
require "aidp/workspace"
|
7
|
+
require "aidp/util"
|
8
|
+
require "aidp/cli"
|
9
|
+
require "aidp/project_detector"
|
10
|
+
require "aidp/sync"
|
11
|
+
require "aidp/providers/base"
|
12
|
+
require "aidp/providers/cursor"
|
13
|
+
require "aidp/providers/anthropic"
|
14
|
+
require "aidp/providers/gemini"
|
15
|
+
require "aidp/providers/macos_ui"
|
16
16
|
|
17
17
|
# Execute mode modules
|
18
18
|
require "aidp/execute/steps"
|
@@ -49,5 +49,5 @@ require "aidp/analyze/performance_optimizer"
|
|
49
49
|
require "aidp/analyze/error_handler"
|
50
50
|
|
51
51
|
module Aidp
|
52
|
-
|
52
|
+
class Error < StandardError; end
|
53
53
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aidp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bart Agapinan
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-08-
|
10
|
+
date: 2025-08-18 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: colorize
|
@@ -69,16 +69,22 @@ dependencies:
|
|
69
69
|
name: sqlite3
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- - "
|
72
|
+
- - ">="
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '1.6'
|
75
|
+
- - "<"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.0'
|
75
78
|
type: :runtime
|
76
79
|
prerelease: false
|
77
80
|
version_requirements: !ruby/object:Gem::Requirement
|
78
81
|
requirements:
|
79
|
-
- - "
|
82
|
+
- - ">="
|
80
83
|
- !ruby/object:Gem::Version
|
81
84
|
version: '1.6'
|
85
|
+
- - "<"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '3.0'
|
82
88
|
- !ruby/object:Gem::Dependency
|
83
89
|
name: thor
|
84
90
|
requirement: !ruby/object:Gem::Requirement
|
@@ -191,8 +197,9 @@ dependencies:
|
|
191
197
|
- - "~>"
|
192
198
|
- !ruby/object:Gem::Version
|
193
199
|
version: '1.0'
|
194
|
-
description:
|
195
|
-
|
200
|
+
description: The AI-Dev-Pipeline (AIDP) CLI provides a powerful, markdown-driven workflow
|
201
|
+
for software development. It supports in-depth project analysis to understand existing
|
202
|
+
codebases and an execution mode to systematically implement new features.
|
196
203
|
email:
|
197
204
|
- bart@sonic.next
|
198
205
|
executables:
|
@@ -231,21 +238,21 @@ files:
|
|
231
238
|
- lib/aidp/analyze/storage.rb
|
232
239
|
- lib/aidp/analyze/tool_configuration.rb
|
233
240
|
- lib/aidp/analyze/tool_modernization.rb
|
241
|
+
- lib/aidp/cli.rb
|
242
|
+
- lib/aidp/config.rb
|
234
243
|
- lib/aidp/execute/progress.rb
|
235
244
|
- lib/aidp/execute/runner.rb
|
236
245
|
- lib/aidp/execute/steps.rb
|
237
|
-
- lib/aidp/
|
238
|
-
- lib/aidp/
|
239
|
-
- lib/aidp/
|
240
|
-
- lib/aidp/
|
241
|
-
- lib/aidp/
|
242
|
-
- lib/aidp/
|
243
|
-
- lib/aidp/
|
244
|
-
- lib/aidp/
|
245
|
-
- lib/aidp/
|
246
|
-
- lib/aidp/
|
247
|
-
- lib/aidp/shared/version.rb
|
248
|
-
- lib/aidp/shared/workspace.rb
|
246
|
+
- lib/aidp/project_detector.rb
|
247
|
+
- lib/aidp/providers/anthropic.rb
|
248
|
+
- lib/aidp/providers/base.rb
|
249
|
+
- lib/aidp/providers/cursor.rb
|
250
|
+
- lib/aidp/providers/gemini.rb
|
251
|
+
- lib/aidp/providers/macos_ui.rb
|
252
|
+
- lib/aidp/sync.rb
|
253
|
+
- lib/aidp/util.rb
|
254
|
+
- lib/aidp/version.rb
|
255
|
+
- lib/aidp/workspace.rb
|
249
256
|
- templates/ANALYZE/01_REPOSITORY_ANALYSIS.md
|
250
257
|
- templates/ANALYZE/02_ARCHITECTURE_ANALYSIS.md
|
251
258
|
- templates/ANALYZE/03_TEST_ANALYSIS.md
|
@@ -277,7 +284,7 @@ files:
|
|
277
284
|
- templates/EXECUTE/13_DELIVERY_ROLLOUT.md
|
278
285
|
- templates/EXECUTE/14_DOCS_PORTAL.md
|
279
286
|
- templates/EXECUTE/15_POST_RELEASE.md
|
280
|
-
homepage: https://github.com/viamin/
|
287
|
+
homepage: https://github.com/viamin/aidp
|
281
288
|
licenses:
|
282
289
|
- MIT
|
283
290
|
metadata: {}
|
@@ -297,5 +304,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
304
|
requirements: []
|
298
305
|
rubygems_version: 3.6.2
|
299
306
|
specification_version: 4
|
300
|
-
summary:
|
307
|
+
summary: A CLI for AI-driven software development, from analysis to execution.
|
301
308
|
test_files: []
|
data/lib/aidp/shared/cli.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "thor"
|
4
|
-
|
5
|
-
module Aidp
|
6
|
-
module Shared
|
7
|
-
# CLI interface for both execute and analyze modes
|
8
|
-
class CLI < Thor
|
9
|
-
desc "execute [STEP]", "Run execute mode step(s)"
|
10
|
-
option :force, type: :boolean, desc: "Force execution even if dependencies are not met"
|
11
|
-
option :rerun, type: :boolean, desc: "Re-run a completed step"
|
12
|
-
def execute(project_dir = Dir.pwd, step_name = nil, custom_options = {})
|
13
|
-
if step_name
|
14
|
-
runner = Aidp::Execute::Runner.new(project_dir)
|
15
|
-
# Merge Thor options with custom options
|
16
|
-
all_options = options.merge(custom_options)
|
17
|
-
runner.run_step(step_name, all_options)
|
18
|
-
else
|
19
|
-
puts "Available execute steps:"
|
20
|
-
Aidp::Execute::Steps::SPEC.keys.each { |step| puts " - #{step}" }
|
21
|
-
progress = Aidp::Execute::Progress.new(project_dir)
|
22
|
-
next_step = progress.next_step
|
23
|
-
{status: "success", message: "Available steps listed", next_step: next_step}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
desc "analyze [STEP]", "Run analyze mode step(s)"
|
28
|
-
option :force, type: :boolean, desc: "Force execution even if dependencies are not met"
|
29
|
-
option :rerun, type: :boolean, desc: "Re-run a completed step"
|
30
|
-
def analyze(project_dir = Dir.pwd, step_name = nil, custom_options = {})
|
31
|
-
if step_name
|
32
|
-
runner = Aidp::Analyze::Runner.new(project_dir)
|
33
|
-
# Merge Thor options with custom options
|
34
|
-
all_options = options.merge(custom_options)
|
35
|
-
runner.run_step(step_name, all_options)
|
36
|
-
else
|
37
|
-
puts "Available analyze steps:"
|
38
|
-
Aidp::Analyze::Steps::SPEC.keys.each { |step| puts " - #{step}" }
|
39
|
-
progress = Aidp::Analyze::Progress.new(project_dir)
|
40
|
-
next_step = progress.next_step
|
41
|
-
{status: "success", message: "Available steps listed", next_step: next_step,
|
42
|
-
completed_steps: progress.completed_steps}
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
desc "analyze-approve STEP", "Approve a completed analyze gate step"
|
47
|
-
def analyze_approve(project_dir = Dir.pwd, step_name = nil)
|
48
|
-
progress = Aidp::Analyze::Progress.new(project_dir)
|
49
|
-
progress.mark_step_completed(step_name)
|
50
|
-
puts "✅ Approved analyze step: #{step_name}"
|
51
|
-
{status: "success", step: step_name}
|
52
|
-
end
|
53
|
-
|
54
|
-
desc "analyze-reset", "Reset analyze mode progress"
|
55
|
-
def analyze_reset(project_dir = Dir.pwd)
|
56
|
-
progress = Aidp::Analyze::Progress.new(project_dir)
|
57
|
-
progress.reset
|
58
|
-
puts "🔄 Reset analyze mode progress"
|
59
|
-
{status: "success", message: "Progress reset"}
|
60
|
-
end
|
61
|
-
|
62
|
-
desc "execute-approve STEP", "Approve a completed execute gate step"
|
63
|
-
def execute_approve(project_dir = Dir.pwd, step_name = nil)
|
64
|
-
progress = Aidp::Execute::Progress.new(project_dir)
|
65
|
-
progress.mark_step_completed(step_name)
|
66
|
-
puts "✅ Approved execute step: #{step_name}"
|
67
|
-
{status: "success", step: step_name}
|
68
|
-
end
|
69
|
-
|
70
|
-
desc "execute-reset", "Reset execute mode progress"
|
71
|
-
def execute_reset(project_dir = Dir.pwd)
|
72
|
-
progress = Aidp::Execute::Progress.new(project_dir)
|
73
|
-
progress.reset
|
74
|
-
puts "🔄 Reset execute mode progress"
|
75
|
-
{status: "success", message: "Progress reset"}
|
76
|
-
end
|
77
|
-
|
78
|
-
# Backward compatibility aliases
|
79
|
-
desc "approve STEP", "Approve a completed execute gate step (alias for execute-approve)"
|
80
|
-
def approve(project_dir = Dir.pwd, step_name = nil)
|
81
|
-
execute_approve(project_dir, step_name)
|
82
|
-
end
|
83
|
-
|
84
|
-
desc "reset", "Reset execute mode progress (alias for execute-reset)"
|
85
|
-
def reset(project_dir = Dir.pwd)
|
86
|
-
execute_reset(project_dir)
|
87
|
-
end
|
88
|
-
|
89
|
-
desc "status", "Show current progress for both modes"
|
90
|
-
def status
|
91
|
-
puts "\n📊 AI Dev Pipeline Status"
|
92
|
-
puts "=" * 50
|
93
|
-
|
94
|
-
# Execute mode status
|
95
|
-
execute_progress = Aidp::Execute::Progress.new(Dir.pwd)
|
96
|
-
puts "\n🔧 Execute Mode:"
|
97
|
-
Aidp::Execute::Steps::SPEC.keys.each do |step|
|
98
|
-
status = execute_progress.step_completed?(step) ? "✅" : "⏳"
|
99
|
-
puts " #{status} #{step}"
|
100
|
-
end
|
101
|
-
|
102
|
-
# Analyze mode status
|
103
|
-
analyze_progress = Aidp::Analyze::Progress.new(Dir.pwd)
|
104
|
-
puts "\n🔍 Analyze Mode:"
|
105
|
-
Aidp::Analyze::Steps::SPEC.keys.each do |step|
|
106
|
-
status = analyze_progress.step_completed?(step) ? "✅" : "⏳"
|
107
|
-
puts " #{status} #{step}"
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
desc "version", "Show version information"
|
112
|
-
def version
|
113
|
-
puts "Aidp version #{Aidp::Shared::VERSION}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
data/lib/aidp/shared/config.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "yaml"
|
4
|
-
|
5
|
-
module Aidp
|
6
|
-
module Shared
|
7
|
-
# Configuration management for both execute and analyze modes
|
8
|
-
class Config
|
9
|
-
def self.load(project_dir = Dir.pwd)
|
10
|
-
config_file = File.join(project_dir, ".aidp.yml")
|
11
|
-
if File.exist?(config_file)
|
12
|
-
YAML.load_file(config_file) || {}
|
13
|
-
else
|
14
|
-
{}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.templates_root
|
19
|
-
File.join(Dir.pwd, "templates")
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.analyze_templates_root
|
23
|
-
File.join(Dir.pwd, "templates", "ANALYZE")
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.execute_templates_root
|
27
|
-
File.join(Dir.pwd, "templates", "EXECUTE")
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.common_templates_root
|
31
|
-
File.join(Dir.pwd, "templates", "COMMON")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
require "yaml"
|
5
|
-
|
6
|
-
module Aidp
|
7
|
-
module Shared
|
8
|
-
# Detects project type, language, framework, and other characteristics
|
9
|
-
class ProjectDetector
|
10
|
-
attr_reader :project_dir
|
11
|
-
|
12
|
-
def initialize(project_dir = Dir.pwd)
|
13
|
-
@project_dir = project_dir
|
14
|
-
end
|
15
|
-
|
16
|
-
def detect
|
17
|
-
{
|
18
|
-
language: detect_language,
|
19
|
-
framework: detect_framework,
|
20
|
-
build_system: detect_build_system,
|
21
|
-
package_manager: detect_package_manager,
|
22
|
-
static_analysis_tools: detect_static_analysis_tools,
|
23
|
-
test_framework: detect_test_framework,
|
24
|
-
database: detect_database,
|
25
|
-
deployment: detect_deployment
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def detect_language
|
32
|
-
return "ruby" if File.exist?(File.join(@project_dir, "Gemfile"))
|
33
|
-
return "javascript" if File.exist?(File.join(@project_dir, "package.json"))
|
34
|
-
return "python" if File.exist?(File.join(@project_dir, "requirements.txt")) || File.exist?(File.join(@project_dir, "pyproject.toml"))
|
35
|
-
return "java" if File.exist?(File.join(@project_dir, "pom.xml")) || File.exist?(File.join(@project_dir, "build.gradle"))
|
36
|
-
return "go" if File.exist?(File.join(@project_dir, "go.mod"))
|
37
|
-
return "rust" if File.exist?(File.join(@project_dir, "Cargo.toml"))
|
38
|
-
return "csharp" if File.exist?(File.join(@project_dir, "*.csproj"))
|
39
|
-
"unknown"
|
40
|
-
end
|
41
|
-
|
42
|
-
def detect_framework
|
43
|
-
case detect_language
|
44
|
-
when "ruby"
|
45
|
-
return "rails" if File.exist?(File.join(@project_dir, "config", "application.rb"))
|
46
|
-
return "sinatra" if File.exist?(File.join(@project_dir, "app.rb")) && File.read(File.join(@project_dir, "app.rb")).include?("Sinatra")
|
47
|
-
when "javascript"
|
48
|
-
return "react" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("react")
|
49
|
-
return "vue" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("vue")
|
50
|
-
return "angular" if File.exist?(File.join(@project_dir, "angular.json"))
|
51
|
-
return "express" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("express")
|
52
|
-
when "python"
|
53
|
-
return "django" if File.exist?(File.join(@project_dir, "manage.py"))
|
54
|
-
return "flask" if File.exist?(File.join(@project_dir, "app.py")) && File.read(File.join(@project_dir, "app.py")).include?("Flask")
|
55
|
-
when "java"
|
56
|
-
return "spring" if File.exist?(File.join(@project_dir, "pom.xml")) && File.read(File.join(@project_dir, "pom.xml")).include?("spring-boot")
|
57
|
-
end
|
58
|
-
"unknown"
|
59
|
-
end
|
60
|
-
|
61
|
-
def detect_build_system
|
62
|
-
return "maven" if File.exist?(File.join(@project_dir, "pom.xml"))
|
63
|
-
return "gradle" if File.exist?(File.join(@project_dir, "build.gradle"))
|
64
|
-
return "npm" if File.exist?(File.join(@project_dir, "package.json"))
|
65
|
-
return "bundler" if File.exist?(File.join(@project_dir, "Gemfile"))
|
66
|
-
return "pip" if File.exist?(File.join(@project_dir, "requirements.txt"))
|
67
|
-
return "cargo" if File.exist?(File.join(@project_dir, "Cargo.toml"))
|
68
|
-
return "go" if File.exist?(File.join(@project_dir, "go.mod"))
|
69
|
-
"unknown"
|
70
|
-
end
|
71
|
-
|
72
|
-
def detect_package_manager
|
73
|
-
detect_build_system
|
74
|
-
end
|
75
|
-
|
76
|
-
def detect_static_analysis_tools
|
77
|
-
tools = []
|
78
|
-
tools << "rubocop" if File.exist?(File.join(@project_dir, ".rubocop.yml"))
|
79
|
-
tools << "eslint" if File.exist?(File.join(@project_dir, ".eslintrc"))
|
80
|
-
tools << "flake8" if File.exist?(File.join(@project_dir, ".flake8"))
|
81
|
-
tools << "checkstyle" if File.exist?(File.join(@project_dir, "checkstyle.xml"))
|
82
|
-
tools << "clippy" if File.exist?(File.join(@project_dir, "Cargo.toml"))
|
83
|
-
tools
|
84
|
-
end
|
85
|
-
|
86
|
-
def detect_test_framework
|
87
|
-
case detect_language
|
88
|
-
when "ruby"
|
89
|
-
return "rspec" if File.exist?(File.join(@project_dir, "spec"))
|
90
|
-
return "minitest" if File.exist?(File.join(@project_dir, "test"))
|
91
|
-
when "javascript"
|
92
|
-
return "jest" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("jest")
|
93
|
-
return "mocha" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("mocha")
|
94
|
-
when "python"
|
95
|
-
return "pytest" if File.exist?(File.join(@project_dir, "pytest.ini"))
|
96
|
-
return "unittest" if Dir.exist?(File.join(@project_dir, "tests"))
|
97
|
-
when "java"
|
98
|
-
return "junit" if File.exist?(File.join(@project_dir, "src", "test"))
|
99
|
-
end
|
100
|
-
"unknown"
|
101
|
-
end
|
102
|
-
|
103
|
-
def detect_database
|
104
|
-
return "postgresql" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("postgresql")
|
105
|
-
return "mysql" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("mysql")
|
106
|
-
return "sqlite" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("sqlite")
|
107
|
-
"unknown"
|
108
|
-
end
|
109
|
-
|
110
|
-
def detect_deployment
|
111
|
-
return "docker" if File.exist?(File.join(@project_dir, "Dockerfile"))
|
112
|
-
return "kubernetes" if File.exist?(File.join(@project_dir, "k8s")) || File.exist?(File.join(@project_dir, "kubernetes"))
|
113
|
-
return "heroku" if File.exist?(File.join(@project_dir, "Procfile"))
|
114
|
-
return "aws" if File.exist?(File.join(@project_dir, "serverless.yml")) || File.exist?(File.join(@project_dir, "template.yaml"))
|
115
|
-
"unknown"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
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 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
|