aidp 0.10.0 → 0.11.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/README.md +194 -25
- data/lib/aidp/analyze/kb_inspector.rb +2 -15
- data/lib/aidp/analyze/progress.rb +2 -1
- data/lib/aidp/analyze/ruby_maat_integration.rb +2 -15
- data/lib/aidp/analyze/runner.rb +64 -20
- data/lib/aidp/analyze/steps.rb +10 -8
- data/lib/aidp/analyze/tree_sitter_grammar_loader.rb +2 -13
- data/lib/aidp/analyze/tree_sitter_scan.rb +2 -13
- data/lib/aidp/cli/checkpoint_command.rb +98 -0
- data/lib/aidp/cli/first_run_wizard.rb +65 -94
- data/lib/aidp/cli/jobs_command.rb +249 -34
- data/lib/aidp/cli.rb +312 -38
- data/lib/aidp/config.rb +5 -8
- data/lib/aidp/debug_logger.rb +4 -4
- data/lib/aidp/debug_mixin.rb +11 -4
- data/lib/aidp/execute/checkpoint.rb +282 -0
- data/lib/aidp/execute/checkpoint_display.rb +221 -0
- data/lib/aidp/execute/progress.rb +2 -1
- data/lib/aidp/execute/prompt_manager.rb +62 -0
- data/lib/aidp/execute/runner.rb +53 -24
- data/lib/aidp/execute/steps.rb +36 -27
- data/lib/aidp/execute/work_loop_runner.rb +308 -0
- data/lib/aidp/execute/workflow_selector.rb +26 -17
- data/lib/aidp/harness/condition_detector.rb +4 -4
- data/lib/aidp/harness/config_schema.rb +40 -0
- data/lib/aidp/harness/config_validator.rb +3 -6
- data/lib/aidp/harness/configuration.rb +35 -1
- data/lib/aidp/harness/enhanced_runner.rb +22 -1
- data/lib/aidp/harness/error_handler.rb +103 -28
- data/lib/aidp/harness/provider_factory.rb +4 -1
- data/lib/aidp/harness/provider_manager.rb +250 -15
- data/lib/aidp/harness/runner.rb +3 -14
- data/lib/aidp/harness/simple_user_interface.rb +2 -15
- data/lib/aidp/harness/status_display.rb +12 -17
- data/lib/aidp/harness/test_runner.rb +83 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +2 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +22 -4
- data/lib/aidp/harness/ui/error_handler.rb +4 -0
- data/lib/aidp/harness/ui/frame_manager.rb +10 -8
- data/lib/aidp/harness/ui/job_monitor.rb +2 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +4 -2
- data/lib/aidp/harness/ui/navigation/menu_item.rb +1 -0
- data/lib/aidp/harness/ui/navigation/menu_state.rb +1 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +1 -0
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +2 -0
- data/lib/aidp/harness/ui/progress_display.rb +8 -12
- data/lib/aidp/harness/ui/question_collector.rb +2 -0
- data/lib/aidp/harness/ui/spinner_group.rb +2 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +1 -1
- data/lib/aidp/harness/ui/status_manager.rb +4 -2
- data/lib/aidp/harness/ui/status_widget.rb +3 -1
- data/lib/aidp/harness/ui/workflow_controller.rb +2 -0
- data/lib/aidp/harness/user_interface.rb +12 -17
- data/lib/aidp/jobs/background_runner.rb +278 -0
- data/lib/aidp/message_display.rb +48 -0
- data/lib/aidp/provider_manager.rb +3 -1
- data/lib/aidp/providers/anthropic.rb +100 -17
- data/lib/aidp/providers/base.rb +42 -11
- data/lib/aidp/providers/codex.rb +248 -0
- data/lib/aidp/providers/cursor.rb +35 -42
- data/lib/aidp/providers/gemini.rb +25 -15
- data/lib/aidp/providers/github_copilot.rb +41 -42
- data/lib/aidp/providers/opencode.rb +34 -41
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/definitions.rb +357 -0
- data/lib/aidp/workflows/selector.rb +171 -0
- data/lib/aidp.rb +12 -0
- data/templates/planning/generate_llm_style_guide.md +119 -0
- metadata +38 -26
- /data/templates/{ANALYZE/02_ARCHITECTURE_ANALYSIS.md → analysis/analyze_architecture.md} +0 -0
- /data/templates/{ANALYZE/05_DOCUMENTATION_ANALYSIS.md → analysis/analyze_documentation.md} +0 -0
- /data/templates/{ANALYZE/04_FUNCTIONALITY_ANALYSIS.md → analysis/analyze_functionality.md} +0 -0
- /data/templates/{ANALYZE/01_REPOSITORY_ANALYSIS.md → analysis/analyze_repository.md} +0 -0
- /data/templates/{ANALYZE/06_STATIC_ANALYSIS.md → analysis/analyze_static_code.md} +0 -0
- /data/templates/{ANALYZE/03_TEST_ANALYSIS.md → analysis/analyze_tests.md} +0 -0
- /data/templates/{ANALYZE/07_REFACTORING_RECOMMENDATIONS.md → analysis/recommend_refactoring.md} +0 -0
- /data/templates/{ANALYZE/06a_tree_sitter_scan.md → analysis/scan_with_tree_sitter.md} +0 -0
- /data/templates/{EXECUTE/11_STATIC_ANALYSIS.md → implementation/configure_static_analysis.md} +0 -0
- /data/templates/{EXECUTE/14_DOCS_PORTAL.md → implementation/create_documentation_portal.md} +0 -0
- /data/templates/{EXECUTE/10_IMPLEMENTATION_AGENT.md → implementation/implement_features.md} +0 -0
- /data/templates/{EXECUTE/13_DELIVERY_ROLLOUT.md → implementation/plan_delivery.md} +0 -0
- /data/templates/{EXECUTE/15_POST_RELEASE.md → implementation/review_post_release.md} +0 -0
- /data/templates/{EXECUTE/09_SCAFFOLDING_DEVEX.md → implementation/setup_scaffolding.md} +0 -0
- /data/templates/{EXECUTE/02A_ARCH_GATE_QUESTIONS.md → planning/ask_architecture_questions.md} +0 -0
- /data/templates/{EXECUTE/00_PRD.md → planning/create_prd.md} +0 -0
- /data/templates/{EXECUTE/08_TASKS.md → planning/create_tasks.md} +0 -0
- /data/templates/{EXECUTE/04_DOMAIN_DECOMPOSITION.md → planning/decompose_domain.md} +0 -0
- /data/templates/{EXECUTE/01_NFRS.md → planning/define_nfrs.md} +0 -0
- /data/templates/{EXECUTE/05_CONTRACTS.md → planning/design_apis.md} +0 -0
- /data/templates/{EXECUTE/02_ARCHITECTURE.md → planning/design_architecture.md} +0 -0
- /data/templates/{EXECUTE/06_THREAT_MODEL.md → planning/design_data_model.md} +0 -0
- /data/templates/{EXECUTE/03_ADR_FACTORY.md → planning/generate_adrs.md} +0 -0
- /data/templates/{EXECUTE/12_OBSERVABILITY_SLOS.md → planning/plan_observability.md} +0 -0
- /data/templates/{EXECUTE/07_TEST_PLAN.md → planning/plan_testing.md} +0 -0
data/lib/aidp/execute/steps.rb
CHANGED
@@ -4,117 +4,126 @@ module Aidp
|
|
4
4
|
module Execute
|
5
5
|
module Steps
|
6
6
|
# Simplified step specifications with fewer gates
|
7
|
+
# Templates are now organized by purpose (planning/, analysis/, implementation/)
|
8
|
+
# and named with action verbs for clarity
|
7
9
|
SPEC = {
|
10
|
+
"00_LLM_STYLE_GUIDE" => {
|
11
|
+
"templates" => ["planning/generate_llm_style_guide.md"],
|
12
|
+
"description" => "Generate project-specific LLM Style Guide",
|
13
|
+
"outs" => ["docs/LLM_STYLE_GUIDE.md"],
|
14
|
+
"gate" => false,
|
15
|
+
"interactive" => false
|
16
|
+
},
|
8
17
|
"00_PRD" => {
|
9
|
-
"templates" => ["
|
18
|
+
"templates" => ["planning/create_prd.md"],
|
10
19
|
"description" => "Generate Product Requirements Document",
|
11
20
|
"outs" => ["docs/prd.md"],
|
12
|
-
"gate" => false,
|
13
|
-
"interactive" => true
|
21
|
+
"gate" => false, # Now auto-generated from user input
|
22
|
+
"interactive" => true # Uses collected user input
|
14
23
|
},
|
15
24
|
"01_NFRS" => {
|
16
|
-
"templates" => ["
|
25
|
+
"templates" => ["planning/define_nfrs.md"],
|
17
26
|
"description" => "Define Non-Functional Requirements",
|
18
27
|
"outs" => ["docs/nfrs.md"],
|
19
|
-
"gate" => false
|
28
|
+
"gate" => false # Auto-generated
|
20
29
|
},
|
21
30
|
"02_ARCHITECTURE" => {
|
22
|
-
"templates" => ["
|
31
|
+
"templates" => ["planning/design_architecture.md"],
|
23
32
|
"description" => "Design System Architecture",
|
24
33
|
"outs" => ["docs/architecture.md"],
|
25
|
-
"gate" => false
|
34
|
+
"gate" => false # Auto-generated
|
26
35
|
},
|
27
36
|
"02A_ARCH_GATE_QUESTIONS" => {
|
28
|
-
"templates" => ["
|
37
|
+
"templates" => ["planning/ask_architecture_questions.md"],
|
29
38
|
"description" => "Architecture Gate Questions",
|
30
39
|
"outs" => ["docs/arch_gate_questions.md"],
|
31
40
|
"gate" => true
|
32
41
|
},
|
33
42
|
"03_ADR_FACTORY" => {
|
34
|
-
"templates" => ["
|
43
|
+
"templates" => ["planning/generate_adrs.md"],
|
35
44
|
"description" => "Generate Architecture Decision Records",
|
36
45
|
"outs" => ["docs/adr/*.md"],
|
37
46
|
"gate" => false
|
38
47
|
},
|
39
48
|
"04_DOMAIN_DECOMPOSITION" => {
|
40
|
-
"templates" => ["
|
49
|
+
"templates" => ["planning/decompose_domain.md"],
|
41
50
|
"description" => "Decompose Domain into Components",
|
42
51
|
"outs" => ["docs/domain_decomposition.md"],
|
43
|
-
"gate" => false
|
52
|
+
"gate" => false # Auto-generated
|
44
53
|
},
|
45
54
|
"05_API_DESIGN" => {
|
46
|
-
"templates" => ["
|
55
|
+
"templates" => ["planning/design_apis.md"],
|
47
56
|
"description" => "Design APIs and Interfaces",
|
48
57
|
"outs" => ["docs/api_design.md"],
|
49
|
-
"gate" => false
|
58
|
+
"gate" => false # Auto-generated
|
50
59
|
},
|
51
60
|
"06_DATA_MODEL" => {
|
52
|
-
"templates" => ["
|
61
|
+
"templates" => ["planning/design_data_model.md"],
|
53
62
|
"description" => "Design Data Model",
|
54
63
|
"outs" => ["docs/data_model.md"],
|
55
64
|
"gate" => true
|
56
65
|
},
|
57
66
|
"07_SECURITY_REVIEW" => {
|
58
|
-
"templates" => ["
|
67
|
+
"templates" => ["planning/plan_testing.md"],
|
59
68
|
"description" => "Security Review and Threat Model",
|
60
69
|
"outs" => ["docs/security_review.md"],
|
61
70
|
"gate" => true
|
62
71
|
},
|
63
72
|
"08_PERFORMANCE_REVIEW" => {
|
64
|
-
"templates" => ["
|
73
|
+
"templates" => ["planning/create_tasks.md"],
|
65
74
|
"description" => "Performance Review and Optimization",
|
66
75
|
"outs" => ["docs/performance_review.md"],
|
67
76
|
"gate" => true
|
68
77
|
},
|
69
78
|
"09_RELIABILITY_REVIEW" => {
|
70
|
-
"templates" => ["
|
79
|
+
"templates" => ["implementation/setup_scaffolding.md"],
|
71
80
|
"description" => "Reliability Review and SLOs",
|
72
81
|
"outs" => ["docs/reliability_review.md"],
|
73
82
|
"gate" => true
|
74
83
|
},
|
75
84
|
"10_TESTING_STRATEGY" => {
|
76
|
-
"templates" => ["
|
85
|
+
"templates" => ["implementation/implement_features.md"],
|
77
86
|
"description" => "Define Testing Strategy",
|
78
87
|
"outs" => ["docs/testing_strategy.md"],
|
79
|
-
"gate" => false
|
88
|
+
"gate" => false # Auto-generated
|
80
89
|
},
|
81
90
|
"11_STATIC_ANALYSIS" => {
|
82
|
-
"templates" => ["
|
91
|
+
"templates" => ["implementation/configure_static_analysis.md"],
|
83
92
|
"description" => "Static Code Analysis",
|
84
93
|
"outs" => ["docs/static_analysis.md"],
|
85
94
|
"gate" => false
|
86
95
|
},
|
87
96
|
"12_OBSERVABILITY_SLOS" => {
|
88
|
-
"templates" => ["
|
97
|
+
"templates" => ["planning/plan_observability.md"],
|
89
98
|
"description" => "Define Observability and SLOs",
|
90
99
|
"outs" => ["docs/observability_slos.md"],
|
91
100
|
"gate" => true
|
92
101
|
},
|
93
102
|
"13_DELIVERY_ROLLOUT" => {
|
94
|
-
"templates" => ["
|
103
|
+
"templates" => ["implementation/plan_delivery.md"],
|
95
104
|
"description" => "Plan Delivery and Rollout",
|
96
105
|
"outs" => ["docs/delivery_rollout.md"],
|
97
106
|
"gate" => true
|
98
107
|
},
|
99
108
|
"14_DOCS_PORTAL" => {
|
100
|
-
"templates" => ["
|
109
|
+
"templates" => ["implementation/create_documentation_portal.md"],
|
101
110
|
"description" => "Documentation Portal",
|
102
111
|
"outs" => ["docs/docs_portal.md"],
|
103
112
|
"gate" => false
|
104
113
|
},
|
105
114
|
"15_POST_RELEASE" => {
|
106
|
-
"templates" => ["
|
115
|
+
"templates" => ["implementation/review_post_release.md"],
|
107
116
|
"description" => "Post-Release Review",
|
108
117
|
"outs" => ["docs/post_release.md"],
|
109
|
-
"gate" => false
|
118
|
+
"gate" => false # Auto-generated
|
110
119
|
},
|
111
120
|
# New implementation step for actual development work
|
112
121
|
"16_IMPLEMENTATION" => {
|
113
|
-
"templates" => ["
|
122
|
+
"templates" => ["implementation/implement_features.md"], # Reuse existing implementation template
|
114
123
|
"description" => "Execute Implementation Tasks",
|
115
124
|
"outs" => ["implementation_log.md"],
|
116
125
|
"gate" => false,
|
117
|
-
"implementation" => true
|
126
|
+
"implementation" => true # Special step that runs development tasks
|
118
127
|
}
|
119
128
|
}.freeze
|
120
129
|
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "prompt_manager"
|
4
|
+
require_relative "checkpoint"
|
5
|
+
require_relative "checkpoint_display"
|
6
|
+
require_relative "../harness/test_runner"
|
7
|
+
|
8
|
+
module Aidp
|
9
|
+
module Execute
|
10
|
+
# Executes work loops for a single step
|
11
|
+
# Responsibilities:
|
12
|
+
# - Create initial PROMPT.md from templates and context
|
13
|
+
# - Loop: send PROMPT.md to agent, run tests/linters, check completion
|
14
|
+
# - Only send test/lint failures back to agent
|
15
|
+
# - Track iteration count
|
16
|
+
# - Record periodic checkpoints with metrics
|
17
|
+
class WorkLoopRunner
|
18
|
+
include Aidp::MessageDisplay
|
19
|
+
|
20
|
+
attr_reader :iteration_count, :project_dir
|
21
|
+
|
22
|
+
MAX_ITERATIONS = 50 # Safety limit
|
23
|
+
CHECKPOINT_INTERVAL = 5 # Record checkpoint every N iterations
|
24
|
+
|
25
|
+
def initialize(project_dir, provider_manager, config, options = {})
|
26
|
+
@project_dir = project_dir
|
27
|
+
@provider_manager = provider_manager
|
28
|
+
@config = config
|
29
|
+
@prompt_manager = PromptManager.new(project_dir)
|
30
|
+
@test_runner = Aidp::Harness::TestRunner.new(project_dir, config)
|
31
|
+
@checkpoint = Checkpoint.new(project_dir)
|
32
|
+
@checkpoint_display = CheckpointDisplay.new
|
33
|
+
@iteration_count = 0
|
34
|
+
@step_name = nil
|
35
|
+
@options = options
|
36
|
+
end
|
37
|
+
|
38
|
+
# Execute a step using work loop pattern
|
39
|
+
# Returns final result when step is complete
|
40
|
+
def execute_step(step_name, step_spec, context = {})
|
41
|
+
@step_name = step_name
|
42
|
+
@iteration_count = 0
|
43
|
+
|
44
|
+
display_message("🔄 Starting work loop for step: #{step_name}", type: :info)
|
45
|
+
|
46
|
+
# Create initial PROMPT.md
|
47
|
+
create_initial_prompt(step_spec, context)
|
48
|
+
|
49
|
+
# Main work loop
|
50
|
+
loop do
|
51
|
+
@iteration_count += 1
|
52
|
+
display_message(" Iteration #{@iteration_count}", type: :info)
|
53
|
+
|
54
|
+
break if @iteration_count > MAX_ITERATIONS
|
55
|
+
|
56
|
+
# Send PROMPT.md to agent
|
57
|
+
result = send_to_agent
|
58
|
+
|
59
|
+
# Run tests and linters
|
60
|
+
test_results = @test_runner.run_tests
|
61
|
+
lint_results = @test_runner.run_linters
|
62
|
+
|
63
|
+
# Record checkpoint at intervals
|
64
|
+
record_periodic_checkpoint(test_results, lint_results)
|
65
|
+
|
66
|
+
# Check if step is complete
|
67
|
+
if step_complete?(result, test_results, lint_results)
|
68
|
+
# Record final checkpoint
|
69
|
+
record_final_checkpoint(test_results, lint_results)
|
70
|
+
display_message("✅ Step #{step_name} completed after #{@iteration_count} iterations", type: :success)
|
71
|
+
archive_and_cleanup
|
72
|
+
return build_success_result(result)
|
73
|
+
end
|
74
|
+
|
75
|
+
# If not complete, prepare next iteration with failures (if any)
|
76
|
+
prepare_next_iteration(test_results, lint_results)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Safety: max iterations reached
|
80
|
+
display_message("⚠️ Max iterations (#{MAX_ITERATIONS}) reached for #{step_name}", type: :warning)
|
81
|
+
archive_and_cleanup
|
82
|
+
build_max_iterations_result
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# Create initial PROMPT.md with all context
|
88
|
+
def create_initial_prompt(step_spec, context)
|
89
|
+
template_content = load_template(step_spec["templates"]&.first)
|
90
|
+
prd_content = load_prd
|
91
|
+
style_guide = load_style_guide
|
92
|
+
user_input = format_user_input(context[:user_input])
|
93
|
+
|
94
|
+
initial_prompt = build_initial_prompt_content(
|
95
|
+
template: template_content,
|
96
|
+
prd: prd_content,
|
97
|
+
style_guide: style_guide,
|
98
|
+
user_input: user_input,
|
99
|
+
step_name: @step_name
|
100
|
+
)
|
101
|
+
|
102
|
+
@prompt_manager.write(initial_prompt)
|
103
|
+
display_message(" Created PROMPT.md (#{initial_prompt.length} chars)", type: :info)
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_initial_prompt_content(template:, prd:, style_guide:, user_input:, step_name:)
|
107
|
+
parts = []
|
108
|
+
|
109
|
+
parts << "# Work Loop: #{step_name}"
|
110
|
+
parts << ""
|
111
|
+
parts << "## Instructions"
|
112
|
+
parts << "You are working in a work loop. Your responsibilities:"
|
113
|
+
parts << "1. Read this PROMPT.md file to understand what needs to be done"
|
114
|
+
parts << "2. Complete the work described below"
|
115
|
+
parts << "3. **IMPORTANT**: Edit this PROMPT.md file yourself to:"
|
116
|
+
parts << " - Remove completed items"
|
117
|
+
parts << " - Update with current status"
|
118
|
+
parts << " - Keep it concise (remove unnecessary context)"
|
119
|
+
parts << " - Mark the step COMPLETE when 100% done"
|
120
|
+
parts << "4. After you finish, tests and linters will run automatically"
|
121
|
+
parts << "5. If tests/linters fail, you'll see the errors in the next iteration"
|
122
|
+
parts << ""
|
123
|
+
parts << "## Completion Criteria"
|
124
|
+
parts << "Mark this step COMPLETE by adding this line to PROMPT.md:"
|
125
|
+
parts << "```"
|
126
|
+
parts << "STATUS: COMPLETE"
|
127
|
+
parts << "```"
|
128
|
+
parts << ""
|
129
|
+
|
130
|
+
if user_input && !user_input.empty?
|
131
|
+
parts << "## User Input"
|
132
|
+
parts << user_input
|
133
|
+
parts << ""
|
134
|
+
end
|
135
|
+
|
136
|
+
if style_guide
|
137
|
+
parts << "## LLM Style Guide"
|
138
|
+
parts << style_guide
|
139
|
+
parts << ""
|
140
|
+
end
|
141
|
+
|
142
|
+
if prd
|
143
|
+
parts << "## Product Requirements (PRD)"
|
144
|
+
parts << prd
|
145
|
+
parts << ""
|
146
|
+
end
|
147
|
+
|
148
|
+
parts << "## Task Template"
|
149
|
+
parts << template
|
150
|
+
parts << ""
|
151
|
+
|
152
|
+
parts.join("\n")
|
153
|
+
end
|
154
|
+
|
155
|
+
def send_to_agent
|
156
|
+
prompt_content = @prompt_manager.read
|
157
|
+
return {status: "error", message: "PROMPT.md not found"} unless prompt_content
|
158
|
+
|
159
|
+
# Send to provider via provider_manager
|
160
|
+
@provider_manager.execute_with_provider(
|
161
|
+
@provider_manager.current_provider,
|
162
|
+
prompt_content,
|
163
|
+
{
|
164
|
+
step_name: @step_name,
|
165
|
+
iteration: @iteration_count,
|
166
|
+
project_dir: @project_dir
|
167
|
+
}
|
168
|
+
)
|
169
|
+
end
|
170
|
+
|
171
|
+
def step_complete?(agent_result, test_results, lint_results)
|
172
|
+
# Check if agent marked step complete
|
173
|
+
agent_complete = agent_result[:status] == "completed" || prompt_marked_complete?
|
174
|
+
|
175
|
+
# Check if tests and linters pass
|
176
|
+
tests_pass = test_results[:success]
|
177
|
+
linters_pass = lint_results[:success]
|
178
|
+
|
179
|
+
agent_complete && tests_pass && linters_pass
|
180
|
+
end
|
181
|
+
|
182
|
+
def prompt_marked_complete?
|
183
|
+
prompt_content = @prompt_manager.read
|
184
|
+
return false unless prompt_content
|
185
|
+
|
186
|
+
# Check for STATUS: COMPLETE marker
|
187
|
+
prompt_content.match?(/^STATUS:\s*COMPLETE/i)
|
188
|
+
end
|
189
|
+
|
190
|
+
def prepare_next_iteration(test_results, lint_results)
|
191
|
+
# Only append failures to PROMPT.md for agent to see
|
192
|
+
failures = []
|
193
|
+
|
194
|
+
unless test_results[:success]
|
195
|
+
failures << "## Test Failures"
|
196
|
+
failures << test_results[:output]
|
197
|
+
failures << ""
|
198
|
+
end
|
199
|
+
|
200
|
+
unless lint_results[:success]
|
201
|
+
failures << "## Linter Failures"
|
202
|
+
failures << lint_results[:output]
|
203
|
+
failures << ""
|
204
|
+
end
|
205
|
+
|
206
|
+
return if failures.empty?
|
207
|
+
|
208
|
+
# Append failures to PROMPT.md
|
209
|
+
current_prompt = @prompt_manager.read
|
210
|
+
updated_prompt = current_prompt + "\n\n---\n\n" + failures.join("\n")
|
211
|
+
@prompt_manager.write(updated_prompt)
|
212
|
+
|
213
|
+
display_message(" Added failure reports to PROMPT.md", type: :warning)
|
214
|
+
end
|
215
|
+
|
216
|
+
def archive_and_cleanup
|
217
|
+
@prompt_manager.archive(@step_name)
|
218
|
+
@prompt_manager.delete
|
219
|
+
end
|
220
|
+
|
221
|
+
def load_template(template_name)
|
222
|
+
return "" unless template_name
|
223
|
+
|
224
|
+
# Template name now includes subdirectory (e.g., "planning/create_prd.md")
|
225
|
+
template_path = File.join(@project_dir, "templates", template_name)
|
226
|
+
return File.read(template_path) if File.exist?(template_path)
|
227
|
+
|
228
|
+
# Fallback: try COMMON directory
|
229
|
+
common_path = File.join(@project_dir, "templates", "COMMON", template_name)
|
230
|
+
return File.read(common_path) if File.exist?(common_path)
|
231
|
+
|
232
|
+
""
|
233
|
+
end
|
234
|
+
|
235
|
+
def load_prd
|
236
|
+
prd_path = File.join(@project_dir, "docs", "prd.md")
|
237
|
+
File.exist?(prd_path) ? File.read(prd_path) : nil
|
238
|
+
end
|
239
|
+
|
240
|
+
def load_style_guide
|
241
|
+
style_guide_path = File.join(@project_dir, "docs", "LLM_STYLE_GUIDE.md")
|
242
|
+
File.exist?(style_guide_path) ? File.read(style_guide_path) : nil
|
243
|
+
end
|
244
|
+
|
245
|
+
def format_user_input(user_input)
|
246
|
+
return nil if user_input.nil? || user_input.empty?
|
247
|
+
|
248
|
+
lines = user_input.map { |key, value| "- **#{key}**: #{value}" }
|
249
|
+
lines.join("\n")
|
250
|
+
end
|
251
|
+
|
252
|
+
def build_success_result(agent_result)
|
253
|
+
{
|
254
|
+
status: "completed",
|
255
|
+
message: "Step #{@step_name} completed successfully",
|
256
|
+
iterations: @iteration_count,
|
257
|
+
final_result: agent_result
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
def build_max_iterations_result
|
262
|
+
{
|
263
|
+
status: "error",
|
264
|
+
message: "Maximum iterations reached",
|
265
|
+
iterations: @iteration_count,
|
266
|
+
error: "Step did not complete within #{MAX_ITERATIONS} iterations"
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
# Record checkpoint at regular intervals
|
271
|
+
def record_periodic_checkpoint(test_results, lint_results)
|
272
|
+
# Record every CHECKPOINT_INTERVAL iterations or on iteration 1
|
273
|
+
return unless @iteration_count == 1 || (@iteration_count % CHECKPOINT_INTERVAL == 0)
|
274
|
+
|
275
|
+
metrics = {
|
276
|
+
tests_passing: test_results[:success],
|
277
|
+
linters_passing: lint_results[:success]
|
278
|
+
}
|
279
|
+
|
280
|
+
checkpoint_data = @checkpoint.record_checkpoint(@step_name, @iteration_count, metrics)
|
281
|
+
|
282
|
+
# Display inline progress
|
283
|
+
@checkpoint_display.display_inline_progress(@iteration_count, checkpoint_data[:metrics])
|
284
|
+
|
285
|
+
# Show detailed checkpoint every 10 iterations
|
286
|
+
if @iteration_count % 10 == 0
|
287
|
+
@checkpoint_display.display_checkpoint(checkpoint_data)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Record final checkpoint when step completes
|
292
|
+
def record_final_checkpoint(test_results, lint_results)
|
293
|
+
metrics = {
|
294
|
+
tests_passing: test_results[:success],
|
295
|
+
linters_passing: lint_results[:success],
|
296
|
+
completed: true
|
297
|
+
}
|
298
|
+
|
299
|
+
checkpoint_data = @checkpoint.record_checkpoint(@step_name, @iteration_count, metrics)
|
300
|
+
@checkpoint_display.display_checkpoint(checkpoint_data, show_details: true)
|
301
|
+
|
302
|
+
# Display progress summary
|
303
|
+
summary = @checkpoint.progress_summary
|
304
|
+
@checkpoint_display.display_progress_summary(summary) if summary
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -1,42 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "tty-prompt"
|
4
|
+
require_relative "../workflows/definitions"
|
5
|
+
require_relative "../workflows/selector"
|
4
6
|
|
5
7
|
module Aidp
|
6
8
|
module Execute
|
7
9
|
# Handles interactive workflow selection and project setup
|
8
10
|
class WorkflowSelector
|
11
|
+
include Aidp::MessageDisplay
|
12
|
+
|
9
13
|
def initialize(prompt: TTY::Prompt.new)
|
10
14
|
@user_input = {}
|
11
15
|
@prompt = prompt
|
16
|
+
@workflow_selector = Aidp::Workflows::Selector.new(prompt: @prompt)
|
12
17
|
end
|
13
18
|
|
14
19
|
# Main entry point for interactive workflow selection
|
15
|
-
def select_workflow(harness_mode: false)
|
20
|
+
def select_workflow(harness_mode: false, use_new_selector: true, mode: nil)
|
16
21
|
if harness_mode
|
17
22
|
# In harness mode, use default values to avoid blocking
|
18
23
|
select_workflow_with_defaults
|
24
|
+
elsif use_new_selector
|
25
|
+
# Use new unified workflow selector (default as of Issue #79)
|
26
|
+
select_workflow_with_new_selector(mode)
|
19
27
|
else
|
20
|
-
#
|
28
|
+
# Legacy interactive mode for backward compatibility
|
21
29
|
select_workflow_interactive
|
22
30
|
end
|
23
31
|
end
|
24
32
|
|
25
33
|
private
|
26
34
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
when :error then :red
|
31
|
-
when :success then :green
|
32
|
-
when :warning then :yellow
|
33
|
-
when :info then :blue
|
34
|
-
when :highlight then :cyan
|
35
|
-
when :muted then :bright_black
|
36
|
-
else :white
|
37
|
-
end
|
35
|
+
def select_workflow_with_new_selector(mode = nil)
|
36
|
+
# Step 1: Collect project information (still useful for all workflows)
|
37
|
+
collect_project_info
|
38
38
|
|
39
|
-
|
39
|
+
# Step 2: Use new workflow selector, defaulting to execute mode if not specified
|
40
|
+
workflow_mode = mode || :execute
|
41
|
+
result = @workflow_selector.select_workflow(workflow_mode)
|
42
|
+
|
43
|
+
{
|
44
|
+
workflow_type: result[:workflow_key],
|
45
|
+
steps: result[:steps],
|
46
|
+
user_input: @user_input,
|
47
|
+
workflow: result[:workflow]
|
48
|
+
}
|
40
49
|
end
|
41
50
|
|
42
51
|
def select_workflow_interactive
|
@@ -144,10 +153,10 @@ module Aidp
|
|
144
153
|
|
145
154
|
def exploration_workflow_steps
|
146
155
|
[
|
147
|
-
"00_PRD",
|
156
|
+
"00_PRD", # Generate PRD from user input (no manual gate)
|
148
157
|
"10_TESTING_STRATEGY", # Ensure we have tests
|
149
|
-
"11_STATIC_ANALYSIS",
|
150
|
-
"16_IMPLEMENTATION"
|
158
|
+
"11_STATIC_ANALYSIS", # Code quality
|
159
|
+
"16_IMPLEMENTATION" # Special step for actual development work
|
151
160
|
]
|
152
161
|
end
|
153
162
|
|
@@ -1310,13 +1310,13 @@ module Aidp
|
|
1310
1310
|
# Get timeout duration for operation type
|
1311
1311
|
def get_timeout_duration(operation_type, configuration = nil)
|
1312
1312
|
default_timeouts = {
|
1313
|
-
analyze: 300,
|
1314
|
-
execute: 600,
|
1313
|
+
analyze: 300, # 5 minutes
|
1314
|
+
execute: 600, # 10 minutes
|
1315
1315
|
provider_call: 120, # 2 minutes
|
1316
1316
|
file_operation: 30, # 30 seconds
|
1317
1317
|
network_request: 60, # 1 minute
|
1318
|
-
user_input: 300,
|
1319
|
-
default: 120
|
1318
|
+
user_input: 300, # 5 minutes
|
1319
|
+
default: 120 # 2 minutes
|
1320
1320
|
}
|
1321
1321
|
|
1322
1322
|
# Get timeout from configuration if available
|
@@ -366,6 +366,46 @@ module Aidp
|
|
366
366
|
enum: ["provider_model", "provider", "model", "none"]
|
367
367
|
}
|
368
368
|
}
|
369
|
+
},
|
370
|
+
work_loop: {
|
371
|
+
type: :hash,
|
372
|
+
required: false,
|
373
|
+
default: {
|
374
|
+
enabled: true,
|
375
|
+
max_iterations: 50,
|
376
|
+
test_commands: [],
|
377
|
+
lint_commands: []
|
378
|
+
},
|
379
|
+
properties: {
|
380
|
+
enabled: {
|
381
|
+
type: :boolean,
|
382
|
+
required: false,
|
383
|
+
default: true
|
384
|
+
},
|
385
|
+
max_iterations: {
|
386
|
+
type: :integer,
|
387
|
+
required: false,
|
388
|
+
default: 50,
|
389
|
+
min: 1,
|
390
|
+
max: 200
|
391
|
+
},
|
392
|
+
test_commands: {
|
393
|
+
type: :array,
|
394
|
+
required: false,
|
395
|
+
default: [],
|
396
|
+
items: {
|
397
|
+
type: :string
|
398
|
+
}
|
399
|
+
},
|
400
|
+
lint_commands: {
|
401
|
+
type: :array,
|
402
|
+
required: false,
|
403
|
+
default: [],
|
404
|
+
items: {
|
405
|
+
type: :string
|
406
|
+
}
|
407
|
+
}
|
408
|
+
}
|
369
409
|
}
|
370
410
|
}
|
371
411
|
},
|
@@ -76,8 +76,9 @@ module Aidp
|
|
76
76
|
return false if config_exists?
|
77
77
|
|
78
78
|
example_config = ConfigSchema.generate_example
|
79
|
-
config_path = File.join(@project_dir, "aidp.yml")
|
79
|
+
config_path = File.join(@project_dir, ".aidp", "aidp.yml")
|
80
80
|
|
81
|
+
FileUtils.mkdir_p(File.dirname(config_path))
|
81
82
|
File.write(config_path, YAML.dump(example_config))
|
82
83
|
true
|
83
84
|
end
|
@@ -243,14 +244,10 @@ module Aidp
|
|
243
244
|
private
|
244
245
|
|
245
246
|
def find_config_file
|
246
|
-
|
247
|
-
config_file = File.join(@project_dir, "aidp.yml")
|
248
|
-
legacy_config_file = File.join(@project_dir, ".aidp.yml")
|
247
|
+
config_file = File.join(@project_dir, ".aidp", "aidp.yml")
|
249
248
|
|
250
249
|
if File.exist?(config_file)
|
251
250
|
config_file
|
252
|
-
elsif File.exist?(legacy_config_file)
|
253
|
-
legacy_config_file
|
254
251
|
end
|
255
252
|
end
|
256
253
|
|