aidp 0.9.6 → 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/error_handler.rb +4 -2
- data/lib/aidp/{analysis → analyze}/kb_inspector.rb +93 -89
- data/lib/aidp/analyze/prioritizer.rb +3 -2
- data/lib/aidp/analyze/progress.rb +2 -1
- data/lib/aidp/analyze/ruby_maat_integration.rb +7 -3
- data/lib/aidp/analyze/runner.rb +73 -11
- data/lib/aidp/{analysis → analyze}/seams.rb +1 -1
- data/lib/aidp/analyze/steps.rb +10 -8
- data/lib/aidp/{analysis → analyze}/tree_sitter_grammar_loader.rb +11 -5
- data/lib/aidp/{analysis → analyze}/tree_sitter_scan.rb +21 -15
- data/lib/aidp/cli/checkpoint_command.rb +98 -0
- data/lib/aidp/cli/first_run_wizard.rb +83 -103
- data/lib/aidp/cli/jobs_command.rb +270 -36
- data/lib/aidp/cli/terminal_io.rb +3 -3
- data/lib/aidp/cli.rb +411 -69
- 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 +67 -20
- 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 +50 -26
- 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 +25 -4
- data/lib/aidp/harness/error_handler.rb +103 -28
- data/lib/aidp/harness/provider_factory.rb +6 -1
- data/lib/aidp/harness/provider_manager.rb +273 -19
- data/lib/aidp/harness/runner.rb +14 -6
- data/lib/aidp/harness/simple_user_interface.rb +6 -4
- data/lib/aidp/harness/status_display.rb +118 -106
- data/lib/aidp/harness/test_runner.rb +83 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +7 -5
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +22 -4
- data/lib/aidp/harness/ui/error_handler.rb +7 -2
- data/lib/aidp/harness/ui/frame_manager.rb +61 -39
- data/lib/aidp/harness/ui/job_monitor.rb +2 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +27 -16
- 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 +26 -7
- 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 +20 -9
- data/lib/aidp/harness/ui/workflow_controller.rb +27 -9
- data/lib/aidp/harness/user_interface.rb +338 -330
- data/lib/aidp/jobs/background_runner.rb +278 -0
- data/lib/aidp/message_display.rb +48 -0
- data/lib/aidp/provider_manager.rb +13 -7
- data/lib/aidp/providers/anthropic.rb +101 -18
- data/lib/aidp/providers/base.rb +51 -1
- data/lib/aidp/providers/codex.rb +248 -0
- data/lib/aidp/providers/cursor.rb +39 -48
- data/lib/aidp/providers/gemini.rb +26 -16
- data/lib/aidp/providers/github_copilot.rb +263 -0
- data/lib/aidp/providers/opencode.rb +38 -47
- 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 +16 -4
- data/templates/planning/generate_llm_style_guide.md +119 -0
- metadata +43 -31
- data/lib/aidp/analyze/progress_visualizer.rb +0 -314
- /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
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "tty-prompt"
|
|
4
|
+
require "tty-cursor"
|
|
4
5
|
|
|
5
6
|
module Aidp
|
|
6
7
|
module Harness
|
|
7
8
|
# Handles user interaction and feedback collection
|
|
8
9
|
class UserInterface
|
|
10
|
+
include Aidp::MessageDisplay
|
|
11
|
+
|
|
9
12
|
def initialize(prompt: TTY::Prompt.new)
|
|
10
13
|
@input_history = []
|
|
11
14
|
@file_selection_enabled = false
|
|
12
15
|
@prompt = prompt
|
|
16
|
+
@cursor = TTY::Cursor
|
|
13
17
|
@control_mutex = Mutex.new
|
|
14
18
|
@pause_requested = false
|
|
15
19
|
@stop_requested = false
|
|
@@ -36,7 +40,7 @@ module Aidp
|
|
|
36
40
|
if default
|
|
37
41
|
return default
|
|
38
42
|
elsif required
|
|
39
|
-
|
|
43
|
+
display_message("❌ This field is required. Please provide a response.", type: :error)
|
|
40
44
|
next
|
|
41
45
|
else
|
|
42
46
|
return nil
|
|
@@ -82,7 +86,7 @@ module Aidp
|
|
|
82
86
|
|
|
83
87
|
# Validate response if required
|
|
84
88
|
if question_data[:required] != false && (response.nil? || response.to_s.strip.empty?)
|
|
85
|
-
|
|
89
|
+
display_message("❌ This question is required. Please provide a response.", type: :error)
|
|
86
90
|
redo
|
|
87
91
|
end
|
|
88
92
|
|
|
@@ -99,11 +103,11 @@ module Aidp
|
|
|
99
103
|
|
|
100
104
|
# Display feedback context
|
|
101
105
|
def display_feedback_context(context)
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
display_message("\n📋 Context:", type: :highlight)
|
|
107
|
+
display_message("-" * 30, type: :muted)
|
|
104
108
|
|
|
105
109
|
if context[:type]
|
|
106
|
-
|
|
110
|
+
display_message("Type: #{context[:type]}", type: :info)
|
|
107
111
|
end
|
|
108
112
|
|
|
109
113
|
if context[:urgency]
|
|
@@ -113,23 +117,23 @@ module Aidp
|
|
|
113
117
|
"low" => "🟢"
|
|
114
118
|
}
|
|
115
119
|
urgency_emoji = urgency_emojis[context[:urgency]] || "ℹ️"
|
|
116
|
-
|
|
120
|
+
display_message("Urgency: #{urgency_emoji} #{context[:urgency].capitalize}", type: :info)
|
|
117
121
|
end
|
|
118
122
|
|
|
119
123
|
if context[:description]
|
|
120
|
-
|
|
124
|
+
display_message("Description: #{context[:description]}", type: :info)
|
|
121
125
|
end
|
|
122
126
|
|
|
123
127
|
if context[:agent_output]
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
display_message("\nAgent Output:", type: :info)
|
|
129
|
+
display_message(context[:agent_output], type: :info)
|
|
126
130
|
end
|
|
127
131
|
end
|
|
128
132
|
|
|
129
133
|
# Display question presentation header
|
|
130
134
|
def display_question_presentation_header(questions, context)
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
display_message("\n🤖 Agent needs your feedback:", type: :highlight)
|
|
136
|
+
display_message("=" * 60, type: :muted)
|
|
133
137
|
|
|
134
138
|
# Display question overview
|
|
135
139
|
display_question_overview(questions)
|
|
@@ -139,8 +143,8 @@ module Aidp
|
|
|
139
143
|
display_context_summary(context)
|
|
140
144
|
end
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
display_message("\n📝 Questions to answer:", type: :info)
|
|
147
|
+
display_message("-" * 40, type: :muted)
|
|
144
148
|
end
|
|
145
149
|
|
|
146
150
|
# Display question overview
|
|
@@ -151,23 +155,23 @@ module Aidp
|
|
|
151
155
|
|
|
152
156
|
question_types = questions.map { |q| q[:type] || "text" }.uniq
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
display_message("📊 Overview:", type: :info)
|
|
159
|
+
display_message(" Total questions: #{total_questions}", type: :info)
|
|
160
|
+
display_message(" Required: #{required_questions}", type: :info)
|
|
161
|
+
display_message(" Optional: #{optional_questions}", type: :info)
|
|
162
|
+
display_message(" Question types: #{question_types.join(", ")}", type: :info)
|
|
159
163
|
|
|
160
164
|
# Estimate completion time
|
|
161
165
|
estimated_time = estimate_completion_time(questions)
|
|
162
|
-
|
|
166
|
+
display_message(" Estimated time: #{estimated_time}", type: :info)
|
|
163
167
|
end
|
|
164
168
|
|
|
165
169
|
# Display context summary
|
|
166
170
|
def display_context_summary(context)
|
|
167
|
-
|
|
171
|
+
display_message("\n📋 Context Summary:", type: :info)
|
|
168
172
|
|
|
169
173
|
if context[:type]
|
|
170
|
-
|
|
174
|
+
display_message(" Type: #{context[:type]}", type: :info)
|
|
171
175
|
end
|
|
172
176
|
|
|
173
177
|
if context[:urgency]
|
|
@@ -177,11 +181,11 @@ module Aidp
|
|
|
177
181
|
"low" => "🟢"
|
|
178
182
|
}
|
|
179
183
|
urgency_emoji = urgency_emojis[context[:urgency]] || "ℹ️"
|
|
180
|
-
|
|
184
|
+
display_message(" Urgency: #{urgency_emoji} #{context[:urgency].capitalize}", type: :info)
|
|
181
185
|
end
|
|
182
186
|
|
|
183
187
|
if context[:description]
|
|
184
|
-
|
|
188
|
+
display_message(" Description: #{context[:description]}", type: :info)
|
|
185
189
|
end
|
|
186
190
|
end
|
|
187
191
|
|
|
@@ -230,9 +234,9 @@ module Aidp
|
|
|
230
234
|
required = question_data[:required] != false
|
|
231
235
|
|
|
232
236
|
# Display question header
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
237
|
+
display_message("\n" + "=" * 60, type: :muted)
|
|
238
|
+
display_message("📝 Question #{question_number} of #{total_questions}", type: :highlight)
|
|
239
|
+
display_message("=" * 60, type: :muted)
|
|
236
240
|
|
|
237
241
|
# Display question text with formatting
|
|
238
242
|
display_question_text(question_text, question_type)
|
|
@@ -243,7 +247,7 @@ module Aidp
|
|
|
243
247
|
# Display question instructions
|
|
244
248
|
display_question_instructions(question_type, options, default_value, required)
|
|
245
249
|
|
|
246
|
-
|
|
250
|
+
display_message("\n" + "-" * 60, type: :muted)
|
|
247
251
|
end
|
|
248
252
|
|
|
249
253
|
# Display question text with formatting
|
|
@@ -260,96 +264,96 @@ module Aidp
|
|
|
260
264
|
}
|
|
261
265
|
type_emoji = type_emojis[question_type] || "❓"
|
|
262
266
|
|
|
263
|
-
|
|
267
|
+
display_message("#{type_emoji} #{question_text}", type: :info)
|
|
264
268
|
end
|
|
265
269
|
|
|
266
270
|
# Display question metadata
|
|
267
271
|
def display_question_metadata(question_type, expected_input, options, default_value, required)
|
|
268
|
-
|
|
272
|
+
display_message("\n📋 Question Details:", type: :info)
|
|
269
273
|
|
|
270
274
|
# Question type
|
|
271
|
-
|
|
275
|
+
display_message(" Type: #{question_type.capitalize}", type: :info)
|
|
272
276
|
|
|
273
277
|
# Expected input
|
|
274
278
|
if expected_input != "text"
|
|
275
|
-
|
|
279
|
+
display_message(" Expected input: #{expected_input}", type: :info)
|
|
276
280
|
end
|
|
277
281
|
|
|
278
282
|
# Options
|
|
279
283
|
if options && !options.empty?
|
|
280
|
-
|
|
284
|
+
display_message(" Options: #{options.length} available", type: :info)
|
|
281
285
|
end
|
|
282
286
|
|
|
283
287
|
# Default value
|
|
284
288
|
if default_value
|
|
285
|
-
|
|
289
|
+
display_message(" Default: #{default_value}", type: :info)
|
|
286
290
|
end
|
|
287
291
|
|
|
288
292
|
# Required status
|
|
289
293
|
status = required ? "Required" : "Optional"
|
|
290
294
|
status_emoji = required ? "🔴" : "🟢"
|
|
291
|
-
|
|
295
|
+
display_message(" Status: #{status_emoji} #{status}", type: :info)
|
|
292
296
|
end
|
|
293
297
|
|
|
294
298
|
# Display question instructions
|
|
295
299
|
def display_question_instructions(question_type, options, default_value, required)
|
|
296
|
-
|
|
300
|
+
display_message("\n💡 Instructions:", type: :info)
|
|
297
301
|
|
|
298
302
|
case question_type
|
|
299
303
|
when "text"
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
304
|
+
display_message(" • Enter your text response", type: :info)
|
|
305
|
+
display_message(" • Use @ for file selection if needed", type: :info)
|
|
306
|
+
display_message(" • Press Enter when done", type: :info)
|
|
303
307
|
when "choice"
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
308
|
+
display_message(" • Select from the numbered options below", type: :info)
|
|
309
|
+
display_message(" • Enter the number of your choice", type: :info)
|
|
310
|
+
display_message(" • Press Enter to confirm", type: :info)
|
|
307
311
|
when "confirmation"
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
312
|
+
display_message(" • Enter 'y' or 'yes' for Yes", type: :info)
|
|
313
|
+
display_message(" • Enter 'n' or 'no' for No", type: :info)
|
|
314
|
+
display_message(" • Press Enter for default", type: :info)
|
|
311
315
|
when "file"
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
316
|
+
display_message(" • Enter file path directly", type: :info)
|
|
317
|
+
display_message(" • Use @ to browse and select files", type: :info)
|
|
318
|
+
display_message(" • File must exist and be readable", type: :info)
|
|
315
319
|
when "number"
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
320
|
+
display_message(" • Enter a valid number", type: :info)
|
|
321
|
+
display_message(" • Use decimal point for decimals", type: :info)
|
|
322
|
+
display_message(" • Press Enter when done", type: :info)
|
|
319
323
|
when "email"
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
324
|
+
display_message(" • Enter a valid email address", type: :info)
|
|
325
|
+
display_message(" • Format: user@domain.com", type: :info)
|
|
326
|
+
display_message(" • Press Enter when done", type: :info)
|
|
323
327
|
when "url"
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
328
|
+
display_message(" • Enter a valid URL", type: :info)
|
|
329
|
+
display_message(" • Format: https://example.com", type: :info)
|
|
330
|
+
display_message(" • Press Enter when done", type: :info)
|
|
327
331
|
end
|
|
328
332
|
|
|
329
333
|
# Additional instructions based on options
|
|
330
334
|
if options && !options.empty?
|
|
331
|
-
|
|
335
|
+
display_message("\n📋 Available Options:", type: :info)
|
|
332
336
|
options.each_with_index do |option, index|
|
|
333
337
|
marker = (default_value && option == default_value) ? " (default)" : ""
|
|
334
|
-
|
|
338
|
+
display_message(" #{index + 1}. #{option}#{marker}", type: :info)
|
|
335
339
|
end
|
|
336
340
|
end
|
|
337
341
|
|
|
338
342
|
# Default value instructions
|
|
339
343
|
if default_value
|
|
340
|
-
|
|
341
|
-
|
|
344
|
+
display_message("\n⚡ Quick Answer:", type: :info)
|
|
345
|
+
display_message(" • Press Enter to use default: #{default_value}", type: :info)
|
|
342
346
|
end
|
|
343
347
|
|
|
344
348
|
# Required field instructions
|
|
345
349
|
if required
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
350
|
+
display_message("\n⚠️ Required Field:", type: :info)
|
|
351
|
+
display_message(" • This question must be answered", type: :info)
|
|
352
|
+
display_message(" • Cannot be left blank", type: :info)
|
|
349
353
|
else
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
354
|
+
display_message("\n✅ Optional Field:", type: :info)
|
|
355
|
+
display_message(" • This question can be skipped", type: :info)
|
|
356
|
+
display_message(" • Press Enter to leave blank", type: :info)
|
|
353
357
|
end
|
|
354
358
|
end
|
|
355
359
|
|
|
@@ -358,13 +362,13 @@ module Aidp
|
|
|
358
362
|
progress_percentage = (current_index.to_f / total_questions * 100).round(1)
|
|
359
363
|
progress_bar = generate_progress_bar(progress_percentage)
|
|
360
364
|
|
|
361
|
-
|
|
365
|
+
display_message("\n📊 Progress: #{progress_bar} #{progress_percentage}% (#{current_index}/#{total_questions})", type: :info)
|
|
362
366
|
|
|
363
367
|
# Show estimated time remaining
|
|
364
368
|
if current_index < total_questions
|
|
365
369
|
remaining_questions = total_questions - current_index
|
|
366
370
|
estimated_remaining = estimate_remaining_time(remaining_questions)
|
|
367
|
-
|
|
371
|
+
display_message("⏱️ Estimated time remaining: #{estimated_remaining}", type: :info)
|
|
368
372
|
end
|
|
369
373
|
end
|
|
370
374
|
|
|
@@ -391,34 +395,34 @@ module Aidp
|
|
|
391
395
|
|
|
392
396
|
# Display question completion summary
|
|
393
397
|
def display_question_completion_summary(responses, questions)
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
398
|
+
display_message("\n" + "=" * 60, type: :muted)
|
|
399
|
+
display_message("✅ Question Completion Summary", type: :success)
|
|
400
|
+
display_message("=" * 60, type: :muted)
|
|
397
401
|
|
|
398
402
|
# Show completion statistics
|
|
399
403
|
total_questions = questions.length
|
|
400
404
|
answered_questions = responses.values.count { |v| !v.nil? && !v.to_s.strip.empty? }
|
|
401
405
|
skipped_questions = total_questions - answered_questions
|
|
402
406
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
407
|
+
display_message("📊 Statistics:", type: :info)
|
|
408
|
+
display_message(" Total questions: #{total_questions}", type: :info)
|
|
409
|
+
display_message(" Answered: #{answered_questions}", type: :info)
|
|
410
|
+
display_message(" Skipped: #{skipped_questions}", type: :info)
|
|
411
|
+
display_message(" Completion rate: #{(answered_questions.to_f / total_questions * 100).round(1)}%", type: :info)
|
|
408
412
|
|
|
409
413
|
# Show response summary
|
|
410
|
-
|
|
414
|
+
display_message("\n📝 Response Summary:", type: :info)
|
|
411
415
|
responses.each do |key, value|
|
|
412
416
|
question_number = key.gsub("question_", "")
|
|
413
417
|
if value.nil? || value.to_s.strip.empty?
|
|
414
|
-
|
|
418
|
+
display_message(" #{question_number}. [Skipped]", type: :muted)
|
|
415
419
|
else
|
|
416
420
|
display_value = (value.to_s.length > 50) ? "#{value.to_s[0..47]}..." : value.to_s
|
|
417
|
-
|
|
421
|
+
display_message(" #{question_number}. #{display_value}", type: :info)
|
|
418
422
|
end
|
|
419
423
|
end
|
|
420
424
|
|
|
421
|
-
|
|
425
|
+
display_message("\n🚀 Continuing execution...", type: :success)
|
|
422
426
|
end
|
|
423
427
|
|
|
424
428
|
# Display question information (legacy method for compatibility)
|
|
@@ -460,7 +464,7 @@ module Aidp
|
|
|
460
464
|
"Required: No"
|
|
461
465
|
end
|
|
462
466
|
|
|
463
|
-
|
|
467
|
+
display_message(" #{info_parts.join(" | ")}", type: :info)
|
|
464
468
|
end
|
|
465
469
|
|
|
466
470
|
# Get response for a specific question with enhanced validation
|
|
@@ -496,15 +500,15 @@ module Aidp
|
|
|
496
500
|
def handle_input_error(error, question_data, retry_count = 0)
|
|
497
501
|
max_retries = 3
|
|
498
502
|
|
|
499
|
-
|
|
500
|
-
|
|
503
|
+
display_message("\n🚨 Input Error:", type: :error)
|
|
504
|
+
display_message(" #{error.message}", type: :error)
|
|
501
505
|
|
|
502
506
|
if retry_count < max_retries
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
507
|
+
display_message("\n🔄 Retry Options:", type: :info)
|
|
508
|
+
display_message(" 1. Try again", type: :info)
|
|
509
|
+
display_message(" 2. Skip this question", type: :info)
|
|
510
|
+
display_message(" 3. Get help", type: :info)
|
|
511
|
+
display_message(" 4. Cancel all questions", type: :info)
|
|
508
512
|
|
|
509
513
|
choice = @prompt.select("Choose an option:", {
|
|
510
514
|
"Try again" => "1",
|
|
@@ -515,23 +519,23 @@ module Aidp
|
|
|
515
519
|
|
|
516
520
|
case choice
|
|
517
521
|
when "1"
|
|
518
|
-
|
|
522
|
+
display_message("🔄 Retrying...", type: :info)
|
|
519
523
|
:retry
|
|
520
524
|
when "2"
|
|
521
|
-
|
|
525
|
+
display_message("⏭️ Skipping question...", type: :warning)
|
|
522
526
|
:skip
|
|
523
527
|
when "3"
|
|
524
528
|
show_question_help(question_data)
|
|
525
529
|
:retry
|
|
526
530
|
when "4"
|
|
527
|
-
|
|
531
|
+
display_message("❌ Cancelling all questions...", type: :error)
|
|
528
532
|
:cancel
|
|
529
533
|
else
|
|
530
|
-
|
|
534
|
+
display_message("❌ Invalid choice. Retrying...", type: :error)
|
|
531
535
|
:retry
|
|
532
536
|
end
|
|
533
537
|
else
|
|
534
|
-
|
|
538
|
+
display_message("\n❌ Maximum retries exceeded. Skipping question...", type: :error)
|
|
535
539
|
:skip
|
|
536
540
|
end
|
|
537
541
|
end
|
|
@@ -540,74 +544,74 @@ module Aidp
|
|
|
540
544
|
def show_question_help(question_data)
|
|
541
545
|
question_type = question_data[:type] || "text"
|
|
542
546
|
|
|
543
|
-
|
|
544
|
-
|
|
547
|
+
display_message("\n📖 Help for #{question_type.capitalize} Question:", type: :info)
|
|
548
|
+
display_message("=" * 50, type: :muted)
|
|
545
549
|
|
|
546
550
|
case question_type
|
|
547
551
|
when "text"
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
552
|
+
display_message("• Enter any text response", type: :info)
|
|
553
|
+
display_message("• Use @ for file selection if needed", type: :info)
|
|
554
|
+
display_message("• Press Enter when done", type: :info)
|
|
551
555
|
when "choice"
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
556
|
+
display_message("• Select from the numbered options", type: :info)
|
|
557
|
+
display_message("• Enter the number of your choice", type: :info)
|
|
558
|
+
display_message("• Or type the option text directly", type: :info)
|
|
555
559
|
when "confirmation"
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
560
|
+
display_message("• Enter 'y' or 'yes' for Yes", type: :info)
|
|
561
|
+
display_message("• Enter 'n' or 'no' for No", type: :info)
|
|
562
|
+
display_message("• Press Enter for default", type: :info)
|
|
559
563
|
when "file"
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
564
|
+
display_message("• Enter file path directly", type: :info)
|
|
565
|
+
display_message("• Use @ to browse and select files", type: :info)
|
|
566
|
+
display_message("• File must exist and be readable", type: :info)
|
|
563
567
|
when "number"
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
568
|
+
display_message("• Enter a valid number", type: :info)
|
|
569
|
+
display_message("• Use decimal point for decimals", type: :info)
|
|
570
|
+
display_message("• Check range requirements", type: :info)
|
|
567
571
|
when "email"
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
572
|
+
display_message("• Enter a valid email address", type: :info)
|
|
573
|
+
display_message("• Format: user@domain.com", type: :info)
|
|
574
|
+
display_message("• Check for typos", type: :info)
|
|
571
575
|
when "url"
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
576
|
+
display_message("• Enter a valid URL", type: :info)
|
|
577
|
+
display_message("• Format: https://example.com", type: :info)
|
|
578
|
+
display_message("• Include protocol (http:// or https://)", type: :info)
|
|
575
579
|
end
|
|
576
580
|
|
|
577
|
-
|
|
581
|
+
display_message("\nPress Enter to continue...", type: :info)
|
|
578
582
|
@prompt.keypress("Press any key to continue...")
|
|
579
583
|
end
|
|
580
584
|
|
|
581
585
|
# Enhanced error handling and validation display
|
|
582
586
|
def display_validation_error(validation_result, _input_type)
|
|
583
|
-
|
|
584
|
-
|
|
587
|
+
display_message("\n❌ Validation Error:", type: :error)
|
|
588
|
+
display_message(" #{validation_result[:error_message]}", type: :error)
|
|
585
589
|
|
|
586
590
|
if validation_result[:suggestions].any?
|
|
587
|
-
|
|
591
|
+
display_message("\n💡 Suggestions:", type: :info)
|
|
588
592
|
validation_result[:suggestions].each do |suggestion|
|
|
589
|
-
|
|
593
|
+
display_message(" • #{suggestion}", type: :info)
|
|
590
594
|
end
|
|
591
595
|
end
|
|
592
596
|
|
|
593
597
|
if validation_result[:warnings].any?
|
|
594
|
-
|
|
598
|
+
display_message("\n⚠️ Warnings:", type: :warning)
|
|
595
599
|
validation_result[:warnings].each do |warning|
|
|
596
|
-
|
|
600
|
+
display_message(" • #{warning}", type: :warning)
|
|
597
601
|
end
|
|
598
602
|
end
|
|
599
603
|
|
|
600
|
-
|
|
604
|
+
display_message("\n🔄 Please try again...", type: :info)
|
|
601
605
|
end
|
|
602
606
|
|
|
603
607
|
# Display validation warnings
|
|
604
608
|
def display_validation_warnings(validation_result)
|
|
605
609
|
if validation_result[:warnings].any?
|
|
606
|
-
|
|
610
|
+
display_message("\n⚠️ Warnings:", type: :warning)
|
|
607
611
|
validation_result[:warnings].each do |warning|
|
|
608
|
-
|
|
612
|
+
display_message(" • #{warning}", type: :warning)
|
|
609
613
|
end
|
|
610
|
-
|
|
614
|
+
display_message("\nPress Enter to continue or type 'fix' to correct...", type: :info)
|
|
611
615
|
|
|
612
616
|
input = @prompt.ask("")
|
|
613
617
|
return input&.strip&.downcase == "fix"
|
|
@@ -652,10 +656,10 @@ module Aidp
|
|
|
652
656
|
def get_choice_response(options, default_value, required)
|
|
653
657
|
return nil if options.nil? || options.empty?
|
|
654
658
|
|
|
655
|
-
|
|
659
|
+
display_message("\n Available options:", type: :info)
|
|
656
660
|
options.each_with_index do |option, index|
|
|
657
661
|
marker = (default_value && option == default_value) ? " (default)" : ""
|
|
658
|
-
|
|
662
|
+
display_message(" #{index + 1}. #{option}#{marker}", type: :info)
|
|
659
663
|
end
|
|
660
664
|
|
|
661
665
|
loop do
|
|
@@ -669,7 +673,7 @@ module Aidp
|
|
|
669
673
|
if default_value
|
|
670
674
|
return default_value
|
|
671
675
|
elsif required
|
|
672
|
-
|
|
676
|
+
display_message("❌ Please make a selection.", type: :error)
|
|
673
677
|
next
|
|
674
678
|
else
|
|
675
679
|
return nil
|
|
@@ -749,7 +753,7 @@ module Aidp
|
|
|
749
753
|
if default_value
|
|
750
754
|
return default_value
|
|
751
755
|
elsif required
|
|
752
|
-
|
|
756
|
+
display_message("❌ Please provide a file path.", type: :error)
|
|
753
757
|
next
|
|
754
758
|
else
|
|
755
759
|
return nil
|
|
@@ -792,7 +796,7 @@ module Aidp
|
|
|
792
796
|
if default_value
|
|
793
797
|
return default_value
|
|
794
798
|
elsif required
|
|
795
|
-
|
|
799
|
+
display_message("❌ Please provide a number.", type: :error)
|
|
796
800
|
next
|
|
797
801
|
else
|
|
798
802
|
return nil
|
|
@@ -820,7 +824,7 @@ module Aidp
|
|
|
820
824
|
return Float(input.strip)
|
|
821
825
|
end
|
|
822
826
|
rescue ArgumentError
|
|
823
|
-
|
|
827
|
+
display_message("❌ Please enter a valid #{expected_input}.", type: :error)
|
|
824
828
|
next
|
|
825
829
|
end
|
|
826
830
|
end
|
|
@@ -839,7 +843,7 @@ module Aidp
|
|
|
839
843
|
if default_value
|
|
840
844
|
return default_value
|
|
841
845
|
elsif required
|
|
842
|
-
|
|
846
|
+
display_message("❌ Please provide an email address.", type: :error)
|
|
843
847
|
next
|
|
844
848
|
else
|
|
845
849
|
return nil
|
|
@@ -876,7 +880,7 @@ module Aidp
|
|
|
876
880
|
if default_value
|
|
877
881
|
return default_value
|
|
878
882
|
elsif required
|
|
879
|
-
|
|
883
|
+
display_message("❌ Please provide a URL.", type: :error)
|
|
880
884
|
next
|
|
881
885
|
else
|
|
882
886
|
return nil
|
|
@@ -1323,7 +1327,7 @@ module Aidp
|
|
|
1323
1327
|
|
|
1324
1328
|
# Handle empty input
|
|
1325
1329
|
if input.nil? || input.strip.empty?
|
|
1326
|
-
|
|
1330
|
+
display_message("Please provide a response.", type: :error)
|
|
1327
1331
|
next
|
|
1328
1332
|
end
|
|
1329
1333
|
|
|
@@ -1351,8 +1355,8 @@ module Aidp
|
|
|
1351
1355
|
available_files = find_files_advanced(search_options)
|
|
1352
1356
|
|
|
1353
1357
|
if available_files.empty?
|
|
1354
|
-
|
|
1355
|
-
|
|
1358
|
+
display_message("No files found matching '#{search_options[:term]}'. Please try again.", type: :warning)
|
|
1359
|
+
display_message("💡 Try: @ (all files), @.rb (Ruby files), @config (files with 'config'), @lib/ (files in lib directory)", type: :info)
|
|
1356
1360
|
return nil
|
|
1357
1361
|
end
|
|
1358
1362
|
|
|
@@ -1364,7 +1368,7 @@ module Aidp
|
|
|
1364
1368
|
|
|
1365
1369
|
if selection && selection >= 0 && selection < available_files.size
|
|
1366
1370
|
selected_file = available_files[selection]
|
|
1367
|
-
|
|
1371
|
+
display_message("✅ Selected: #{selected_file}", type: :success)
|
|
1368
1372
|
|
|
1369
1373
|
# Show file preview if requested
|
|
1370
1374
|
if search_options[:preview]
|
|
@@ -1376,7 +1380,7 @@ module Aidp
|
|
|
1376
1380
|
# User wants to refine search
|
|
1377
1381
|
handle_file_selection("@#{search_term}")
|
|
1378
1382
|
else
|
|
1379
|
-
|
|
1383
|
+
display_message("❌ Invalid selection. Please try again.", type: :error)
|
|
1380
1384
|
nil
|
|
1381
1385
|
end
|
|
1382
1386
|
end
|
|
@@ -1580,21 +1584,21 @@ module Aidp
|
|
|
1580
1584
|
|
|
1581
1585
|
# Display advanced file selection menu
|
|
1582
1586
|
def display_advanced_file_menu(files, search_options)
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1587
|
+
display_message("\n📁 Available files:", type: :info)
|
|
1588
|
+
display_message("Search: #{search_options[:term]} | Extensions: #{search_options[:extensions].join(", ")} | Directories: #{search_options[:directories].join(", ")}", type: :info)
|
|
1589
|
+
display_message("-" * 80, type: :muted)
|
|
1586
1590
|
|
|
1587
1591
|
files.each_with_index do |file, index|
|
|
1588
1592
|
file_info = get_file_info(file)
|
|
1589
|
-
|
|
1590
|
-
|
|
1593
|
+
display_message(" #{index + 1}. #{file_info[:display_name]}", type: :info)
|
|
1594
|
+
display_message(" 📄 #{file_info[:size]} | 📅 #{file_info[:modified]} | 🏷️ #{file_info[:type]}", type: :muted)
|
|
1591
1595
|
end
|
|
1592
1596
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1597
|
+
display_message("\nOptions:", type: :info)
|
|
1598
|
+
display_message(" 0. Cancel", type: :info)
|
|
1599
|
+
display_message(" -1. Refine search", type: :info)
|
|
1600
|
+
display_message(" p. Preview selected file", type: :info)
|
|
1601
|
+
display_message(" h. Show help", type: :info)
|
|
1598
1602
|
end
|
|
1599
1603
|
|
|
1600
1604
|
# Get file information for display
|
|
@@ -1666,7 +1670,7 @@ module Aidp
|
|
|
1666
1670
|
input = @prompt.ask("Select file (0-#{max_files}, -1=refine, p=preview, h=help): ")
|
|
1667
1671
|
|
|
1668
1672
|
if input.nil? || input.strip.empty?
|
|
1669
|
-
|
|
1673
|
+
display_message("Please enter a selection.", type: :error)
|
|
1670
1674
|
next
|
|
1671
1675
|
end
|
|
1672
1676
|
|
|
@@ -1678,7 +1682,7 @@ module Aidp
|
|
|
1678
1682
|
show_file_selection_help
|
|
1679
1683
|
next
|
|
1680
1684
|
when "p", "preview"
|
|
1681
|
-
|
|
1685
|
+
display_message("💡 Select a file number first, then use 'p' to preview it.", type: :info)
|
|
1682
1686
|
next
|
|
1683
1687
|
end
|
|
1684
1688
|
|
|
@@ -1691,71 +1695,71 @@ module Aidp
|
|
|
1691
1695
|
elsif selection.between?(1, max_files)
|
|
1692
1696
|
return selection - 1 # Convert to 0-based index
|
|
1693
1697
|
else
|
|
1694
|
-
|
|
1698
|
+
display_message("Please enter a number between 0 and #{max_files}, or use -1, p, h.", type: :error)
|
|
1695
1699
|
end
|
|
1696
1700
|
rescue ArgumentError
|
|
1697
|
-
|
|
1701
|
+
display_message("Please enter a valid number or command (0-#{max_files}, -1, p, h).", type: :error)
|
|
1698
1702
|
end
|
|
1699
1703
|
end
|
|
1700
1704
|
end
|
|
1701
1705
|
|
|
1702
1706
|
# Show file selection help
|
|
1703
1707
|
def show_file_selection_help
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1708
|
+
display_message("\n📖 File Selection Help:", type: :info)
|
|
1709
|
+
display_message("=" * 40, type: :muted)
|
|
1710
|
+
|
|
1711
|
+
display_message("\n🔍 Search Examples:", type: :info)
|
|
1712
|
+
display_message(" @ - Show all files", type: :info)
|
|
1713
|
+
display_message(" @.rb - Show Ruby files only", type: :info)
|
|
1714
|
+
display_message(" @config - Show files with 'config' in name", type: :info)
|
|
1715
|
+
display_message(" @lib/ - Show files in lib directory", type: :info)
|
|
1716
|
+
display_message(" @spec preview - Show spec files with preview option", type: :info)
|
|
1717
|
+
display_message(" @.js case - Show JavaScript files (case sensitive)", type: :info)
|
|
1718
|
+
|
|
1719
|
+
display_message("\n⌨️ Selection Commands:", type: :info)
|
|
1720
|
+
display_message(" 1-50 - Select file by number", type: :info)
|
|
1721
|
+
display_message(" 0 - Cancel selection", type: :info)
|
|
1722
|
+
display_message(" -1 - Refine search", type: :info)
|
|
1723
|
+
display_message(" p - Preview selected file", type: :info)
|
|
1724
|
+
display_message(" h - Show this help", type: :info)
|
|
1725
|
+
|
|
1726
|
+
display_message("\n💡 Tips:", type: :info)
|
|
1727
|
+
display_message(" • Files are sorted by relevance and type", type: :info)
|
|
1728
|
+
display_message(" • Use extension filters for specific file types", type: :info)
|
|
1729
|
+
display_message(" • Use directory filters to limit search scope", type: :info)
|
|
1730
|
+
display_message(" • Preview option shows file content before selection", type: :info)
|
|
1727
1731
|
end
|
|
1728
1732
|
|
|
1729
1733
|
# Show file preview
|
|
1730
1734
|
def show_file_preview(file_path)
|
|
1731
|
-
|
|
1732
|
-
|
|
1735
|
+
display_message("\n📄 File Preview: #{file_path}", type: :highlight)
|
|
1736
|
+
display_message("=" * 60, type: :muted)
|
|
1733
1737
|
|
|
1734
1738
|
begin
|
|
1735
1739
|
content = File.read(file_path)
|
|
1736
1740
|
lines = content.lines
|
|
1737
1741
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1742
|
+
display_message("📊 File Info:", type: :info)
|
|
1743
|
+
display_message(" Size: #{format_file_size(File.size(file_path))}", type: :info)
|
|
1744
|
+
display_message(" Lines: #{lines.count}", type: :info)
|
|
1745
|
+
display_message(" Modified: #{File.mtime(file_path).strftime("%Y-%m-%d %H:%M:%S")}", type: :info)
|
|
1746
|
+
display_message(" Type: #{get_file_type(file_path)}", type: :info)
|
|
1743
1747
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1748
|
+
display_message("\n📝 Content Preview (first 20 lines):", type: :info)
|
|
1749
|
+
display_message("-" * 40, type: :muted)
|
|
1746
1750
|
|
|
1747
1751
|
lines.first(20).each_with_index do |line, index|
|
|
1748
|
-
|
|
1752
|
+
display_message("#{(index + 1).to_s.rjust(3)}: #{line.chomp}", type: :info)
|
|
1749
1753
|
end
|
|
1750
1754
|
|
|
1751
1755
|
if lines.count > 20
|
|
1752
|
-
|
|
1756
|
+
display_message("... (#{lines.count - 20} more lines)", type: :muted)
|
|
1753
1757
|
end
|
|
1754
1758
|
rescue => e
|
|
1755
|
-
|
|
1759
|
+
display_message("❌ Error reading file: #{e.message}", type: :error)
|
|
1756
1760
|
end
|
|
1757
1761
|
|
|
1758
|
-
|
|
1762
|
+
display_message("\nPress Enter to continue...", type: :info)
|
|
1759
1763
|
@prompt.keypress("Press any key to continue...")
|
|
1760
1764
|
end
|
|
1761
1765
|
|
|
@@ -1783,17 +1787,17 @@ module Aidp
|
|
|
1783
1787
|
when "n", "no"
|
|
1784
1788
|
return false
|
|
1785
1789
|
else
|
|
1786
|
-
|
|
1790
|
+
display_message("Please enter 'y' or 'n'.", type: :error)
|
|
1787
1791
|
end
|
|
1788
1792
|
end
|
|
1789
1793
|
end
|
|
1790
1794
|
|
|
1791
1795
|
# Get choice from multiple options
|
|
1792
1796
|
def get_choice(message, options, default: nil)
|
|
1793
|
-
|
|
1797
|
+
display_message("\n#{message}", type: :info)
|
|
1794
1798
|
options.each_with_index do |option, index|
|
|
1795
1799
|
marker = (default && index == default) ? " (default)" : ""
|
|
1796
|
-
|
|
1800
|
+
display_message(" #{index + 1}. #{option}#{marker}", type: :info)
|
|
1797
1801
|
end
|
|
1798
1802
|
|
|
1799
1803
|
loop do
|
|
@@ -1801,7 +1805,7 @@ module Aidp
|
|
|
1801
1805
|
|
|
1802
1806
|
if input.nil? || input.strip.empty?
|
|
1803
1807
|
return default if default
|
|
1804
|
-
|
|
1808
|
+
display_message("Please make a selection.", type: :error)
|
|
1805
1809
|
next
|
|
1806
1810
|
end
|
|
1807
1811
|
|
|
@@ -1810,24 +1814,28 @@ module Aidp
|
|
|
1810
1814
|
if choice.between?(1, options.size)
|
|
1811
1815
|
return choice - 1 # Convert to 0-based index
|
|
1812
1816
|
else
|
|
1813
|
-
|
|
1817
|
+
display_message("Please enter a number between 1 and #{options.size}.", type: :error)
|
|
1814
1818
|
end
|
|
1815
1819
|
rescue ArgumentError
|
|
1816
|
-
|
|
1820
|
+
display_message("Please enter a valid number.", type: :error)
|
|
1817
1821
|
end
|
|
1818
1822
|
end
|
|
1819
1823
|
end
|
|
1820
1824
|
|
|
1821
1825
|
# Display progress message
|
|
1822
1826
|
def show_progress(message)
|
|
1823
|
-
|
|
1824
|
-
$stdout.flush
|
|
1827
|
+
print_to_stderr(@cursor.clear_line, @cursor.column(1), message)
|
|
1825
1828
|
end
|
|
1826
1829
|
|
|
1827
1830
|
# Clear progress message
|
|
1828
1831
|
def clear_progress
|
|
1829
|
-
|
|
1830
|
-
|
|
1832
|
+
print_to_stderr(@cursor.clear_line, @cursor.column(1))
|
|
1833
|
+
end
|
|
1834
|
+
|
|
1835
|
+
# Helper method to print to stderr with flush
|
|
1836
|
+
def print_to_stderr(*parts)
|
|
1837
|
+
parts.each { |part| $stderr.print part }
|
|
1838
|
+
$stderr.flush
|
|
1831
1839
|
end
|
|
1832
1840
|
|
|
1833
1841
|
# Get input history
|
|
@@ -1842,43 +1850,43 @@ module Aidp
|
|
|
1842
1850
|
|
|
1843
1851
|
# Display interactive help
|
|
1844
1852
|
def show_help
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1853
|
+
display_message("\n📖 Interactive Prompt Help:", type: :info)
|
|
1854
|
+
display_message("=" * 40, type: :info)
|
|
1855
|
+
|
|
1856
|
+
display_message("\n🔤 Input Types:", type: :info)
|
|
1857
|
+
display_message(" • Text: Free-form text input", type: :info)
|
|
1858
|
+
display_message(" • Choice: Select from predefined options", type: :info)
|
|
1859
|
+
display_message(" • Confirmation: Yes/No questions", type: :info)
|
|
1860
|
+
display_message(" • File: File path with @ browsing", type: :info)
|
|
1861
|
+
display_message(" • Number: Integer or decimal numbers", type: :info)
|
|
1862
|
+
display_message(" • Email: Email address format", type: :info)
|
|
1863
|
+
display_message(" • URL: Web URL format", type: :info)
|
|
1864
|
+
|
|
1865
|
+
display_message("\n⌨️ Special Commands:", type: :info)
|
|
1866
|
+
display_message(" • @: Browse and select files", type: :info)
|
|
1867
|
+
display_message(" • Enter: Use default value (if available)", type: :info)
|
|
1868
|
+
display_message(" • Ctrl+C: Cancel operation", type: :info)
|
|
1869
|
+
|
|
1870
|
+
display_message("\n📁 File Selection:", type: :info)
|
|
1871
|
+
display_message(" • Type @ to browse files", type: :info)
|
|
1872
|
+
display_message(" • Type @search to filter files", type: :info)
|
|
1873
|
+
display_message(" • Select by number or type 0 to cancel", type: :info)
|
|
1874
|
+
|
|
1875
|
+
display_message("\n✅ Validation:", type: :info)
|
|
1876
|
+
display_message(" • Required fields must be filled", type: :info)
|
|
1877
|
+
display_message(" • Input format is validated automatically", type: :info)
|
|
1878
|
+
display_message(" • Invalid input shows error and retries", type: :info)
|
|
1879
|
+
|
|
1880
|
+
display_message("\n💡 Tips:", type: :info)
|
|
1881
|
+
display_message(" • Use Tab for auto-completion", type: :info)
|
|
1882
|
+
display_message(" • Arrow keys for history navigation", type: :info)
|
|
1883
|
+
display_message(" • Default values are shown in prompts", type: :info)
|
|
1876
1884
|
end
|
|
1877
1885
|
|
|
1878
1886
|
# Display question summary
|
|
1879
1887
|
def display_question_summary(questions)
|
|
1880
|
-
|
|
1881
|
-
|
|
1888
|
+
display_message("\n📋 Question Summary:", type: :info)
|
|
1889
|
+
display_message("-" * 30, type: :info)
|
|
1882
1890
|
|
|
1883
1891
|
questions.each_with_index do |question_data, index|
|
|
1884
1892
|
question_number = question_data[:number] || (index + 1)
|
|
@@ -1898,14 +1906,14 @@ module Aidp
|
|
|
1898
1906
|
}
|
|
1899
1907
|
type_emoji = type_emojis[question_type] || "❓"
|
|
1900
1908
|
|
|
1901
|
-
|
|
1909
|
+
display_message(" #{question_number}. #{type_emoji} #{question_text} (#{status})", type: :info)
|
|
1902
1910
|
end
|
|
1903
1911
|
end
|
|
1904
1912
|
|
|
1905
1913
|
# Get user preferences for feedback collection
|
|
1906
1914
|
def get_user_preferences
|
|
1907
|
-
|
|
1908
|
-
|
|
1915
|
+
display_message("\n⚙️ User Preferences:", type: :info)
|
|
1916
|
+
display_message("-" * 25, type: :muted)
|
|
1909
1917
|
|
|
1910
1918
|
preferences = {}
|
|
1911
1919
|
|
|
@@ -1967,14 +1975,14 @@ module Aidp
|
|
|
1967
1975
|
# Show help if needed
|
|
1968
1976
|
if should_show_help?(questions.first&.dig(:type), seen_types)
|
|
1969
1977
|
show_help
|
|
1970
|
-
|
|
1978
|
+
display_message("\nPress Enter to continue...", type: :info)
|
|
1971
1979
|
@prompt.keypress("Press any key to continue...")
|
|
1972
1980
|
end
|
|
1973
1981
|
|
|
1974
1982
|
# Display question summary if verbose
|
|
1975
1983
|
if @verbose_mode
|
|
1976
1984
|
display_question_summary(questions)
|
|
1977
|
-
|
|
1985
|
+
display_message("\nPress Enter to start answering questions...", type: :info)
|
|
1978
1986
|
@prompt.keypress("Press any key to continue...")
|
|
1979
1987
|
end
|
|
1980
1988
|
|
|
@@ -1995,7 +2003,7 @@ module Aidp
|
|
|
1995
2003
|
default_value = options[:default]
|
|
1996
2004
|
required = options[:required] != false
|
|
1997
2005
|
|
|
1998
|
-
|
|
2006
|
+
display_message("\n❓ #{question}", type: :info)
|
|
1999
2007
|
|
|
2000
2008
|
case question_type
|
|
2001
2009
|
when "text"
|
|
@@ -2013,8 +2021,8 @@ module Aidp
|
|
|
2013
2021
|
def collect_batch_feedback(questions)
|
|
2014
2022
|
responses = {}
|
|
2015
2023
|
|
|
2016
|
-
|
|
2017
|
-
|
|
2024
|
+
display_message("\n📝 Quick Feedback Collection:", type: :info)
|
|
2025
|
+
display_message("=" * 35, type: :muted)
|
|
2018
2026
|
|
|
2019
2027
|
questions.each_with_index do |question_data, index|
|
|
2020
2028
|
question_number = index + 1
|
|
@@ -2023,7 +2031,7 @@ module Aidp
|
|
|
2023
2031
|
default_value = question_data[:default]
|
|
2024
2032
|
required = question_data[:required] != false
|
|
2025
2033
|
|
|
2026
|
-
|
|
2034
|
+
display_message("\n#{question_number}. #{question_text}", type: :info)
|
|
2027
2035
|
|
|
2028
2036
|
response = get_quick_feedback(question_text, {
|
|
2029
2037
|
type: question_type,
|
|
@@ -2035,7 +2043,7 @@ module Aidp
|
|
|
2035
2043
|
responses["question_#{question_number}"] = response
|
|
2036
2044
|
end
|
|
2037
2045
|
|
|
2038
|
-
|
|
2046
|
+
display_message("\n✅ Batch feedback collected.", type: :success)
|
|
2039
2047
|
responses
|
|
2040
2048
|
end
|
|
2041
2049
|
|
|
@@ -2059,13 +2067,13 @@ module Aidp
|
|
|
2059
2067
|
end
|
|
2060
2068
|
end
|
|
2061
2069
|
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2070
|
+
display_message("\n🎮 Control Interface Started", type: :success)
|
|
2071
|
+
display_message(" Press 'p' + Enter to pause", type: :info)
|
|
2072
|
+
display_message(" Press 'r' + Enter to resume", type: :info)
|
|
2073
|
+
display_message(" Press 's' + Enter to stop", type: :info)
|
|
2074
|
+
display_message(" Press 'h' + Enter for help", type: :info)
|
|
2075
|
+
display_message(" Press 'q' + Enter to quit control interface", type: :info)
|
|
2076
|
+
display_message("=" * 50, type: :muted)
|
|
2069
2077
|
end
|
|
2070
2078
|
|
|
2071
2079
|
# Stop the control interface
|
|
@@ -2077,7 +2085,7 @@ module Aidp
|
|
|
2077
2085
|
end
|
|
2078
2086
|
end
|
|
2079
2087
|
|
|
2080
|
-
|
|
2088
|
+
display_message("\n🛑 Control Interface Stopped", type: :info)
|
|
2081
2089
|
end
|
|
2082
2090
|
|
|
2083
2091
|
# Check if pause is requested
|
|
@@ -2101,7 +2109,7 @@ module Aidp
|
|
|
2101
2109
|
@pause_requested = true
|
|
2102
2110
|
@resume_requested = false
|
|
2103
2111
|
end
|
|
2104
|
-
|
|
2112
|
+
display_message("\n⏸️ Pause requested...", type: :warning)
|
|
2105
2113
|
end
|
|
2106
2114
|
|
|
2107
2115
|
# Request stop
|
|
@@ -2111,7 +2119,7 @@ module Aidp
|
|
|
2111
2119
|
@pause_requested = false
|
|
2112
2120
|
@resume_requested = false
|
|
2113
2121
|
end
|
|
2114
|
-
|
|
2122
|
+
display_message("\n🛑 Stop requested...", type: :error)
|
|
2115
2123
|
end
|
|
2116
2124
|
|
|
2117
2125
|
# Request resume
|
|
@@ -2120,7 +2128,7 @@ module Aidp
|
|
|
2120
2128
|
@resume_requested = true
|
|
2121
2129
|
@pause_requested = false
|
|
2122
2130
|
end
|
|
2123
|
-
|
|
2131
|
+
display_message("\n▶️ Resume requested...", type: :success)
|
|
2124
2132
|
end
|
|
2125
2133
|
|
|
2126
2134
|
# Clear all control requests
|
|
@@ -2155,14 +2163,14 @@ module Aidp
|
|
|
2155
2163
|
|
|
2156
2164
|
# Handle pause state
|
|
2157
2165
|
def handle_pause_state
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
+
display_message("\n⏸️ HARNESS PAUSED", type: :warning)
|
|
2167
|
+
display_message("=" * 50, type: :muted)
|
|
2168
|
+
display_message("🎮 Control Options:", type: :info)
|
|
2169
|
+
display_message(" 'r' + Enter: Resume execution", type: :info)
|
|
2170
|
+
display_message(" 's' + Enter: Stop execution", type: :info)
|
|
2171
|
+
display_message(" 'h' + Enter: Show help", type: :info)
|
|
2172
|
+
display_message(" 'q' + Enter: Quit control interface", type: :info)
|
|
2173
|
+
display_message("=" * 50, type: :muted)
|
|
2166
2174
|
|
|
2167
2175
|
loop do
|
|
2168
2176
|
input = @prompt.ask("Paused>")
|
|
@@ -2180,51 +2188,51 @@ module Aidp
|
|
|
2180
2188
|
stop_control_interface
|
|
2181
2189
|
break
|
|
2182
2190
|
else
|
|
2183
|
-
|
|
2191
|
+
display_message("❌ Invalid command. Type 'h' for help.", type: :error)
|
|
2184
2192
|
end
|
|
2185
2193
|
end
|
|
2186
2194
|
end
|
|
2187
2195
|
|
|
2188
2196
|
# Handle stop state
|
|
2189
2197
|
def handle_stop_state
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2198
|
+
display_message("\n🛑 HARNESS STOPPED", type: :error)
|
|
2199
|
+
display_message("=" * 50, type: :muted)
|
|
2200
|
+
display_message("Execution has been stopped by user request.", type: :info)
|
|
2201
|
+
display_message("You can restart the harness from where it left off.", type: :info)
|
|
2202
|
+
display_message("=" * 50, type: :muted)
|
|
2195
2203
|
end
|
|
2196
2204
|
|
|
2197
2205
|
# Handle resume state
|
|
2198
2206
|
def handle_resume_state
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2207
|
+
display_message("\n▶️ HARNESS RESUMED", type: :success)
|
|
2208
|
+
display_message("=" * 50, type: :muted)
|
|
2209
|
+
display_message("Execution has been resumed.", type: :info)
|
|
2210
|
+
display_message("=" * 50, type: :muted)
|
|
2203
2211
|
end
|
|
2204
2212
|
|
|
2205
2213
|
# Show control help
|
|
2206
2214
|
def show_control_help
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2215
|
+
display_message("\n📖 Control Interface Help", type: :info)
|
|
2216
|
+
display_message("=" * 50, type: :muted)
|
|
2217
|
+
display_message("🎮 Available Commands:", type: :info)
|
|
2218
|
+
display_message(" 'p' or 'pause' - Pause the harness execution", type: :info)
|
|
2219
|
+
display_message(" 'r' or 'resume' - Resume the harness execution", type: :info)
|
|
2220
|
+
display_message(" 's' or 'stop' - Stop the harness execution", type: :info)
|
|
2221
|
+
display_message(" 'h' or 'help' - Show this help message", type: :info)
|
|
2222
|
+
display_message(" 'q' or 'quit' - Quit the control interface", type: :info)
|
|
2223
|
+
display_message("", type: :info)
|
|
2224
|
+
display_message("📋 Control States:", type: :info)
|
|
2225
|
+
display_message(" Running - Harness is executing normally", type: :info)
|
|
2226
|
+
display_message(" Paused - Harness is paused, waiting for resume", type: :info)
|
|
2227
|
+
display_message(" Stopped - Harness has been stopped by user", type: :info)
|
|
2228
|
+
display_message(" Resumed - Harness has been resumed from pause", type: :info)
|
|
2229
|
+
display_message("", type: :info)
|
|
2230
|
+
display_message("💡 Tips:", type: :info)
|
|
2231
|
+
display_message(" • You can pause/resume/stop at any time during execution", type: :info)
|
|
2232
|
+
display_message(" • The harness will save its state when paused/stopped", type: :info)
|
|
2233
|
+
display_message(" • You can restart from where you left off", type: :info)
|
|
2234
|
+
display_message(" • Use 'h' for help at any time", type: :info)
|
|
2235
|
+
display_message("=" * 50, type: :muted)
|
|
2228
2236
|
end
|
|
2229
2237
|
|
|
2230
2238
|
# Control interface main loop
|
|
@@ -2248,15 +2256,15 @@ module Aidp
|
|
|
2248
2256
|
# Empty input, continue
|
|
2249
2257
|
next
|
|
2250
2258
|
else
|
|
2251
|
-
|
|
2259
|
+
display_message("❌ Invalid command. Type 'h' for help.", type: :error)
|
|
2252
2260
|
end
|
|
2253
2261
|
rescue Interrupt
|
|
2254
|
-
|
|
2262
|
+
display_message("\n🛑 Control interface interrupted. Stopping...", type: :error)
|
|
2255
2263
|
request_stop
|
|
2256
2264
|
break
|
|
2257
2265
|
rescue => e
|
|
2258
|
-
|
|
2259
|
-
|
|
2266
|
+
display_message("❌ Control interface error: #{e.message}", type: :error)
|
|
2267
|
+
display_message(" Type 'h' for help or 'q' to quit.", type: :info)
|
|
2260
2268
|
end
|
|
2261
2269
|
end
|
|
2262
2270
|
|
|
@@ -2280,14 +2288,14 @@ module Aidp
|
|
|
2280
2288
|
# Enable control interface
|
|
2281
2289
|
def enable_control_interface
|
|
2282
2290
|
@control_interface_enabled = true
|
|
2283
|
-
|
|
2291
|
+
display_message("🎮 Control interface enabled", type: :success)
|
|
2284
2292
|
end
|
|
2285
2293
|
|
|
2286
2294
|
# Disable control interface
|
|
2287
2295
|
def disable_control_interface
|
|
2288
2296
|
@control_interface_enabled = false
|
|
2289
2297
|
stop_control_interface
|
|
2290
|
-
|
|
2298
|
+
display_message("🎮 Control interface disabled", type: :info)
|
|
2291
2299
|
end
|
|
2292
2300
|
|
|
2293
2301
|
# Get control status
|
|
@@ -2307,29 +2315,29 @@ module Aidp
|
|
|
2307
2315
|
def display_control_status
|
|
2308
2316
|
status = get_control_status
|
|
2309
2317
|
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
+
display_message("\n🎮 Control Interface Status", type: :info)
|
|
2319
|
+
display_message("=" * 40, type: :muted)
|
|
2320
|
+
display_message("Enabled: #{status[:enabled] ? "✅ Yes" : "❌ No"}", type: :info)
|
|
2321
|
+
display_message("Pause Requested: #{status[:pause_requested] ? "⏸️ Yes" : "▶️ No"}", type: :info)
|
|
2322
|
+
display_message("Stop Requested: #{status[:stop_requested] ? "🛑 Yes" : "▶️ No"}", type: :info)
|
|
2323
|
+
display_message("Resume Requested: #{status[:resume_requested] ? "▶️ Yes" : "⏸️ No"}", type: :info)
|
|
2324
|
+
display_message("Control Thread: #{status[:control_thread_alive] ? "🟢 Active" : "🔴 Inactive"}", type: :info)
|
|
2325
|
+
display_message("=" * 40, type: :muted)
|
|
2318
2326
|
end
|
|
2319
2327
|
|
|
2320
2328
|
# Interactive control menu
|
|
2321
2329
|
def show_control_menu
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2330
|
+
display_message("\n🎮 Harness Control Menu", type: :info)
|
|
2331
|
+
display_message("=" * 50, type: :muted)
|
|
2332
|
+
display_message("1. Start Control Interface", type: :info)
|
|
2333
|
+
display_message("2. Stop Control Interface", type: :info)
|
|
2334
|
+
display_message("3. Pause Harness", type: :info)
|
|
2335
|
+
display_message("4. Resume Harness", type: :info)
|
|
2336
|
+
display_message("5. Stop Harness", type: :info)
|
|
2337
|
+
display_message("6. Show Control Status", type: :info)
|
|
2338
|
+
display_message("7. Show Help", type: :info)
|
|
2339
|
+
display_message("8. Exit Menu", type: :info)
|
|
2340
|
+
display_message("=" * 50, type: :muted)
|
|
2333
2341
|
|
|
2334
2342
|
loop do
|
|
2335
2343
|
choice = @prompt.ask("Select option (1-8): ")
|
|
@@ -2350,10 +2358,10 @@ module Aidp
|
|
|
2350
2358
|
when "7"
|
|
2351
2359
|
show_control_help
|
|
2352
2360
|
when "8"
|
|
2353
|
-
|
|
2361
|
+
display_message("👋 Exiting control menu...", type: :info)
|
|
2354
2362
|
break
|
|
2355
2363
|
else
|
|
2356
|
-
|
|
2364
|
+
display_message("❌ Invalid option. Please select 1-8.", type: :error)
|
|
2357
2365
|
end
|
|
2358
2366
|
end
|
|
2359
2367
|
end
|
|
@@ -2361,17 +2369,17 @@ module Aidp
|
|
|
2361
2369
|
# Quick control commands
|
|
2362
2370
|
def quick_pause
|
|
2363
2371
|
request_pause
|
|
2364
|
-
|
|
2372
|
+
display_message("⏸️ Quick pause requested. Use 'r' to resume.", type: :warning)
|
|
2365
2373
|
end
|
|
2366
2374
|
|
|
2367
2375
|
def quick_resume
|
|
2368
2376
|
request_resume
|
|
2369
|
-
|
|
2377
|
+
display_message("▶️ Quick resume requested.", type: :success)
|
|
2370
2378
|
end
|
|
2371
2379
|
|
|
2372
2380
|
def quick_stop
|
|
2373
2381
|
request_stop
|
|
2374
|
-
|
|
2382
|
+
display_message("🛑 Quick stop requested.", type: :error)
|
|
2375
2383
|
end
|
|
2376
2384
|
|
|
2377
2385
|
# Control interface with timeout
|
|
@@ -2390,7 +2398,7 @@ module Aidp
|
|
|
2390
2398
|
handle_resume_state
|
|
2391
2399
|
break
|
|
2392
2400
|
elsif Time.now - start_time > timeout_seconds
|
|
2393
|
-
|
|
2401
|
+
display_message("\n⏰ Control interface timeout reached. Continuing execution...", type: :warning)
|
|
2394
2402
|
break
|
|
2395
2403
|
elsif ENV["RACK_ENV"] == "test" || defined?(RSpec)
|
|
2396
2404
|
sleep(0.1)
|
|
@@ -2402,11 +2410,11 @@ module Aidp
|
|
|
2402
2410
|
|
|
2403
2411
|
# Emergency stop
|
|
2404
2412
|
def emergency_stop
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2413
|
+
display_message("\n🚨 EMERGENCY STOP INITIATED", type: :error)
|
|
2414
|
+
display_message("=" * 50, type: :muted)
|
|
2415
|
+
display_message("All execution will be halted immediately.", type: :error)
|
|
2416
|
+
display_message("This action cannot be undone.", type: :error)
|
|
2417
|
+
display_message("=" * 50, type: :muted)
|
|
2410
2418
|
|
|
2411
2419
|
@control_mutex.synchronize do
|
|
2412
2420
|
@stop_requested = true
|
|
@@ -2415,7 +2423,7 @@ module Aidp
|
|
|
2415
2423
|
end
|
|
2416
2424
|
|
|
2417
2425
|
stop_control_interface
|
|
2418
|
-
|
|
2426
|
+
display_message("🛑 Emergency stop completed.", type: :error)
|
|
2419
2427
|
end
|
|
2420
2428
|
end
|
|
2421
2429
|
end
|