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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +210 -0
- data/bin/aidp +5 -0
- data/lib/aidp/analyze/agent_personas.rb +71 -0
- data/lib/aidp/analyze/agent_tool_executor.rb +445 -0
- data/lib/aidp/analyze/data_retention_manager.rb +426 -0
- data/lib/aidp/analyze/database.rb +243 -0
- data/lib/aidp/analyze/dependencies.rb +335 -0
- data/lib/aidp/analyze/error_handler.rb +486 -0
- data/lib/aidp/analyze/export_manager.rb +425 -0
- data/lib/aidp/analyze/feature_analyzer.rb +397 -0
- data/lib/aidp/analyze/focus_guidance.rb +517 -0
- data/lib/aidp/analyze/incremental_analyzer.rb +543 -0
- data/lib/aidp/analyze/language_analysis_strategies.rb +897 -0
- data/lib/aidp/analyze/large_analysis_progress.rb +504 -0
- data/lib/aidp/analyze/memory_manager.rb +365 -0
- data/lib/aidp/analyze/parallel_processor.rb +460 -0
- data/lib/aidp/analyze/performance_optimizer.rb +694 -0
- data/lib/aidp/analyze/prioritizer.rb +402 -0
- data/lib/aidp/analyze/progress.rb +75 -0
- data/lib/aidp/analyze/progress_visualizer.rb +320 -0
- data/lib/aidp/analyze/report_generator.rb +582 -0
- data/lib/aidp/analyze/repository_chunker.rb +702 -0
- data/lib/aidp/analyze/ruby_maat_integration.rb +572 -0
- data/lib/aidp/analyze/runner.rb +245 -0
- data/lib/aidp/analyze/static_analysis_detector.rb +577 -0
- data/lib/aidp/analyze/steps.rb +53 -0
- data/lib/aidp/analyze/storage.rb +600 -0
- data/lib/aidp/analyze/tool_configuration.rb +456 -0
- data/lib/aidp/analyze/tool_modernization.rb +750 -0
- data/lib/aidp/execute/progress.rb +76 -0
- data/lib/aidp/execute/runner.rb +135 -0
- data/lib/aidp/execute/steps.rb +113 -0
- data/lib/aidp/shared/cli.rb +117 -0
- data/lib/aidp/shared/config.rb +35 -0
- data/lib/aidp/shared/project_detector.rb +119 -0
- data/lib/aidp/shared/providers/anthropic.rb +26 -0
- data/lib/aidp/shared/providers/base.rb +17 -0
- data/lib/aidp/shared/providers/cursor.rb +102 -0
- data/lib/aidp/shared/providers/gemini.rb +26 -0
- data/lib/aidp/shared/providers/macos_ui.rb +26 -0
- data/lib/aidp/shared/sync.rb +15 -0
- data/lib/aidp/shared/util.rb +41 -0
- data/lib/aidp/shared/version.rb +7 -0
- data/lib/aidp/shared/workspace.rb +21 -0
- data/lib/aidp.rb +53 -0
- data/templates/ANALYZE/01_REPOSITORY_ANALYSIS.md +100 -0
- data/templates/ANALYZE/02_ARCHITECTURE_ANALYSIS.md +151 -0
- data/templates/ANALYZE/03_TEST_ANALYSIS.md +182 -0
- data/templates/ANALYZE/04_FUNCTIONALITY_ANALYSIS.md +200 -0
- data/templates/ANALYZE/05_DOCUMENTATION_ANALYSIS.md +202 -0
- data/templates/ANALYZE/06_STATIC_ANALYSIS.md +233 -0
- data/templates/ANALYZE/07_REFACTORING_RECOMMENDATIONS.md +316 -0
- data/templates/COMMON/AGENT_BASE.md +129 -0
- data/templates/COMMON/CONVENTIONS.md +19 -0
- data/templates/COMMON/TEMPLATES/ADR_TEMPLATE.md +21 -0
- data/templates/COMMON/TEMPLATES/DOMAIN_CHARTER.md +27 -0
- data/templates/COMMON/TEMPLATES/EVENT_EXAMPLE.yaml +16 -0
- data/templates/COMMON/TEMPLATES/MERMAID_C4.md +46 -0
- data/templates/COMMON/TEMPLATES/OPENAPI_STUB.yaml +11 -0
- data/templates/EXECUTE/00_PRD.md +36 -0
- data/templates/EXECUTE/01_NFRS.md +27 -0
- data/templates/EXECUTE/02A_ARCH_GATE_QUESTIONS.md +13 -0
- data/templates/EXECUTE/02_ARCHITECTURE.md +42 -0
- data/templates/EXECUTE/03_ADR_FACTORY.md +22 -0
- data/templates/EXECUTE/04_DOMAIN_DECOMPOSITION.md +24 -0
- data/templates/EXECUTE/05_CONTRACTS.md +27 -0
- data/templates/EXECUTE/06_THREAT_MODEL.md +23 -0
- data/templates/EXECUTE/07_TEST_PLAN.md +24 -0
- data/templates/EXECUTE/08_TASKS.md +29 -0
- data/templates/EXECUTE/09_SCAFFOLDING_DEVEX.md +25 -0
- data/templates/EXECUTE/10_IMPLEMENTATION_AGENT.md +30 -0
- data/templates/EXECUTE/11_STATIC_ANALYSIS.md +22 -0
- data/templates/EXECUTE/12_OBSERVABILITY_SLOS.md +21 -0
- data/templates/EXECUTE/13_DELIVERY_ROLLOUT.md +21 -0
- data/templates/EXECUTE/14_DOCS_PORTAL.md +23 -0
- data/templates/EXECUTE/15_POST_RELEASE.md +25 -0
- metadata +301 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module Aidp
|
7
|
+
module Execute
|
8
|
+
# Manages progress tracking for execute mode, isolated from analyze mode
|
9
|
+
class Progress
|
10
|
+
attr_reader :project_dir, :progress_file
|
11
|
+
|
12
|
+
def initialize(project_dir)
|
13
|
+
@project_dir = project_dir
|
14
|
+
@progress_file = File.join(project_dir, ".aidp-progress.yml")
|
15
|
+
load_progress
|
16
|
+
end
|
17
|
+
|
18
|
+
def completed_steps
|
19
|
+
@progress["completed_steps"] || []
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_step
|
23
|
+
@progress["current_step"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def started_at
|
27
|
+
@progress["started_at"] ? Time.parse(@progress["started_at"]) : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def step_completed?(step_name)
|
31
|
+
completed_steps.include?(step_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
def mark_step_completed(step_name)
|
35
|
+
@progress["completed_steps"] ||= []
|
36
|
+
@progress["completed_steps"] << step_name unless step_completed?(step_name)
|
37
|
+
@progress["current_step"] = nil
|
38
|
+
@progress["started_at"] ||= Time.now.iso8601
|
39
|
+
save_progress
|
40
|
+
end
|
41
|
+
|
42
|
+
def mark_step_in_progress(step_name)
|
43
|
+
@progress["current_step"] = step_name
|
44
|
+
@progress["started_at"] ||= Time.now.iso8601
|
45
|
+
save_progress
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset
|
49
|
+
@progress = {
|
50
|
+
"completed_steps" => [],
|
51
|
+
"current_step" => nil,
|
52
|
+
"started_at" => nil
|
53
|
+
}
|
54
|
+
save_progress
|
55
|
+
end
|
56
|
+
|
57
|
+
def next_step
|
58
|
+
Aidp::Execute::Steps::SPEC.keys.find { |step| !step_completed?(step) }
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def load_progress
|
64
|
+
@progress = if File.exist?(@progress_file)
|
65
|
+
YAML.load_file(@progress_file) || {}
|
66
|
+
else
|
67
|
+
{}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_progress
|
72
|
+
File.write(@progress_file, @progress.to_yaml)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require "yaml"
|
5
|
+
require "json"
|
6
|
+
|
7
|
+
module Aidp
|
8
|
+
module Execute
|
9
|
+
# Handles execution logic for execute mode steps
|
10
|
+
class Runner
|
11
|
+
attr_reader :project_dir, :progress
|
12
|
+
|
13
|
+
def initialize(project_dir)
|
14
|
+
@project_dir = project_dir
|
15
|
+
@progress = Aidp::Execute::Progress.new(project_dir)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_step(step_name, options = {})
|
19
|
+
raise "Step '#{step_name}' not found in execute mode steps" unless Aidp::Execute::Steps::SPEC.key?(step_name)
|
20
|
+
|
21
|
+
step_spec = Aidp::Execute::Steps::SPEC[step_name]
|
22
|
+
template_name = step_spec["templates"].first
|
23
|
+
|
24
|
+
# Load template
|
25
|
+
template = find_template(template_name)
|
26
|
+
raise "Template '#{template_name}' not found" unless template
|
27
|
+
|
28
|
+
# Compose prompt
|
29
|
+
prompt = composed_prompt(template_name, options)
|
30
|
+
|
31
|
+
# Handle error simulation for tests
|
32
|
+
if options[:simulate_error]
|
33
|
+
return {
|
34
|
+
status: "error",
|
35
|
+
error: options[:simulate_error],
|
36
|
+
step: step_name
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Execute step (mock for now)
|
41
|
+
result = {
|
42
|
+
status: "success",
|
43
|
+
step: step_name,
|
44
|
+
output_files: step_spec["outs"],
|
45
|
+
prompt: prompt
|
46
|
+
}
|
47
|
+
|
48
|
+
# Mark step as completed
|
49
|
+
@progress.mark_step_completed(step_name)
|
50
|
+
|
51
|
+
# Generate output files
|
52
|
+
generate_output_files(step_name, step_spec["outs"], result)
|
53
|
+
|
54
|
+
# Generate database export
|
55
|
+
generate_database_export
|
56
|
+
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def find_template(template_name)
|
63
|
+
template_search_paths.each do |path|
|
64
|
+
template_file = File.join(path, template_name)
|
65
|
+
return File.read(template_file) if File.exist?(template_file)
|
66
|
+
end
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def template_search_paths
|
71
|
+
[
|
72
|
+
File.join(@project_dir, "templates"),
|
73
|
+
File.join(@project_dir, "templates", "COMMON"),
|
74
|
+
File.join(File.dirname(__FILE__), "..", "..", "..", "templates", "EXECUTE"),
|
75
|
+
File.join(File.dirname(__FILE__), "..", "..", "..", "templates", "COMMON")
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
79
|
+
def composed_prompt(template_name, options = {})
|
80
|
+
template = find_template(template_name)
|
81
|
+
return template unless template
|
82
|
+
|
83
|
+
# Load agent base template if available
|
84
|
+
agent_base = find_template("AGENT_BASE.md")
|
85
|
+
template = "#{agent_base}\n\n#{template}" if agent_base
|
86
|
+
|
87
|
+
# Replace placeholders
|
88
|
+
options.each do |key, value|
|
89
|
+
template = template.gsub("{{#{key}}}", value.to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
template
|
93
|
+
end
|
94
|
+
|
95
|
+
def generate_output_files(step_name, output_files, result)
|
96
|
+
output_files.each do |output_file|
|
97
|
+
file_path = File.join(@project_dir, output_file)
|
98
|
+
content = generate_output_content(step_name, output_file, result)
|
99
|
+
File.write(file_path, content)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate_output_content(step_name, output_file, result)
|
104
|
+
case output_file
|
105
|
+
when /\.md$/
|
106
|
+
"# #{step_name} Output\n\nGenerated on #{Time.now}\n\n## Result\n\n#{result[:status]}"
|
107
|
+
when /\.json$/
|
108
|
+
result.to_json
|
109
|
+
else
|
110
|
+
"Output for #{step_name}: #{result[:status]}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def generate_database_export
|
115
|
+
database_file = File.join(@project_dir, ".aidp.db")
|
116
|
+
require "sqlite3"
|
117
|
+
|
118
|
+
begin
|
119
|
+
db = SQLite3::Database.new(database_file)
|
120
|
+
db.execute("CREATE TABLE IF NOT EXISTS execute_results (step TEXT, status TEXT, completed_at TEXT)")
|
121
|
+
|
122
|
+
Aidp::Execute::Steps::SPEC.keys.each do |step|
|
123
|
+
if @progress.step_completed?(step)
|
124
|
+
db.execute("INSERT INTO execute_results (step, status, completed_at) VALUES (?, ?, ?)",
|
125
|
+
[step, "success", Time.now.iso8601])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
rescue => e
|
129
|
+
# Log the error but don't fail the execution
|
130
|
+
puts "Warning: Database export failed: #{e.message}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aidp
|
4
|
+
module Execute
|
5
|
+
# Defines the steps, templates, outputs, and associated AI agents for execute mode
|
6
|
+
class Steps
|
7
|
+
SPEC = {
|
8
|
+
"00_PRD" => {
|
9
|
+
"templates" => ["00_PRD.md"],
|
10
|
+
"outs" => ["00_PRD.md"],
|
11
|
+
"gate" => false,
|
12
|
+
"agent" => "Product Manager"
|
13
|
+
},
|
14
|
+
"01_NFRS" => {
|
15
|
+
"templates" => ["01_NFRS.md"],
|
16
|
+
"outs" => ["01_NFRS.md"],
|
17
|
+
"gate" => false,
|
18
|
+
"agent" => "Architect"
|
19
|
+
},
|
20
|
+
"02_ARCHITECTURE" => {
|
21
|
+
"templates" => ["02_ARCHITECTURE.md"],
|
22
|
+
"outs" => ["02_ARCHITECTURE.md"],
|
23
|
+
"gate" => false,
|
24
|
+
"agent" => "Architect"
|
25
|
+
},
|
26
|
+
"02A_ARCH_GATE_QUESTIONS" => {
|
27
|
+
"templates" => ["02A_ARCH_GATE_QUESTIONS.md"],
|
28
|
+
"outs" => ["02A_ARCH_GATE_QUESTIONS.md"],
|
29
|
+
"gate" => true,
|
30
|
+
"agent" => "Architect"
|
31
|
+
},
|
32
|
+
"03_ADR_FACTORY" => {
|
33
|
+
"templates" => ["03_ADR_FACTORY.md"],
|
34
|
+
"outs" => ["03_ADR_FACTORY.md"],
|
35
|
+
"gate" => false,
|
36
|
+
"agent" => "Architect"
|
37
|
+
},
|
38
|
+
"04_DOMAIN_DECOMPOSITION" => {
|
39
|
+
"templates" => ["04_DOMAIN_DECOMPOSITION.md"],
|
40
|
+
"outs" => ["04_DOMAIN_DECOMPOSITION.md"],
|
41
|
+
"gate" => false,
|
42
|
+
"agent" => "Architect"
|
43
|
+
},
|
44
|
+
"05_CONTRACTS" => {
|
45
|
+
"templates" => ["05_CONTRACTS.md"],
|
46
|
+
"outs" => ["05_CONTRACTS.md"],
|
47
|
+
"gate" => false,
|
48
|
+
"agent" => "Architect"
|
49
|
+
},
|
50
|
+
"06_THREAT_MODEL" => {
|
51
|
+
"templates" => ["06_THREAT_MODEL.md"],
|
52
|
+
"outs" => ["06_THREAT_MODEL.md"],
|
53
|
+
"gate" => false,
|
54
|
+
"agent" => "Security Expert"
|
55
|
+
},
|
56
|
+
"07_TEST_PLAN" => {
|
57
|
+
"templates" => ["07_TEST_PLAN.md"],
|
58
|
+
"outs" => ["07_TEST_PLAN.md"],
|
59
|
+
"gate" => false,
|
60
|
+
"agent" => "Test Engineer"
|
61
|
+
},
|
62
|
+
"08_TASKS" => {
|
63
|
+
"templates" => ["08_TASKS.md"],
|
64
|
+
"outs" => ["08_TASKS.md"],
|
65
|
+
"gate" => false,
|
66
|
+
"agent" => "Project Manager"
|
67
|
+
},
|
68
|
+
"09_SCAFFOLDING_DEVEX" => {
|
69
|
+
"templates" => ["09_SCAFFOLDING_DEVEX.md"],
|
70
|
+
"outs" => ["09_SCAFFOLDING_DEVEX.md"],
|
71
|
+
"gate" => false,
|
72
|
+
"agent" => "DevOps Engineer"
|
73
|
+
},
|
74
|
+
"10_IMPLEMENTATION_AGENT" => {
|
75
|
+
"templates" => ["10_IMPLEMENTATION_AGENT.md"],
|
76
|
+
"outs" => ["10_IMPLEMENTATION_AGENT.md"],
|
77
|
+
"gate" => false,
|
78
|
+
"agent" => "Implementation Specialist"
|
79
|
+
},
|
80
|
+
"11_STATIC_ANALYSIS" => {
|
81
|
+
"templates" => ["11_STATIC_ANALYSIS.md"],
|
82
|
+
"outs" => ["11_STATIC_ANALYSIS.md"],
|
83
|
+
"gate" => false,
|
84
|
+
"agent" => "Code Quality Expert"
|
85
|
+
},
|
86
|
+
"12_OBSERVABILITY_SLOS" => {
|
87
|
+
"templates" => ["12_OBSERVABILITY_SLOS.md"],
|
88
|
+
"outs" => ["12_OBSERVABILITY_SLOS.md"],
|
89
|
+
"gate" => false,
|
90
|
+
"agent" => "SRE Engineer"
|
91
|
+
},
|
92
|
+
"13_DELIVERY_ROLLOUT" => {
|
93
|
+
"templates" => ["13_DELIVERY_ROLLOUT.md"],
|
94
|
+
"outs" => ["13_DELIVERY_ROLLOUT.md"],
|
95
|
+
"gate" => false,
|
96
|
+
"agent" => "DevOps Engineer"
|
97
|
+
},
|
98
|
+
"14_DOCS_PORTAL" => {
|
99
|
+
"templates" => ["14_DOCS_PORTAL.md"],
|
100
|
+
"outs" => ["14_DOCS_PORTAL.md"],
|
101
|
+
"gate" => false,
|
102
|
+
"agent" => "Technical Writer"
|
103
|
+
},
|
104
|
+
"15_POST_RELEASE" => {
|
105
|
+
"templates" => ["15_POST_RELEASE.md"],
|
106
|
+
"outs" => ["15_POST_RELEASE.md"],
|
107
|
+
"gate" => false,
|
108
|
+
"agent" => "Project Manager"
|
109
|
+
}
|
110
|
+
}.freeze
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,117 @@
|
|
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
|
@@ -0,0 +1,35 @@
|
|
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
|
@@ -0,0 +1,119 @@
|
|
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
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,17 @@
|
|
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
|