aidp 0.26.0 ā 0.28.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 +89 -0
- data/lib/aidp/cli/checkpoint_command.rb +198 -0
- data/lib/aidp/cli/config_command.rb +71 -0
- data/lib/aidp/cli/enhanced_input.rb +2 -0
- data/lib/aidp/cli/first_run_wizard.rb +8 -7
- data/lib/aidp/cli/harness_command.rb +102 -0
- data/lib/aidp/cli/jobs_command.rb +3 -3
- data/lib/aidp/cli/mcp_dashboard.rb +4 -3
- data/lib/aidp/cli/models_command.rb +661 -0
- data/lib/aidp/cli/providers_command.rb +223 -0
- data/lib/aidp/cli.rb +45 -464
- data/lib/aidp/config.rb +54 -0
- data/lib/aidp/daemon/runner.rb +2 -2
- data/lib/aidp/debug_mixin.rb +25 -10
- data/lib/aidp/execute/agent_signal_parser.rb +22 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
- data/lib/aidp/execute/checkpoint_display.rb +38 -37
- data/lib/aidp/execute/interactive_repl.rb +2 -1
- data/lib/aidp/execute/prompt_manager.rb +4 -4
- data/lib/aidp/execute/repl_macros.rb +2 -2
- data/lib/aidp/execute/steps.rb +94 -1
- data/lib/aidp/execute/work_loop_runner.rb +238 -19
- data/lib/aidp/execute/workflow_selector.rb +4 -27
- data/lib/aidp/firewall/provider_requirements_collector.rb +262 -0
- data/lib/aidp/harness/ai_decision_engine.rb +35 -2
- data/lib/aidp/harness/config_manager.rb +5 -10
- data/lib/aidp/harness/config_schema.rb +8 -0
- data/lib/aidp/harness/configuration.rb +40 -2
- data/lib/aidp/harness/enhanced_runner.rb +25 -19
- data/lib/aidp/harness/error_handler.rb +23 -73
- data/lib/aidp/harness/model_cache.rb +269 -0
- data/lib/aidp/harness/model_discovery_service.rb +259 -0
- data/lib/aidp/harness/model_registry.rb +201 -0
- data/lib/aidp/harness/provider_factory.rb +11 -2
- data/lib/aidp/harness/runner.rb +5 -0
- data/lib/aidp/harness/state_manager.rb +0 -7
- data/lib/aidp/harness/thinking_depth_manager.rb +202 -7
- data/lib/aidp/harness/ui/enhanced_tui.rb +8 -18
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +0 -18
- data/lib/aidp/harness/ui/progress_display.rb +6 -2
- data/lib/aidp/harness/user_interface.rb +0 -58
- data/lib/aidp/init/runner.rb +7 -2
- data/lib/aidp/message_display.rb +0 -46
- data/lib/aidp/planning/analyzers/feedback_analyzer.rb +365 -0
- data/lib/aidp/planning/builders/agile_plan_builder.rb +387 -0
- data/lib/aidp/planning/builders/project_plan_builder.rb +193 -0
- data/lib/aidp/planning/generators/gantt_generator.rb +190 -0
- data/lib/aidp/planning/generators/iteration_plan_generator.rb +392 -0
- data/lib/aidp/planning/generators/legacy_research_planner.rb +473 -0
- data/lib/aidp/planning/generators/marketing_report_generator.rb +348 -0
- data/lib/aidp/planning/generators/mvp_scope_generator.rb +310 -0
- data/lib/aidp/planning/generators/user_test_plan_generator.rb +373 -0
- data/lib/aidp/planning/generators/wbs_generator.rb +259 -0
- data/lib/aidp/planning/mappers/persona_mapper.rb +163 -0
- data/lib/aidp/planning/parsers/document_parser.rb +141 -0
- data/lib/aidp/planning/parsers/feedback_data_parser.rb +252 -0
- data/lib/aidp/provider_manager.rb +8 -32
- data/lib/aidp/providers/adapter.rb +2 -4
- data/lib/aidp/providers/aider.rb +264 -0
- data/lib/aidp/providers/anthropic.rb +206 -121
- data/lib/aidp/providers/base.rb +123 -3
- data/lib/aidp/providers/capability_registry.rb +0 -1
- data/lib/aidp/providers/codex.rb +75 -70
- data/lib/aidp/providers/cursor.rb +87 -59
- data/lib/aidp/providers/gemini.rb +57 -60
- data/lib/aidp/providers/github_copilot.rb +19 -66
- data/lib/aidp/providers/kilocode.rb +35 -80
- data/lib/aidp/providers/opencode.rb +35 -80
- data/lib/aidp/setup/wizard.rb +555 -8
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +211 -30
- data/lib/aidp/watch/change_request_processor.rb +128 -14
- data/lib/aidp/watch/ci_fix_processor.rb +103 -37
- data/lib/aidp/watch/ci_log_extractor.rb +258 -0
- data/lib/aidp/watch/github_state_extractor.rb +177 -0
- data/lib/aidp/watch/implementation_verifier.rb +284 -0
- data/lib/aidp/watch/plan_generator.rb +95 -52
- data/lib/aidp/watch/plan_processor.rb +7 -6
- data/lib/aidp/watch/repository_client.rb +245 -17
- data/lib/aidp/watch/review_processor.rb +100 -19
- data/lib/aidp/watch/reviewers/base_reviewer.rb +1 -1
- data/lib/aidp/watch/runner.rb +181 -29
- data/lib/aidp/watch/state_store.rb +22 -1
- data/lib/aidp/workflows/definitions.rb +147 -0
- data/lib/aidp/workflows/guided_agent.rb +3 -3
- data/lib/aidp/workstream_cleanup.rb +245 -0
- data/lib/aidp/worktree.rb +19 -0
- data/templates/aidp-development.yml.example +2 -2
- data/templates/aidp-production.yml.example +3 -3
- data/templates/aidp.yml.example +57 -0
- data/templates/implementation/generate_tdd_specs.md +213 -0
- data/templates/implementation/iterative_implementation.md +122 -0
- data/templates/planning/agile/analyze_feedback.md +183 -0
- data/templates/planning/agile/generate_iteration_plan.md +179 -0
- data/templates/planning/agile/generate_legacy_research_plan.md +171 -0
- data/templates/planning/agile/generate_marketing_report.md +162 -0
- data/templates/planning/agile/generate_mvp_scope.md +127 -0
- data/templates/planning/agile/generate_user_test_plan.md +143 -0
- data/templates/planning/agile/ingest_feedback.md +174 -0
- data/templates/planning/assemble_project_plan.md +113 -0
- data/templates/planning/assign_personas.md +108 -0
- data/templates/planning/create_tasks.md +52 -6
- data/templates/planning/generate_gantt.md +86 -0
- data/templates/planning/generate_wbs.md +85 -0
- data/templates/planning/initialize_planning_mode.md +70 -0
- data/templates/skills/README.md +2 -2
- data/templates/skills/marketing_strategist/SKILL.md +279 -0
- data/templates/skills/product_manager/SKILL.md +177 -0
- data/templates/skills/ruby_aidp_planning/SKILL.md +497 -0
- data/templates/skills/ruby_rspec_tdd/SKILL.md +514 -0
- data/templates/skills/ux_researcher/SKILL.md +222 -0
- metadata +47 -1
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "capability_registry"
|
|
4
4
|
require_relative "configuration"
|
|
5
|
+
require_relative "../message_display"
|
|
5
6
|
|
|
6
7
|
module Aidp
|
|
7
8
|
module Harness
|
|
8
9
|
# Manages thinking depth tier selection and escalation
|
|
9
10
|
# Integrates with CapabilityRegistry and Configuration to select appropriate models
|
|
10
11
|
class ThinkingDepthManager
|
|
12
|
+
include Aidp::MessageDisplay
|
|
13
|
+
|
|
11
14
|
attr_reader :configuration, :registry
|
|
12
15
|
|
|
13
16
|
def initialize(configuration, registry: nil, root_dir: nil)
|
|
@@ -150,11 +153,40 @@ module Aidp
|
|
|
150
153
|
tier ||= current_tier
|
|
151
154
|
validate_tier!(tier)
|
|
152
155
|
|
|
153
|
-
#
|
|
156
|
+
# First, try to get models from user's configuration for this tier and provider
|
|
157
|
+
if provider
|
|
158
|
+
configured_models = configuration.models_for_tier(tier, provider)
|
|
159
|
+
|
|
160
|
+
if configured_models.any?
|
|
161
|
+
# Use first configured model for this provider and tier
|
|
162
|
+
model_name = configured_models.first
|
|
163
|
+
Aidp.log_debug("thinking_depth_manager", "Selected model from user config",
|
|
164
|
+
tier: tier,
|
|
165
|
+
provider: provider,
|
|
166
|
+
model: model_name)
|
|
167
|
+
return [provider, model_name, {}]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Provider specified but has no models for this tier in config
|
|
171
|
+
# Try catalog for the specified provider before switching providers
|
|
172
|
+
Aidp.log_debug("thinking_depth_manager", "Provider has no configured models for tier, trying catalog",
|
|
173
|
+
tier: tier,
|
|
174
|
+
provider: provider)
|
|
175
|
+
|
|
176
|
+
# Continue to catalog-based selection below (will try specified provider first)
|
|
177
|
+
else
|
|
178
|
+
# No provider specified - this should not happen in normal flow
|
|
179
|
+
# Log warning and fall through to catalog-based selection
|
|
180
|
+
Aidp.log_warn("thinking_depth_manager", "select_model_for_tier called without provider",
|
|
181
|
+
tier: tier)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Fall back to catalog-based selection if no models in user config
|
|
185
|
+
# If provider specified, try to find model for that provider in catalog
|
|
154
186
|
if provider
|
|
155
187
|
model_name, model_data = @registry.best_model_for_tier(tier, provider)
|
|
156
188
|
if model_name
|
|
157
|
-
Aidp.log_debug("thinking_depth_manager", "Selected model",
|
|
189
|
+
Aidp.log_debug("thinking_depth_manager", "Selected model from catalog",
|
|
158
190
|
tier: tier,
|
|
159
191
|
provider: provider,
|
|
160
192
|
model: model_name)
|
|
@@ -163,20 +195,24 @@ module Aidp
|
|
|
163
195
|
|
|
164
196
|
# If provider doesn't support tier and switching allowed, try others
|
|
165
197
|
unless configuration.allow_provider_switch_for_tier?
|
|
166
|
-
Aidp.log_warn("thinking_depth_manager", "Provider lacks tier, switching disabled",
|
|
198
|
+
Aidp.log_warn("thinking_depth_manager", "Provider lacks tier in catalog, switching disabled",
|
|
167
199
|
tier: tier,
|
|
168
200
|
provider: provider)
|
|
169
201
|
return nil
|
|
170
202
|
end
|
|
171
203
|
end
|
|
172
204
|
|
|
173
|
-
# Try all providers
|
|
205
|
+
# Try all providers in catalog
|
|
206
|
+
if provider && !configuration.allow_provider_switch_for_tier?
|
|
207
|
+
return nil
|
|
208
|
+
end
|
|
209
|
+
|
|
174
210
|
providers_to_try = provider ? [@registry.provider_names - [provider]].flatten : @registry.provider_names
|
|
175
211
|
|
|
176
212
|
providers_to_try.each do |prov_name|
|
|
177
213
|
model_name, model_data = @registry.best_model_for_tier(tier, prov_name)
|
|
178
214
|
if model_name
|
|
179
|
-
Aidp.log_info("thinking_depth_manager", "Selected model from alternate provider",
|
|
215
|
+
Aidp.log_info("thinking_depth_manager", "Selected model from catalog (alternate provider)",
|
|
180
216
|
tier: tier,
|
|
181
217
|
original_provider: provider,
|
|
182
218
|
selected_provider: prov_name,
|
|
@@ -185,10 +221,23 @@ module Aidp
|
|
|
185
221
|
end
|
|
186
222
|
end
|
|
187
223
|
|
|
188
|
-
|
|
224
|
+
# No model found for requested tier - try fallback to other tiers
|
|
225
|
+
Aidp.log_warn("thinking_depth_manager", "No model found for requested tier, trying fallback",
|
|
189
226
|
tier: tier,
|
|
190
227
|
provider: provider)
|
|
191
|
-
|
|
228
|
+
|
|
229
|
+
result = try_fallback_tiers(tier, provider)
|
|
230
|
+
|
|
231
|
+
unless result
|
|
232
|
+
# Enhanced error message with discovery hints
|
|
233
|
+
display_enhanced_tier_error(tier, provider)
|
|
234
|
+
|
|
235
|
+
Aidp.log_error("thinking_depth_manager", "No model found for tier or fallback tiers",
|
|
236
|
+
tier: tier,
|
|
237
|
+
provider: provider)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
result
|
|
192
241
|
end
|
|
193
242
|
|
|
194
243
|
# Get tier for a specific model
|
|
@@ -330,6 +379,152 @@ module Aidp
|
|
|
330
379
|
# Keep history bounded
|
|
331
380
|
@tier_history.shift if @tier_history.size > 100
|
|
332
381
|
end
|
|
382
|
+
|
|
383
|
+
# Try to find a model in fallback tiers when requested tier has no models
|
|
384
|
+
# Tries lower tiers first (cheaper), then higher tiers
|
|
385
|
+
# Returns [provider_name, model_name, model_data] or nil
|
|
386
|
+
def try_fallback_tiers(requested_tier, provider)
|
|
387
|
+
# Generate fallback order: try lower tiers first, then higher
|
|
388
|
+
fallback_tiers = generate_fallback_tier_order(requested_tier)
|
|
389
|
+
|
|
390
|
+
fallback_tiers.each do |fallback_tier|
|
|
391
|
+
# First, try user's configuration for this fallback tier and provider
|
|
392
|
+
if provider
|
|
393
|
+
configured_models = configuration.models_for_tier(fallback_tier, provider)
|
|
394
|
+
|
|
395
|
+
if configured_models.any?
|
|
396
|
+
model_name = configured_models.first
|
|
397
|
+
Aidp.log_warn("thinking_depth_manager", "Falling back to different tier (from config)",
|
|
398
|
+
requested_tier: requested_tier,
|
|
399
|
+
fallback_tier: fallback_tier,
|
|
400
|
+
provider: provider,
|
|
401
|
+
model: model_name)
|
|
402
|
+
return [provider, model_name, {}]
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Fall back to catalog if no models in config for the provider
|
|
407
|
+
# Try specified provider first if given
|
|
408
|
+
if provider
|
|
409
|
+
model_name, model_data = @registry.best_model_for_tier(fallback_tier, provider)
|
|
410
|
+
if model_name
|
|
411
|
+
Aidp.log_warn("thinking_depth_manager", "Falling back to different tier (from catalog)",
|
|
412
|
+
requested_tier: requested_tier,
|
|
413
|
+
fallback_tier: fallback_tier,
|
|
414
|
+
provider: provider,
|
|
415
|
+
model: model_name)
|
|
416
|
+
return [provider, model_name, model_data]
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# Try all available providers in catalog if switching allowed
|
|
421
|
+
if configuration.allow_provider_switch_for_tier?
|
|
422
|
+
@registry.provider_names.each do |prov_name|
|
|
423
|
+
next if prov_name == provider # Skip if already tried above
|
|
424
|
+
|
|
425
|
+
model_name, model_data = @registry.best_model_for_tier(fallback_tier, prov_name)
|
|
426
|
+
if model_name
|
|
427
|
+
Aidp.log_warn("thinking_depth_manager", "Falling back to different tier and provider (from catalog)",
|
|
428
|
+
requested_tier: requested_tier,
|
|
429
|
+
fallback_tier: fallback_tier,
|
|
430
|
+
requested_provider: provider,
|
|
431
|
+
fallback_provider: prov_name,
|
|
432
|
+
model: model_name)
|
|
433
|
+
return [prov_name, model_name, model_data]
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
nil
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
# Generate fallback tier order: lower tiers first (cheaper), then higher
|
|
443
|
+
# For example, if tier is "standard", try: mini, thinking, pro, max
|
|
444
|
+
def generate_fallback_tier_order(tier)
|
|
445
|
+
current_priority = @registry.tier_priority(tier) || 1
|
|
446
|
+
all_tiers = CapabilityRegistry::VALID_TIERS
|
|
447
|
+
|
|
448
|
+
# Split into lower and higher tiers
|
|
449
|
+
lower_tiers = all_tiers.select { |t| (@registry.tier_priority(t) || 0) < current_priority }.reverse
|
|
450
|
+
higher_tiers = all_tiers.select { |t| (@registry.tier_priority(t) || 0) > current_priority }
|
|
451
|
+
|
|
452
|
+
# Try lower tiers first (cost optimization), then higher tiers
|
|
453
|
+
lower_tiers + higher_tiers
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# Display enhanced error message with discovery hints
|
|
457
|
+
def display_enhanced_tier_error(tier, provider)
|
|
458
|
+
return unless defined?(Aidp::MessageDisplay)
|
|
459
|
+
|
|
460
|
+
# Check if there are discovered models in cache
|
|
461
|
+
discovered_models = check_discovered_models(tier, provider)
|
|
462
|
+
|
|
463
|
+
if discovered_models&.any?
|
|
464
|
+
display_tier_error_with_suggestions(tier, provider, discovered_models)
|
|
465
|
+
else
|
|
466
|
+
display_tier_error_with_discovery_hint(tier, provider)
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Check cache for discovered models for this tier
|
|
471
|
+
def check_discovered_models(tier, provider)
|
|
472
|
+
require_relative "model_cache"
|
|
473
|
+
require_relative "model_registry"
|
|
474
|
+
|
|
475
|
+
cache = Aidp::Harness::ModelCache.new
|
|
476
|
+
registry = Aidp::Harness::ModelRegistry.new
|
|
477
|
+
|
|
478
|
+
# Get all cached models for the provider
|
|
479
|
+
cached_models = cache.get_cached_models(provider)
|
|
480
|
+
return nil unless cached_models&.any?
|
|
481
|
+
|
|
482
|
+
# Filter to models for the requested tier
|
|
483
|
+
tier_models = cached_models.select do |model|
|
|
484
|
+
family = model[:family] || model["family"]
|
|
485
|
+
model_info = registry.get_model_info(family)
|
|
486
|
+
model_info && model_info["tier"] == tier.to_s
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
tier_models.any? ? tier_models : nil
|
|
490
|
+
rescue => e
|
|
491
|
+
Aidp.log_debug("thinking_depth_manager", "failed to check cached models",
|
|
492
|
+
error: e.message)
|
|
493
|
+
nil
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
# Display error with model suggestions from cache
|
|
497
|
+
def display_tier_error_with_suggestions(tier, provider, models)
|
|
498
|
+
display_message("\nā No model configured for '#{tier}' tier", type: :error)
|
|
499
|
+
display_message(" Provider: #{provider}", type: :info) if provider
|
|
500
|
+
|
|
501
|
+
display_message("\nš” Discovered models for this tier:", type: :highlight)
|
|
502
|
+
models.first(3).each do |model|
|
|
503
|
+
model_name = model[:name] || model["name"]
|
|
504
|
+
display_message(" - #{model_name}", type: :info)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
display_message("\n Add to aidp.yml:", type: :highlight)
|
|
508
|
+
display_message(" providers:", type: :info)
|
|
509
|
+
display_message(" #{provider}:", type: :info)
|
|
510
|
+
display_message(" thinking:", type: :info)
|
|
511
|
+
display_message(" tiers:", type: :info)
|
|
512
|
+
display_message(" #{tier}:", type: :info)
|
|
513
|
+
display_message(" models:", type: :info)
|
|
514
|
+
first_model = models.first[:name] || models.first["name"]
|
|
515
|
+
display_message(" - model: #{first_model}\n", type: :info)
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# Display error with discovery hint
|
|
519
|
+
def display_tier_error_with_discovery_hint(tier, provider)
|
|
520
|
+
display_message("\nā No model configured for '#{tier}' tier", type: :error)
|
|
521
|
+
display_message(" Provider: #{provider}", type: :info) if provider
|
|
522
|
+
|
|
523
|
+
display_message("\nš” Suggested actions:", type: :highlight)
|
|
524
|
+
display_message(" 1. Run 'aidp models discover' to find available models", type: :info)
|
|
525
|
+
display_message(" 2. Run 'aidp models list --tier=#{tier}' to see models for this tier", type: :info)
|
|
526
|
+
display_message(" 3. Run 'aidp models validate' to check your configuration\n", type: :info)
|
|
527
|
+
end
|
|
333
528
|
end
|
|
334
529
|
end
|
|
335
530
|
end
|
|
@@ -43,16 +43,6 @@ module Aidp
|
|
|
43
43
|
setup_signal_handlers
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
# Simple display initialization - no background threads
|
|
47
|
-
def start_display_loop
|
|
48
|
-
# Display loop is now just a no-op for compatibility
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def stop_display_loop
|
|
52
|
-
# Simple cleanup - no background threads to stop
|
|
53
|
-
restore_screen
|
|
54
|
-
end
|
|
55
|
-
|
|
56
46
|
# Input methods using TTY::Prompt only - no background threads
|
|
57
47
|
def get_user_input(prompt = "š¬ You: ")
|
|
58
48
|
@prompt.ask(prompt)
|
|
@@ -258,6 +248,12 @@ module Aidp
|
|
|
258
248
|
@prompt.say("š #{message}", color: :cyan)
|
|
259
249
|
end
|
|
260
250
|
|
|
251
|
+
def restore_screen
|
|
252
|
+
@cursor.show
|
|
253
|
+
@cursor.clear_screen
|
|
254
|
+
@cursor.move_to(1, 1)
|
|
255
|
+
end
|
|
256
|
+
|
|
261
257
|
private
|
|
262
258
|
|
|
263
259
|
def extract_questions_for_step(step_name)
|
|
@@ -284,20 +280,14 @@ module Aidp
|
|
|
284
280
|
[]
|
|
285
281
|
end
|
|
286
282
|
|
|
287
|
-
def restore_screen
|
|
288
|
-
@cursor.show
|
|
289
|
-
@cursor.clear_screen
|
|
290
|
-
@cursor.move_to(1, 1)
|
|
291
|
-
end
|
|
292
|
-
|
|
293
283
|
def setup_signal_handlers
|
|
294
284
|
Signal.trap("INT") do
|
|
295
|
-
|
|
285
|
+
restore_screen
|
|
296
286
|
exit(1)
|
|
297
287
|
end
|
|
298
288
|
|
|
299
289
|
Signal.trap("TERM") do
|
|
300
|
-
|
|
290
|
+
restore_screen
|
|
301
291
|
exit(0)
|
|
302
292
|
end
|
|
303
293
|
end
|
|
@@ -86,24 +86,6 @@ module Aidp
|
|
|
86
86
|
}
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
-
# Legacy method - kept for backward compatibility if needed
|
|
90
|
-
def select_execute_workflow_interactive
|
|
91
|
-
# Step 1: Collect project information
|
|
92
|
-
collect_project_info_interactive
|
|
93
|
-
|
|
94
|
-
# Step 2: Choose workflow type
|
|
95
|
-
workflow_type = choose_workflow_type_interactive
|
|
96
|
-
|
|
97
|
-
# Step 3: Generate workflow steps
|
|
98
|
-
steps = generate_workflow_steps_interactive(workflow_type)
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
workflow_type: workflow_type,
|
|
102
|
-
steps: steps,
|
|
103
|
-
user_input: @user_input
|
|
104
|
-
}
|
|
105
|
-
end
|
|
106
|
-
|
|
107
89
|
def select_analyze_workflow_defaults
|
|
108
90
|
@tui.show_message("š Starting analyze mode with default configuration...", :info)
|
|
109
91
|
|
|
@@ -22,14 +22,18 @@ module Aidp
|
|
|
22
22
|
|
|
23
23
|
def initialize(ui_components = {})
|
|
24
24
|
super()
|
|
25
|
+
@output = ui_components[:output]
|
|
25
26
|
@progress = ui_components[:progress] || TTY::ProgressBar
|
|
26
|
-
@pastel =
|
|
27
|
+
@pastel = if @output&.respond_to?(:tty?) && @output.tty?
|
|
28
|
+
Pastel.new(enabled: true)
|
|
29
|
+
else
|
|
30
|
+
Pastel.new(enabled: false)
|
|
31
|
+
end
|
|
27
32
|
@formatter = ui_components[:formatter] || ProgressFormatter.new
|
|
28
33
|
@display_history = []
|
|
29
34
|
@auto_refresh_enabled = false
|
|
30
35
|
@refresh_interval = 1.0
|
|
31
36
|
@refresh_thread = nil
|
|
32
|
-
@output = ui_components[:output]
|
|
33
37
|
@prompt = ui_components[:prompt] || TTY::Prompt.new
|
|
34
38
|
@spinner_class = begin
|
|
35
39
|
ui_components[:spinner] || TTY::Spinner
|
|
@@ -425,48 +425,6 @@ module Aidp
|
|
|
425
425
|
display_message("\nš Continuing execution...", type: :success)
|
|
426
426
|
end
|
|
427
427
|
|
|
428
|
-
# Display question information (legacy method for compatibility)
|
|
429
|
-
def display_question_info(question_type, expected_input, options, default_value, required)
|
|
430
|
-
info_parts = []
|
|
431
|
-
|
|
432
|
-
# Question type
|
|
433
|
-
type_emojis = {
|
|
434
|
-
"text" => "š",
|
|
435
|
-
"choice" => "š",
|
|
436
|
-
"confirmation" => "ā
",
|
|
437
|
-
"file" => "š",
|
|
438
|
-
"number" => "š¢",
|
|
439
|
-
"email" => "š§",
|
|
440
|
-
"url" => "š"
|
|
441
|
-
}
|
|
442
|
-
type_emoji = type_emojis[question_type] || "ā"
|
|
443
|
-
info_parts << "#{type_emoji} #{question_type.capitalize}"
|
|
444
|
-
|
|
445
|
-
# Expected input type
|
|
446
|
-
if expected_input != "text"
|
|
447
|
-
info_parts << "Expected: #{expected_input}"
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
# Options
|
|
451
|
-
if options && !options.empty?
|
|
452
|
-
info_parts << "Options: #{options.join(", ")}"
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
# Default value
|
|
456
|
-
if default_value
|
|
457
|
-
info_parts << "Default: #{default_value}"
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
# Required status
|
|
461
|
-
info_parts << if required
|
|
462
|
-
"Required: Yes"
|
|
463
|
-
else
|
|
464
|
-
"Required: No"
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
display_message(" #{info_parts.join(" | ")}", type: :info)
|
|
468
|
-
end
|
|
469
|
-
|
|
470
428
|
# Get response for a specific question with enhanced validation
|
|
471
429
|
def question_response(question_data, _question_number)
|
|
472
430
|
question_type = question_data[:type] || "text"
|
|
@@ -1576,12 +1534,6 @@ module Aidp
|
|
|
1576
1534
|
end
|
|
1577
1535
|
end
|
|
1578
1536
|
|
|
1579
|
-
# Find files matching search term (legacy method for compatibility)
|
|
1580
|
-
def find_files(search_term)
|
|
1581
|
-
search_options = parse_file_search_options(search_term)
|
|
1582
|
-
find_files_advanced(search_options)
|
|
1583
|
-
end
|
|
1584
|
-
|
|
1585
1537
|
# Display advanced file selection menu
|
|
1586
1538
|
def display_advanced_file_menu(files, search_options)
|
|
1587
1539
|
display_message("\nš Available files:", type: :info)
|
|
@@ -1659,11 +1611,6 @@ module Aidp
|
|
|
1659
1611
|
end
|
|
1660
1612
|
end
|
|
1661
1613
|
|
|
1662
|
-
# Display file selection menu (legacy method for compatibility)
|
|
1663
|
-
def display_file_menu(files)
|
|
1664
|
-
display_advanced_file_menu(files, {term: "", extensions: [], directories: []})
|
|
1665
|
-
end
|
|
1666
|
-
|
|
1667
1614
|
# Get advanced file selection from user
|
|
1668
1615
|
def advanced_file_selection(max_files, _search_options)
|
|
1669
1616
|
loop do
|
|
@@ -1763,11 +1710,6 @@ module Aidp
|
|
|
1763
1710
|
@prompt.keypress("Press any key to continue...")
|
|
1764
1711
|
end
|
|
1765
1712
|
|
|
1766
|
-
# Get file selection from user (legacy method for compatibility)
|
|
1767
|
-
def file_selection(max_files)
|
|
1768
|
-
advanced_file_selection(max_files, {term: "", extensions: [], directories: []})
|
|
1769
|
-
end
|
|
1770
|
-
|
|
1771
1713
|
# Get confirmation from user
|
|
1772
1714
|
def confirmation(message, default: true)
|
|
1773
1715
|
default_text = default ? "Y/n" : "y/N"
|
data/lib/aidp/init/runner.rb
CHANGED
|
@@ -337,8 +337,13 @@ module Aidp
|
|
|
337
337
|
next unless tool_command
|
|
338
338
|
|
|
339
339
|
# Check if command exists
|
|
340
|
-
|
|
341
|
-
|
|
340
|
+
begin
|
|
341
|
+
unless system("which #{tool_command} > /dev/null 2>&1")
|
|
342
|
+
warnings << " ā ļø #{format_tool(tool_data[:tool])} detected but command '#{tool_command}' not found in PATH"
|
|
343
|
+
end
|
|
344
|
+
rescue IOError
|
|
345
|
+
# Streams may be closed in test environment - skip validation
|
|
346
|
+
Aidp.log_debug("init_runner", "skipping_tool_validation", tool: tool_command, reason: "closed_stream")
|
|
342
347
|
end
|
|
343
348
|
end
|
|
344
349
|
|
data/lib/aidp/message_display.rb
CHANGED
|
@@ -25,7 +25,6 @@ module Aidp
|
|
|
25
25
|
|
|
26
26
|
# Instance helper for displaying a colored message via TTY::Prompt
|
|
27
27
|
def display_message(message, type: :info)
|
|
28
|
-
return if suppress_display_message?(message)
|
|
29
28
|
# Ensure message is UTF-8 encoded to handle emoji and special characters
|
|
30
29
|
message_str = message.to_s
|
|
31
30
|
message_str = message_str.force_encoding("UTF-8") if message_str.encoding.name == "ASCII-8BIT"
|
|
@@ -43,32 +42,9 @@ module Aidp
|
|
|
43
42
|
end
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
# Check if specific display message should be suppressed in test/CI environments
|
|
47
|
-
def suppress_display_message?(message)
|
|
48
|
-
return false unless in_test_environment?
|
|
49
|
-
|
|
50
|
-
message_str = message.to_s
|
|
51
|
-
# Only suppress specific automated status messages, not CLI output
|
|
52
|
-
message_str.include?("š Provider switch:") ||
|
|
53
|
-
message_str.include?("š Model switch:") ||
|
|
54
|
-
message_str.include?("š“ Circuit breaker opened") ||
|
|
55
|
-
message_str.include?("š¢ Circuit breaker reset") ||
|
|
56
|
-
message_str.include?("ā No providers available") ||
|
|
57
|
-
message_str.include?("ā No models available") ||
|
|
58
|
-
message_str.include?("š Execution Summary") ||
|
|
59
|
-
message_str.include?("ā¶ļø [") || # Workstream execution messages
|
|
60
|
-
message_str.include?("ā
[") || # Workstream success messages
|
|
61
|
-
message_str.include?("ā [") # Workstream failure messages
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def in_test_environment?
|
|
65
|
-
ENV["RSPEC_RUNNING"] || ENV["CI"] || ENV["RAILS_ENV"] == "test" || ENV["RACK_ENV"] == "test"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
45
|
module ClassMethods
|
|
69
46
|
# Class-level display helper (uses fresh prompt to respect $stdout changes)
|
|
70
47
|
def display_message(message, type: :info)
|
|
71
|
-
return if suppress_display_message?(message)
|
|
72
48
|
# Ensure message is UTF-8 encoded to handle emoji and special characters
|
|
73
49
|
message_str = message.to_s
|
|
74
50
|
message_str = message_str.force_encoding("UTF-8") if message_str.encoding.name == "ASCII-8BIT"
|
|
@@ -78,28 +54,6 @@ module Aidp
|
|
|
78
54
|
|
|
79
55
|
private
|
|
80
56
|
|
|
81
|
-
# Check if specific display message should be suppressed in test/CI environments
|
|
82
|
-
def suppress_display_message?(message)
|
|
83
|
-
return false unless in_test_environment?
|
|
84
|
-
|
|
85
|
-
message_str = message.to_s
|
|
86
|
-
# Only suppress specific automated status messages, not CLI output
|
|
87
|
-
message_str.include?("š Provider switch:") ||
|
|
88
|
-
message_str.include?("š Model switch:") ||
|
|
89
|
-
message_str.include?("š“ Circuit breaker opened") ||
|
|
90
|
-
message_str.include?("š¢ Circuit breaker reset") ||
|
|
91
|
-
message_str.include?("ā No providers available") ||
|
|
92
|
-
message_str.include?("ā No models available") ||
|
|
93
|
-
message_str.include?("š Execution Summary") ||
|
|
94
|
-
message_str.include?("ā¶ļø [") || # Workstream execution messages
|
|
95
|
-
message_str.include?("ā
[") || # Workstream success messages
|
|
96
|
-
message_str.include?("ā [") # Workstream failure messages
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def in_test_environment?
|
|
100
|
-
ENV["RSPEC_RUNNING"] || ENV["CI"] || ENV["RAILS_ENV"] == "test" || ENV["RACK_ENV"] == "test"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
57
|
# Don't memoize - create fresh prompt each time to respect $stdout redirection in tests
|
|
104
58
|
def class_message_display_prompt
|
|
105
59
|
TTY::Prompt.new
|