aidp 0.10.0 → 0.12.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/mcp_dashboard.rb +205 -0
- data/lib/aidp/cli.rb +517 -43
- 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_info.rb +366 -0
- 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 +44 -5
- 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/guided_agent.rb +400 -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 +41 -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
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../harness/provider_manager"
|
|
4
|
+
require_relative "../harness/provider_factory"
|
|
5
|
+
require_relative "../harness/configuration"
|
|
6
|
+
require_relative "definitions"
|
|
7
|
+
require_relative "../message_display"
|
|
8
|
+
|
|
9
|
+
module Aidp
|
|
10
|
+
module Workflows
|
|
11
|
+
# Guided workflow agent that uses AI to help users select appropriate workflows
|
|
12
|
+
# Acts as a copilot to match user intent to AIDP capabilities
|
|
13
|
+
class GuidedAgent
|
|
14
|
+
include Aidp::MessageDisplay
|
|
15
|
+
|
|
16
|
+
class ConversationError < StandardError; end
|
|
17
|
+
|
|
18
|
+
def initialize(project_dir, prompt: nil)
|
|
19
|
+
@project_dir = project_dir
|
|
20
|
+
@prompt = prompt || TTY::Prompt.new
|
|
21
|
+
@configuration = Aidp::Harness::Configuration.new(project_dir)
|
|
22
|
+
@provider_manager = Aidp::Harness::ProviderManager.new(@configuration, prompt: @prompt)
|
|
23
|
+
@conversation_history = []
|
|
24
|
+
@user_input = {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Main entry point for guided workflow selection
|
|
28
|
+
def select_workflow
|
|
29
|
+
display_message("\n🤖 Welcome to AIDP Guided Workflow!", type: :highlight)
|
|
30
|
+
display_message("I'll help you choose the right workflow for your needs.\n", type: :info)
|
|
31
|
+
|
|
32
|
+
# Step 1: Get user's high-level goal
|
|
33
|
+
user_goal = get_user_goal
|
|
34
|
+
|
|
35
|
+
# Step 2: Use AI to analyze intent and recommend workflow
|
|
36
|
+
recommendation = analyze_user_intent(user_goal)
|
|
37
|
+
|
|
38
|
+
# Step 3: Present recommendation and get confirmation
|
|
39
|
+
workflow_selection = present_recommendation(recommendation)
|
|
40
|
+
|
|
41
|
+
# Step 4: Collect any additional required information
|
|
42
|
+
collect_workflow_details(workflow_selection)
|
|
43
|
+
|
|
44
|
+
workflow_selection
|
|
45
|
+
rescue => e
|
|
46
|
+
raise ConversationError, "Failed to guide workflow selection: #{e.message}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def get_user_goal
|
|
52
|
+
display_message("What would you like to do?", type: :highlight)
|
|
53
|
+
display_message("Examples:", type: :muted)
|
|
54
|
+
display_message(" • Build a new feature for user authentication", type: :muted)
|
|
55
|
+
display_message(" • Understand how this codebase handles payments", type: :muted)
|
|
56
|
+
display_message(" • Improve test coverage in my API layer", type: :muted)
|
|
57
|
+
display_message(" • Create a quick prototype for data export\n", type: :muted)
|
|
58
|
+
|
|
59
|
+
goal = @prompt.ask("Your goal:", required: true)
|
|
60
|
+
@user_input[:original_goal] = goal
|
|
61
|
+
goal
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def analyze_user_intent(user_goal)
|
|
65
|
+
display_message("\n🔍 Analyzing your request...", type: :info)
|
|
66
|
+
|
|
67
|
+
# Build the system prompt with AIDP capabilities
|
|
68
|
+
system_prompt = build_system_prompt
|
|
69
|
+
|
|
70
|
+
# Build the user prompt
|
|
71
|
+
user_prompt = build_analysis_prompt(user_goal)
|
|
72
|
+
|
|
73
|
+
# Call provider to analyze intent
|
|
74
|
+
response = call_provider_for_analysis(system_prompt, user_prompt)
|
|
75
|
+
|
|
76
|
+
# Parse the response
|
|
77
|
+
parse_recommendation(response)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def build_system_prompt
|
|
81
|
+
# Try to load from project dir first, fall back to gem's docs
|
|
82
|
+
capabilities_path = File.join(@project_dir, "docs", "AIDP_CAPABILITIES.md")
|
|
83
|
+
unless File.exist?(capabilities_path)
|
|
84
|
+
# Use the gem's copy
|
|
85
|
+
gem_root = File.expand_path("../../..", __dir__)
|
|
86
|
+
capabilities_path = File.join(gem_root, "docs", "AIDP_CAPABILITIES.md")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
capabilities_doc = File.read(capabilities_path)
|
|
90
|
+
|
|
91
|
+
<<~PROMPT
|
|
92
|
+
You are an expert AI assistant helping users select the right AIDP workflow for their needs.
|
|
93
|
+
|
|
94
|
+
Your role:
|
|
95
|
+
1. Understand what the user wants to accomplish
|
|
96
|
+
2. Match their intent to AIDP's capabilities
|
|
97
|
+
3. Recommend the most appropriate workflow
|
|
98
|
+
4. Explain why this workflow fits their needs
|
|
99
|
+
5. Identify if custom steps or templates are needed
|
|
100
|
+
|
|
101
|
+
AIDP Capabilities Reference:
|
|
102
|
+
#{capabilities_doc}
|
|
103
|
+
|
|
104
|
+
Response Format:
|
|
105
|
+
Provide a JSON response with:
|
|
106
|
+
{
|
|
107
|
+
"mode": "analyze|execute|hybrid",
|
|
108
|
+
"workflow_key": "specific_workflow_key",
|
|
109
|
+
"reasoning": "brief explanation of why this fits",
|
|
110
|
+
"additional_steps": ["any", "custom", "steps", "if", "needed"],
|
|
111
|
+
"questions": ["any", "clarifying", "questions"],
|
|
112
|
+
"confidence": "high|medium|low"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
Be concise to preserve the user's context window.
|
|
116
|
+
PROMPT
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def build_analysis_prompt(user_goal)
|
|
120
|
+
<<~PROMPT
|
|
121
|
+
User Goal: #{user_goal}
|
|
122
|
+
|
|
123
|
+
Analyze this goal and recommend the most appropriate AIDP workflow.
|
|
124
|
+
Consider:
|
|
125
|
+
- Is this analysis or development?
|
|
126
|
+
- What level of rigor is needed?
|
|
127
|
+
- Are there any gaps in existing workflows?
|
|
128
|
+
|
|
129
|
+
Provide your recommendation in JSON format.
|
|
130
|
+
PROMPT
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def call_provider_for_analysis(system_prompt, user_prompt)
|
|
134
|
+
# Get current provider from provider manager
|
|
135
|
+
provider_name = @provider_manager.current_provider
|
|
136
|
+
|
|
137
|
+
unless provider_name
|
|
138
|
+
raise ConversationError, "No provider configured for guided workflow"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Create provider instance using ProviderFactory
|
|
142
|
+
provider_factory = Aidp::Harness::ProviderFactory.new(@configuration)
|
|
143
|
+
provider = provider_factory.create_provider(provider_name, prompt: @prompt)
|
|
144
|
+
|
|
145
|
+
unless provider
|
|
146
|
+
raise ConversationError, "Failed to create provider instance for #{provider_name}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Make the request - combine system and user prompts
|
|
150
|
+
combined_prompt = "#{system_prompt}\n\n#{user_prompt}"
|
|
151
|
+
|
|
152
|
+
result = provider.send(prompt: combined_prompt)
|
|
153
|
+
|
|
154
|
+
unless result[:status] == :success
|
|
155
|
+
raise ConversationError, "Provider request failed: #{result[:error]}"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
result[:content]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def parse_recommendation(response_text)
|
|
162
|
+
# Extract JSON from response (might be wrapped in markdown code blocks)
|
|
163
|
+
json_match = response_text.match(/```json\s*(\{.*?\})\s*```/m) ||
|
|
164
|
+
response_text.match(/(\{.*\})/m)
|
|
165
|
+
|
|
166
|
+
unless json_match
|
|
167
|
+
raise ConversationError, "Could not parse recommendation from response"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
JSON.parse(json_match[1], symbolize_names: true)
|
|
171
|
+
rescue JSON::ParserError => e
|
|
172
|
+
raise ConversationError, "Invalid JSON in recommendation: #{e.message}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def present_recommendation(recommendation)
|
|
176
|
+
display_message("\n✨ Recommendation", type: :highlight)
|
|
177
|
+
display_message("─" * 60, type: :muted)
|
|
178
|
+
|
|
179
|
+
mode = recommendation[:mode].to_sym
|
|
180
|
+
workflow_key = recommendation[:workflow_key].to_sym
|
|
181
|
+
|
|
182
|
+
# Get workflow details
|
|
183
|
+
workflow = Definitions.get_workflow(mode, workflow_key)
|
|
184
|
+
|
|
185
|
+
unless workflow
|
|
186
|
+
# Handle custom workflow or error
|
|
187
|
+
return handle_custom_workflow(recommendation)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Display the recommendation
|
|
191
|
+
display_message("Mode: #{mode.to_s.capitalize}", type: :info)
|
|
192
|
+
display_message("Workflow: #{workflow[:name]}", type: :info)
|
|
193
|
+
display_message("\n#{workflow[:description]}", type: :muted)
|
|
194
|
+
display_message("\nReasoning: #{recommendation[:reasoning]}\n", type: :info)
|
|
195
|
+
|
|
196
|
+
# Show what's included
|
|
197
|
+
display_message("This workflow includes:", type: :highlight)
|
|
198
|
+
workflow[:details].each do |detail|
|
|
199
|
+
display_message(" • #{detail}", type: :info)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Handle additional steps if needed
|
|
203
|
+
steps = workflow[:steps]
|
|
204
|
+
if recommendation[:additional_steps]&.any?
|
|
205
|
+
display_message("\nAdditional custom steps recommended:", type: :highlight)
|
|
206
|
+
recommendation[:additional_steps].each do |step|
|
|
207
|
+
display_message(" • #{step}", type: :info)
|
|
208
|
+
end
|
|
209
|
+
steps = workflow[:steps] + recommendation[:additional_steps]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Ask for confirmation
|
|
213
|
+
display_message("")
|
|
214
|
+
confirmed = @prompt.yes?("Does this workflow fit your needs?")
|
|
215
|
+
|
|
216
|
+
if confirmed
|
|
217
|
+
{
|
|
218
|
+
mode: mode,
|
|
219
|
+
workflow_key: workflow_key,
|
|
220
|
+
workflow_type: workflow_key,
|
|
221
|
+
steps: steps,
|
|
222
|
+
user_input: @user_input,
|
|
223
|
+
workflow: workflow
|
|
224
|
+
}
|
|
225
|
+
else
|
|
226
|
+
# Offer alternatives
|
|
227
|
+
offer_alternatives(mode)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def handle_custom_workflow(recommendation)
|
|
232
|
+
display_message("\n💡 Custom Workflow Needed", type: :highlight)
|
|
233
|
+
display_message("The AI recommends creating a custom workflow:\n", type: :info)
|
|
234
|
+
display_message(recommendation[:reasoning], type: :muted)
|
|
235
|
+
|
|
236
|
+
if recommendation[:questions]&.any?
|
|
237
|
+
display_message("\nLet me gather some more information:\n", type: :highlight)
|
|
238
|
+
recommendation[:questions].each do |question|
|
|
239
|
+
answer = @prompt.ask(question)
|
|
240
|
+
@user_input[question.downcase.gsub(/\s+/, "_").to_sym] = answer
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Let user select from available steps
|
|
245
|
+
mode = recommendation[:mode].to_sym
|
|
246
|
+
display_message("\nLet's build a custom workflow by selecting specific steps:", type: :info)
|
|
247
|
+
|
|
248
|
+
steps = select_custom_steps(mode, recommendation[:additional_steps])
|
|
249
|
+
|
|
250
|
+
{
|
|
251
|
+
mode: mode,
|
|
252
|
+
workflow_key: :custom,
|
|
253
|
+
workflow_type: :custom,
|
|
254
|
+
steps: steps,
|
|
255
|
+
user_input: @user_input,
|
|
256
|
+
workflow: {
|
|
257
|
+
name: "Custom Workflow",
|
|
258
|
+
description: recommendation[:reasoning],
|
|
259
|
+
details: steps
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def select_custom_steps(mode, suggested_steps = [])
|
|
265
|
+
# Get available steps for the mode
|
|
266
|
+
spec = case mode
|
|
267
|
+
when :analyze
|
|
268
|
+
Aidp::Analyze::Steps::SPEC
|
|
269
|
+
when :execute
|
|
270
|
+
Aidp::Execute::Steps::SPEC
|
|
271
|
+
when :hybrid
|
|
272
|
+
# Combine both
|
|
273
|
+
Aidp::Analyze::Steps::SPEC.merge(Aidp::Execute::Steps::SPEC)
|
|
274
|
+
else
|
|
275
|
+
{}
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
step_choices = spec.map do |step_key, step_spec|
|
|
279
|
+
{
|
|
280
|
+
name: "#{step_key} - #{step_spec["description"]}",
|
|
281
|
+
value: step_key
|
|
282
|
+
}
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# Pre-select suggested steps
|
|
286
|
+
default_indices = suggested_steps.map do |step|
|
|
287
|
+
step_choices.index { |choice| choice[:value].to_s == step.to_s }
|
|
288
|
+
end.compact
|
|
289
|
+
|
|
290
|
+
selected_steps = @prompt.multi_select(
|
|
291
|
+
"Select steps for your custom workflow:",
|
|
292
|
+
step_choices,
|
|
293
|
+
default: default_indices,
|
|
294
|
+
per_page: 20
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
selected_steps.empty? ? suggested_steps : selected_steps
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def offer_alternatives(current_mode)
|
|
301
|
+
display_message("\n🔄 Let's find a better fit", type: :highlight)
|
|
302
|
+
|
|
303
|
+
choices = [
|
|
304
|
+
{name: "Try a different #{current_mode} workflow", value: :different_workflow},
|
|
305
|
+
{name: "Switch to a different mode", value: :different_mode},
|
|
306
|
+
{name: "Build a custom workflow", value: :custom},
|
|
307
|
+
{name: "Start over", value: :restart}
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
choice = @prompt.select("What would you like to do?", choices)
|
|
311
|
+
|
|
312
|
+
case choice
|
|
313
|
+
when :different_workflow
|
|
314
|
+
select_manual_workflow(current_mode)
|
|
315
|
+
when :different_mode
|
|
316
|
+
# Let user pick mode manually then workflow
|
|
317
|
+
new_mode = @prompt.select(
|
|
318
|
+
"Select mode:",
|
|
319
|
+
{
|
|
320
|
+
"🔬 Analyze Mode" => :analyze,
|
|
321
|
+
"🏗️ Execute Mode" => :execute,
|
|
322
|
+
"🔀 Hybrid Mode" => :hybrid
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
select_manual_workflow(new_mode)
|
|
326
|
+
when :custom
|
|
327
|
+
select_custom_steps(current_mode)
|
|
328
|
+
when :restart
|
|
329
|
+
select_workflow # Recursive call to start over
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def select_manual_workflow(mode)
|
|
334
|
+
workflows = Definitions.workflows_for_mode(mode)
|
|
335
|
+
|
|
336
|
+
choices = workflows.map do |key, workflow|
|
|
337
|
+
{
|
|
338
|
+
name: "#{workflow[:icon]} #{workflow[:name]} - #{workflow[:description]}",
|
|
339
|
+
value: key
|
|
340
|
+
}
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
selected_key = @prompt.select("Choose a workflow:", choices, per_page: 15)
|
|
344
|
+
workflow = workflows[selected_key]
|
|
345
|
+
|
|
346
|
+
{
|
|
347
|
+
mode: mode,
|
|
348
|
+
workflow_key: selected_key,
|
|
349
|
+
workflow_type: selected_key,
|
|
350
|
+
steps: workflow[:steps],
|
|
351
|
+
user_input: @user_input,
|
|
352
|
+
workflow: workflow
|
|
353
|
+
}
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def collect_workflow_details(workflow_selection)
|
|
357
|
+
# Collect additional information based on mode
|
|
358
|
+
case workflow_selection[:mode]
|
|
359
|
+
when :execute
|
|
360
|
+
collect_execute_details
|
|
361
|
+
when :analyze
|
|
362
|
+
# Analyze mode typically doesn't need much user input
|
|
363
|
+
@user_input[:analysis_goal] = @user_input[:original_goal]
|
|
364
|
+
when :hybrid
|
|
365
|
+
collect_execute_details # Hybrid often needs project details
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Update the workflow selection with collected input
|
|
369
|
+
workflow_selection[:user_input] = @user_input
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def collect_execute_details
|
|
373
|
+
return if @user_input[:project_description] # Already collected
|
|
374
|
+
|
|
375
|
+
display_message("\n📝 Project Information", type: :highlight)
|
|
376
|
+
display_message("Let me gather some details for the PRD:\n", type: :info)
|
|
377
|
+
|
|
378
|
+
@user_input[:project_description] = @prompt.ask(
|
|
379
|
+
"Describe what you're building (can reference your original goal):",
|
|
380
|
+
default: @user_input[:original_goal]
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
@user_input[:tech_stack] = @prompt.ask(
|
|
384
|
+
"Tech stack (e.g., Ruby/Rails, Node.js, Python)? [optional]",
|
|
385
|
+
required: false
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
@user_input[:target_users] = @prompt.ask(
|
|
389
|
+
"Who will use this? [optional]",
|
|
390
|
+
required: false
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
@user_input[:success_criteria] = @prompt.ask(
|
|
394
|
+
"How will you measure success? [optional]",
|
|
395
|
+
required: false
|
|
396
|
+
)
|
|
397
|
+
end
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tty-prompt"
|
|
4
|
+
require_relative "definitions"
|
|
5
|
+
require_relative "../message_display"
|
|
6
|
+
|
|
7
|
+
module Aidp
|
|
8
|
+
module Workflows
|
|
9
|
+
# Enhanced workflow selector with support for custom workflows
|
|
10
|
+
# Handles selection for analyze, execute, and hybrid modes
|
|
11
|
+
class Selector
|
|
12
|
+
include Aidp::MessageDisplay
|
|
13
|
+
|
|
14
|
+
def initialize(prompt: TTY::Prompt.new)
|
|
15
|
+
@prompt = prompt
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Select mode (analyze, execute, or hybrid)
|
|
19
|
+
def select_mode
|
|
20
|
+
display_message("\n🚀 Welcome to AI Dev Pipeline!", type: :highlight)
|
|
21
|
+
display_message("Choose your mode:\n", type: :highlight)
|
|
22
|
+
|
|
23
|
+
choices = {
|
|
24
|
+
"🔬 Analyze Mode" => :analyze,
|
|
25
|
+
"🏗️ Execute Mode" => :execute,
|
|
26
|
+
"🔀 Hybrid Mode" => :hybrid
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@prompt.select("What would you like to do?", choices, per_page: 10)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Select workflow for the given mode
|
|
33
|
+
def select_workflow(mode)
|
|
34
|
+
workflows = Definitions.workflows_for_mode(mode)
|
|
35
|
+
|
|
36
|
+
display_message("\n#{mode_header(mode)}", type: :highlight)
|
|
37
|
+
display_message("Choose a workflow:\n")
|
|
38
|
+
|
|
39
|
+
# Build choices with icons and descriptions
|
|
40
|
+
choices = workflows.map do |key, workflow|
|
|
41
|
+
{
|
|
42
|
+
name: "#{workflow[:icon]} #{workflow[:name]} - #{workflow[:description]}",
|
|
43
|
+
value: key
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
selected = @prompt.select(
|
|
48
|
+
"Select workflow:",
|
|
49
|
+
choices,
|
|
50
|
+
per_page: 15,
|
|
51
|
+
help: "(↑/↓ to navigate, Enter to select)"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
workflow = workflows[selected]
|
|
55
|
+
|
|
56
|
+
# Show workflow details
|
|
57
|
+
display_workflow_details(workflow)
|
|
58
|
+
|
|
59
|
+
# Handle custom workflows
|
|
60
|
+
if workflow[:steps] == :custom
|
|
61
|
+
steps = select_custom_steps(mode)
|
|
62
|
+
{workflow_key: selected, steps: steps, workflow: workflow}
|
|
63
|
+
else
|
|
64
|
+
{workflow_key: selected, steps: workflow[:steps], workflow: workflow}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Select custom steps for hybrid or custom workflows
|
|
69
|
+
def select_custom_steps(mode)
|
|
70
|
+
display_message("\n⚙️ Custom Step Selection", type: :highlight)
|
|
71
|
+
display_message("")
|
|
72
|
+
|
|
73
|
+
if mode == :hybrid
|
|
74
|
+
select_hybrid_steps
|
|
75
|
+
elsif mode == :analyze
|
|
76
|
+
select_steps_from_mode(:analyze)
|
|
77
|
+
elsif mode == :execute
|
|
78
|
+
select_steps_from_mode(:execute)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def mode_header(mode)
|
|
85
|
+
case mode
|
|
86
|
+
when :analyze
|
|
87
|
+
"🔬 Analyze Mode - Understand Your Codebase"
|
|
88
|
+
when :execute
|
|
89
|
+
"🏗️ Execute Mode - Build New Features"
|
|
90
|
+
when :hybrid
|
|
91
|
+
"🔀 Hybrid Mode - Analyze Then Execute"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def display_workflow_details(workflow)
|
|
96
|
+
display_message("\n#{workflow[:icon]} #{workflow[:name]}", type: :highlight)
|
|
97
|
+
display_message("─" * 60, type: :muted)
|
|
98
|
+
display_message("")
|
|
99
|
+
display_message("Description: #{workflow[:description]}")
|
|
100
|
+
display_message("")
|
|
101
|
+
display_message("Includes:", type: :highlight)
|
|
102
|
+
workflow[:details].each do |detail|
|
|
103
|
+
display_message(" • #{detail}", type: :info)
|
|
104
|
+
end
|
|
105
|
+
display_message("")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def select_steps_from_mode(mode)
|
|
109
|
+
spec = (mode == :analyze) ? Aidp::Analyze::Steps::SPEC : Aidp::Execute::Steps::SPEC
|
|
110
|
+
|
|
111
|
+
display_message("Available #{mode} steps:")
|
|
112
|
+
display_message("")
|
|
113
|
+
|
|
114
|
+
# Build step choices
|
|
115
|
+
step_choices = spec.map do |step_key, step_spec|
|
|
116
|
+
{
|
|
117
|
+
name: "#{step_key} - #{step_spec["description"]}",
|
|
118
|
+
value: step_key,
|
|
119
|
+
disabled: step_spec["gate"] ? "(requires manual review)" : false
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
selected_steps = @prompt.multi_select(
|
|
124
|
+
"Select steps (Space to select, Enter when done):",
|
|
125
|
+
step_choices,
|
|
126
|
+
per_page: 20,
|
|
127
|
+
help: "Select one or more steps"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if selected_steps.empty?
|
|
131
|
+
display_message("⚠️ No steps selected, using default workflow", type: :warning)
|
|
132
|
+
# Return a sensible default
|
|
133
|
+
(mode == :analyze) ? ["01_REPOSITORY_ANALYSIS"] : ["00_PRD", "16_IMPLEMENTATION"]
|
|
134
|
+
else
|
|
135
|
+
selected_steps.sort
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def select_hybrid_steps
|
|
140
|
+
display_message("You can mix analyze and execute steps for a custom hybrid workflow.")
|
|
141
|
+
display_message("")
|
|
142
|
+
|
|
143
|
+
all_steps = Definitions.all_available_steps
|
|
144
|
+
|
|
145
|
+
# Group steps by mode for display
|
|
146
|
+
step_choices = all_steps.map do |step_info|
|
|
147
|
+
mode_tag = (step_info[:mode] == :analyze) ? "[ANALYZE]" : "[EXECUTE]"
|
|
148
|
+
{
|
|
149
|
+
name: "#{mode_tag} #{step_info[:step]} - #{step_info[:description]}",
|
|
150
|
+
value: step_info[:step]
|
|
151
|
+
}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
selected_steps = @prompt.multi_select(
|
|
155
|
+
"Select steps (Space to select, Enter when done):",
|
|
156
|
+
step_choices,
|
|
157
|
+
per_page: 25,
|
|
158
|
+
help: "Mix analyze and execute steps as needed"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if selected_steps.empty?
|
|
162
|
+
display_message("⚠️ No steps selected, using default hybrid workflow", type: :warning)
|
|
163
|
+
# Return a sensible default hybrid
|
|
164
|
+
["01_REPOSITORY_ANALYSIS", "00_PRD", "16_IMPLEMENTATION"]
|
|
165
|
+
else
|
|
166
|
+
selected_steps.sort
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
data/lib/aidp.rb
CHANGED
|
@@ -7,7 +7,13 @@ require_relative "aidp/core_ext/class_attribute"
|
|
|
7
7
|
require_relative "aidp/version"
|
|
8
8
|
require_relative "aidp/config"
|
|
9
9
|
require_relative "aidp/util"
|
|
10
|
+
require_relative "aidp/message_display"
|
|
10
11
|
require_relative "aidp/cli"
|
|
12
|
+
|
|
13
|
+
# Jobs and background execution
|
|
14
|
+
require_relative "aidp/jobs/background_runner"
|
|
15
|
+
|
|
16
|
+
# CLI commands
|
|
11
17
|
require_relative "aidp/cli/jobs_command"
|
|
12
18
|
|
|
13
19
|
# Providers
|
|
@@ -38,10 +44,16 @@ require_relative "aidp/analyze/seams"
|
|
|
38
44
|
require_relative "aidp/analyze/tree_sitter_scan"
|
|
39
45
|
require_relative "aidp/analyze/kb_inspector"
|
|
40
46
|
|
|
47
|
+
# Workflows
|
|
48
|
+
require_relative "aidp/workflows/definitions"
|
|
49
|
+
require_relative "aidp/workflows/selector"
|
|
50
|
+
|
|
41
51
|
# Execute mode
|
|
42
52
|
require_relative "aidp/execute/steps"
|
|
43
53
|
require_relative "aidp/execute/runner"
|
|
44
54
|
require_relative "aidp/execute/progress"
|
|
55
|
+
require_relative "aidp/execute/checkpoint"
|
|
56
|
+
require_relative "aidp/execute/checkpoint_display"
|
|
45
57
|
|
|
46
58
|
# Harness mode
|
|
47
59
|
require_relative "aidp/harness/configuration"
|