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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +194 -25
  3. data/lib/aidp/analyze/kb_inspector.rb +2 -15
  4. data/lib/aidp/analyze/progress.rb +2 -1
  5. data/lib/aidp/analyze/ruby_maat_integration.rb +2 -15
  6. data/lib/aidp/analyze/runner.rb +64 -20
  7. data/lib/aidp/analyze/steps.rb +10 -8
  8. data/lib/aidp/analyze/tree_sitter_grammar_loader.rb +2 -13
  9. data/lib/aidp/analyze/tree_sitter_scan.rb +2 -13
  10. data/lib/aidp/cli/checkpoint_command.rb +98 -0
  11. data/lib/aidp/cli/first_run_wizard.rb +65 -94
  12. data/lib/aidp/cli/jobs_command.rb +249 -34
  13. data/lib/aidp/cli/mcp_dashboard.rb +205 -0
  14. data/lib/aidp/cli.rb +517 -43
  15. data/lib/aidp/config.rb +5 -8
  16. data/lib/aidp/debug_logger.rb +4 -4
  17. data/lib/aidp/debug_mixin.rb +11 -4
  18. data/lib/aidp/execute/checkpoint.rb +282 -0
  19. data/lib/aidp/execute/checkpoint_display.rb +221 -0
  20. data/lib/aidp/execute/progress.rb +2 -1
  21. data/lib/aidp/execute/prompt_manager.rb +62 -0
  22. data/lib/aidp/execute/runner.rb +53 -24
  23. data/lib/aidp/execute/steps.rb +36 -27
  24. data/lib/aidp/execute/work_loop_runner.rb +308 -0
  25. data/lib/aidp/execute/workflow_selector.rb +26 -17
  26. data/lib/aidp/harness/condition_detector.rb +4 -4
  27. data/lib/aidp/harness/config_schema.rb +40 -0
  28. data/lib/aidp/harness/config_validator.rb +3 -6
  29. data/lib/aidp/harness/configuration.rb +35 -1
  30. data/lib/aidp/harness/enhanced_runner.rb +22 -1
  31. data/lib/aidp/harness/error_handler.rb +103 -28
  32. data/lib/aidp/harness/provider_factory.rb +4 -1
  33. data/lib/aidp/harness/provider_info.rb +366 -0
  34. data/lib/aidp/harness/provider_manager.rb +250 -15
  35. data/lib/aidp/harness/runner.rb +3 -14
  36. data/lib/aidp/harness/simple_user_interface.rb +2 -15
  37. data/lib/aidp/harness/status_display.rb +12 -17
  38. data/lib/aidp/harness/test_runner.rb +83 -0
  39. data/lib/aidp/harness/ui/enhanced_tui.rb +2 -0
  40. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +44 -5
  41. data/lib/aidp/harness/ui/error_handler.rb +4 -0
  42. data/lib/aidp/harness/ui/frame_manager.rb +10 -8
  43. data/lib/aidp/harness/ui/job_monitor.rb +2 -0
  44. data/lib/aidp/harness/ui/navigation/main_menu.rb +4 -2
  45. data/lib/aidp/harness/ui/navigation/menu_item.rb +1 -0
  46. data/lib/aidp/harness/ui/navigation/menu_state.rb +1 -0
  47. data/lib/aidp/harness/ui/navigation/submenu.rb +1 -0
  48. data/lib/aidp/harness/ui/navigation/workflow_selector.rb +2 -0
  49. data/lib/aidp/harness/ui/progress_display.rb +8 -12
  50. data/lib/aidp/harness/ui/question_collector.rb +2 -0
  51. data/lib/aidp/harness/ui/spinner_group.rb +2 -0
  52. data/lib/aidp/harness/ui/spinner_helper.rb +1 -1
  53. data/lib/aidp/harness/ui/status_manager.rb +4 -2
  54. data/lib/aidp/harness/ui/status_widget.rb +3 -1
  55. data/lib/aidp/harness/ui/workflow_controller.rb +2 -0
  56. data/lib/aidp/harness/user_interface.rb +12 -17
  57. data/lib/aidp/jobs/background_runner.rb +278 -0
  58. data/lib/aidp/message_display.rb +48 -0
  59. data/lib/aidp/provider_manager.rb +3 -1
  60. data/lib/aidp/providers/anthropic.rb +100 -17
  61. data/lib/aidp/providers/base.rb +42 -11
  62. data/lib/aidp/providers/codex.rb +248 -0
  63. data/lib/aidp/providers/cursor.rb +35 -42
  64. data/lib/aidp/providers/gemini.rb +25 -15
  65. data/lib/aidp/providers/github_copilot.rb +41 -42
  66. data/lib/aidp/providers/opencode.rb +34 -41
  67. data/lib/aidp/version.rb +1 -1
  68. data/lib/aidp/workflows/definitions.rb +357 -0
  69. data/lib/aidp/workflows/guided_agent.rb +400 -0
  70. data/lib/aidp/workflows/selector.rb +171 -0
  71. data/lib/aidp.rb +12 -0
  72. data/templates/planning/generate_llm_style_guide.md +119 -0
  73. metadata +41 -26
  74. /data/templates/{ANALYZE/02_ARCHITECTURE_ANALYSIS.md → analysis/analyze_architecture.md} +0 -0
  75. /data/templates/{ANALYZE/05_DOCUMENTATION_ANALYSIS.md → analysis/analyze_documentation.md} +0 -0
  76. /data/templates/{ANALYZE/04_FUNCTIONALITY_ANALYSIS.md → analysis/analyze_functionality.md} +0 -0
  77. /data/templates/{ANALYZE/01_REPOSITORY_ANALYSIS.md → analysis/analyze_repository.md} +0 -0
  78. /data/templates/{ANALYZE/06_STATIC_ANALYSIS.md → analysis/analyze_static_code.md} +0 -0
  79. /data/templates/{ANALYZE/03_TEST_ANALYSIS.md → analysis/analyze_tests.md} +0 -0
  80. /data/templates/{ANALYZE/07_REFACTORING_RECOMMENDATIONS.md → analysis/recommend_refactoring.md} +0 -0
  81. /data/templates/{ANALYZE/06a_tree_sitter_scan.md → analysis/scan_with_tree_sitter.md} +0 -0
  82. /data/templates/{EXECUTE/11_STATIC_ANALYSIS.md → implementation/configure_static_analysis.md} +0 -0
  83. /data/templates/{EXECUTE/14_DOCS_PORTAL.md → implementation/create_documentation_portal.md} +0 -0
  84. /data/templates/{EXECUTE/10_IMPLEMENTATION_AGENT.md → implementation/implement_features.md} +0 -0
  85. /data/templates/{EXECUTE/13_DELIVERY_ROLLOUT.md → implementation/plan_delivery.md} +0 -0
  86. /data/templates/{EXECUTE/15_POST_RELEASE.md → implementation/review_post_release.md} +0 -0
  87. /data/templates/{EXECUTE/09_SCAFFOLDING_DEVEX.md → implementation/setup_scaffolding.md} +0 -0
  88. /data/templates/{EXECUTE/02A_ARCH_GATE_QUESTIONS.md → planning/ask_architecture_questions.md} +0 -0
  89. /data/templates/{EXECUTE/00_PRD.md → planning/create_prd.md} +0 -0
  90. /data/templates/{EXECUTE/08_TASKS.md → planning/create_tasks.md} +0 -0
  91. /data/templates/{EXECUTE/04_DOMAIN_DECOMPOSITION.md → planning/decompose_domain.md} +0 -0
  92. /data/templates/{EXECUTE/01_NFRS.md → planning/define_nfrs.md} +0 -0
  93. /data/templates/{EXECUTE/05_CONTRACTS.md → planning/design_apis.md} +0 -0
  94. /data/templates/{EXECUTE/02_ARCHITECTURE.md → planning/design_architecture.md} +0 -0
  95. /data/templates/{EXECUTE/06_THREAT_MODEL.md → planning/design_data_model.md} +0 -0
  96. /data/templates/{EXECUTE/03_ADR_FACTORY.md → planning/generate_adrs.md} +0 -0
  97. /data/templates/{EXECUTE/12_OBSERVABILITY_SLOS.md → planning/plan_observability.md} +0 -0
  98. /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"