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,14 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "tty-prompt"
|
|
4
|
+
require "tty-cursor"
|
|
5
|
+
|
|
3
6
|
module Aidp
|
|
4
7
|
module Harness
|
|
5
8
|
# Real-time status updates and monitoring interface
|
|
6
9
|
class StatusDisplay
|
|
7
|
-
|
|
10
|
+
include Aidp::MessageDisplay
|
|
11
|
+
|
|
12
|
+
def initialize(provider_manager = nil, metrics_manager = nil, circuit_breaker_manager = nil, error_logger = nil, prompt: TTY::Prompt.new)
|
|
8
13
|
@provider_manager = provider_manager
|
|
9
14
|
@metrics_manager = metrics_manager
|
|
10
15
|
@circuit_breaker_manager = circuit_breaker_manager
|
|
11
16
|
@error_logger = error_logger
|
|
17
|
+
@prompt = prompt
|
|
18
|
+
@cursor = TTY::Cursor
|
|
12
19
|
|
|
13
20
|
@start_time = nil
|
|
14
21
|
@current_step = nil
|
|
@@ -177,61 +184,61 @@ module Aidp
|
|
|
177
184
|
# Show paused status
|
|
178
185
|
def show_paused_status
|
|
179
186
|
clear_display
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
display_message("\n⏸️ Harness PAUSED", type: :warning)
|
|
188
|
+
display_message(" Press 'r' to resume, 's' to stop", type: :info)
|
|
189
|
+
display_message(" Current step: #{@current_step}", type: :info) if @current_step
|
|
190
|
+
display_message(" Current provider: #{@current_provider}", type: :info) if @current_provider
|
|
191
|
+
display_message(" Current model: #{@current_model}", type: :info) if @current_model
|
|
192
|
+
display_message(" Duration: #{format_duration(Time.now - @start_time)}", type: :info) if @start_time
|
|
186
193
|
end
|
|
187
194
|
|
|
188
195
|
# Show resumed status
|
|
189
196
|
def show_resumed_status
|
|
190
197
|
clear_display
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
display_message("\n▶️ Harness RESUMED", type: :success)
|
|
199
|
+
display_message(" Continuing execution...", type: :info)
|
|
193
200
|
end
|
|
194
201
|
|
|
195
202
|
# Show stopped status
|
|
196
203
|
def show_stopped_status
|
|
197
204
|
clear_display
|
|
198
|
-
|
|
199
|
-
|
|
205
|
+
display_message("\n⏹️ Harness STOPPED", type: :error)
|
|
206
|
+
display_message(" Execution terminated by user", type: :info)
|
|
200
207
|
end
|
|
201
208
|
|
|
202
209
|
# Show rate limit wait
|
|
203
210
|
def show_rate_limit_wait(reset_time)
|
|
204
211
|
clear_display
|
|
205
212
|
remaining = reset_time - Time.now
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
display_message("\n🚫 Rate limit reached", type: :error)
|
|
214
|
+
display_message(" Waiting for reset at #{reset_time.strftime("%H:%M:%S")}", type: :info)
|
|
215
|
+
display_message(" Remaining: #{format_duration(remaining)}", type: :info)
|
|
216
|
+
display_message(" Press Ctrl+C to cancel", type: :info)
|
|
210
217
|
end
|
|
211
218
|
|
|
212
219
|
# Update rate limit countdown
|
|
213
220
|
def update_rate_limit_countdown(remaining_seconds)
|
|
214
221
|
clear_display
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
222
|
+
display_message("\n🚫 Rate limit - waiting...", type: :warning)
|
|
223
|
+
display_message(" Resets in: #{format_duration(remaining_seconds)}", type: :info)
|
|
224
|
+
display_message(" Press Ctrl+C to cancel", type: :info)
|
|
218
225
|
end
|
|
219
226
|
|
|
220
227
|
# Show completion status
|
|
221
228
|
def show_completion_status(duration, steps_completed, total_steps)
|
|
222
229
|
clear_display
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
230
|
+
display_message("\n✅ Harness COMPLETED", type: :success)
|
|
231
|
+
display_message(" Duration: #{format_duration(duration)}", type: :info)
|
|
232
|
+
display_message(" Steps completed: #{steps_completed}/#{total_steps}", type: :info)
|
|
233
|
+
display_message(" All workflows finished successfully!", type: :success)
|
|
227
234
|
end
|
|
228
235
|
|
|
229
236
|
# Show error status
|
|
230
237
|
def show_error_status(error_message)
|
|
231
238
|
clear_display
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
display_message("\n❌ Harness ERROR", type: :error)
|
|
240
|
+
display_message(" Error: #{error_message}", type: :error)
|
|
241
|
+
display_message(" Check logs for details", type: :info)
|
|
235
242
|
end
|
|
236
243
|
|
|
237
244
|
# Cleanup display
|
|
@@ -368,47 +375,47 @@ module Aidp
|
|
|
368
375
|
def display_compact_status
|
|
369
376
|
duration = @start_time ? Time.now - @start_time : 0
|
|
370
377
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
378
|
+
display_message("\n🔄 Harness Status", type: :info)
|
|
379
|
+
display_message(" Duration: #{format_duration(duration)}", type: :info)
|
|
380
|
+
display_message(" Step: #{@current_step || "Starting..."}", type: :info)
|
|
381
|
+
display_message(" Provider: #{@current_provider || "Initializing..."}", type: :info)
|
|
382
|
+
display_message(" Model: #{@current_model || "N/A"}", type: :info)
|
|
383
|
+
display_message(" Status: Running", type: :info)
|
|
377
384
|
|
|
378
385
|
# Show key metrics
|
|
379
386
|
if @performance_metrics[:error_rate] && @performance_metrics[:error_rate] > 0
|
|
380
|
-
|
|
387
|
+
display_message(" Error Rate: #{format_percentage(@performance_metrics[:error_rate])}", type: :warning)
|
|
381
388
|
end
|
|
382
389
|
|
|
383
390
|
if @token_usage[@current_provider] && @token_usage[@current_provider][@current_model]
|
|
384
391
|
tokens = @token_usage[@current_provider][@current_model]
|
|
385
|
-
|
|
386
|
-
|
|
392
|
+
display_message(" Tokens: #{tokens[:used]} used", type: :info)
|
|
393
|
+
display_message(" Remaining: #{tokens[:remaining]}", type: :info) if tokens[:remaining]
|
|
387
394
|
end
|
|
388
395
|
|
|
389
|
-
|
|
396
|
+
display_message(" Press Ctrl+C to stop", type: :info)
|
|
390
397
|
end
|
|
391
398
|
|
|
392
399
|
def display_detailed_status
|
|
393
400
|
duration = @start_time ? Time.now - @start_time : 0
|
|
394
401
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
402
|
+
display_message("\n🔄 Harness Status - Detailed", type: :info)
|
|
403
|
+
display_message(" Duration: #{format_duration(duration)}", type: :info)
|
|
404
|
+
display_message(" Current Step: #{@current_step || "Starting..."}", type: :info)
|
|
405
|
+
display_message(" Provider: #{@current_provider || "Initializing..."}", type: :info)
|
|
406
|
+
display_message(" Model: #{@current_model || "N/A"}", type: :info)
|
|
407
|
+
display_message(" Status: Running", type: :info)
|
|
401
408
|
|
|
402
409
|
# Provider information
|
|
403
410
|
if @provider_status[:available_providers]
|
|
404
|
-
|
|
411
|
+
display_message(" Available Providers: #{@provider_status[:available_providers].join(", ")}", type: :info)
|
|
405
412
|
end
|
|
406
413
|
|
|
407
414
|
# Circuit breaker status
|
|
408
415
|
if @circuit_breaker_status.any?
|
|
409
416
|
open_circuits = @circuit_breaker_status.select { |_, status| status[:state] == :open }
|
|
410
417
|
if open_circuits.any?
|
|
411
|
-
|
|
418
|
+
display_message(" Open Circuit Breakers: #{open_circuits.keys.join(", ")}", type: :warning)
|
|
412
419
|
end
|
|
413
420
|
end
|
|
414
421
|
|
|
@@ -417,22 +424,22 @@ module Aidp
|
|
|
417
424
|
|
|
418
425
|
# Error summary
|
|
419
426
|
if @error_summary[:error_summary] && @error_summary[:error_summary][:total_errors] > 0
|
|
420
|
-
|
|
427
|
+
display_message(" Errors: #{@error_summary[:error_summary][:total_errors]} total", type: :warning)
|
|
421
428
|
end
|
|
422
429
|
|
|
423
|
-
|
|
430
|
+
display_message(" Press Ctrl+C to stop", type: :info)
|
|
424
431
|
end
|
|
425
432
|
|
|
426
433
|
def display_minimal_status
|
|
427
434
|
duration = @start_time ? Time.now - @start_time : 0
|
|
428
|
-
|
|
435
|
+
display_message("\r🔄 #{@current_step || "Starting"} | #{@current_provider || "Init"} | #{format_duration(duration)}", type: :info)
|
|
429
436
|
end
|
|
430
437
|
|
|
431
438
|
def display_full_status
|
|
432
439
|
clear_display
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
440
|
+
display_message("\n" + "=" * 80, type: :info)
|
|
441
|
+
display_message("🔄 AIDP HARNESS - FULL STATUS REPORT", type: :highlight)
|
|
442
|
+
display_message("=" * 80, type: :info)
|
|
436
443
|
|
|
437
444
|
display_basic_info
|
|
438
445
|
display_provider_info
|
|
@@ -446,33 +453,33 @@ module Aidp
|
|
|
446
453
|
display_work_completion_info
|
|
447
454
|
display_alerts
|
|
448
455
|
|
|
449
|
-
|
|
450
|
-
|
|
456
|
+
display_message("=" * 80, type: :info)
|
|
457
|
+
display_message("Press Ctrl+C to stop | Last updated: #{Time.now.strftime("%H:%M:%S")}", type: :muted)
|
|
451
458
|
end
|
|
452
459
|
|
|
453
460
|
def display_basic_info
|
|
454
461
|
duration = @start_time ? Time.now - @start_time : 0
|
|
455
462
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
+
display_message("\n📊 BASIC INFORMATION", type: :info)
|
|
464
|
+
display_message(" Duration: #{format_duration(duration)}", type: :info)
|
|
465
|
+
display_message(" Current Step: #{@current_step || "Starting..."}", type: :info)
|
|
466
|
+
display_message(" Provider: #{@current_provider || "Initializing..."}", type: :info)
|
|
467
|
+
display_message(" Model: #{@current_model || "N/A"}", type: :info)
|
|
468
|
+
display_message(" Status: Running", type: :info)
|
|
469
|
+
display_message(" Update Interval: #{@update_interval}s", type: :info)
|
|
463
470
|
end
|
|
464
471
|
|
|
465
472
|
def display_provider_info
|
|
466
473
|
return unless @provider_status.any?
|
|
467
474
|
|
|
468
|
-
|
|
475
|
+
display_message("\n🔌 PROVIDER INFORMATION", type: :info)
|
|
469
476
|
if @provider_status[:available_providers]
|
|
470
|
-
|
|
477
|
+
display_message(" Available Providers: #{@provider_status[:available_providers].join(", ")}", type: :info)
|
|
471
478
|
end
|
|
472
479
|
if @provider_status[:provider_health]
|
|
473
|
-
|
|
480
|
+
display_message(" Provider Health:", type: :info)
|
|
474
481
|
@provider_status[:provider_health].each do |provider, health|
|
|
475
|
-
|
|
482
|
+
display_message(" #{provider}: #{health[:status]} (#{format_percentage(health[:health_score])})", type: :info)
|
|
476
483
|
end
|
|
477
484
|
end
|
|
478
485
|
end
|
|
@@ -480,11 +487,11 @@ module Aidp
|
|
|
480
487
|
def display_token_info
|
|
481
488
|
return unless @token_usage.any?
|
|
482
489
|
|
|
483
|
-
|
|
490
|
+
display_message("\n🎫 TOKEN USAGE", type: :info)
|
|
484
491
|
@token_usage.each do |provider, models|
|
|
485
|
-
|
|
492
|
+
display_message(" #{provider}:", type: :info)
|
|
486
493
|
models.each do |model, usage|
|
|
487
|
-
|
|
494
|
+
display_message(" #{model}: #{usage[:used]} used, #{usage[:remaining]} remaining", type: :info)
|
|
488
495
|
end
|
|
489
496
|
end
|
|
490
497
|
end
|
|
@@ -492,14 +499,14 @@ module Aidp
|
|
|
492
499
|
def display_performance_info
|
|
493
500
|
return unless @performance_metrics.any?
|
|
494
501
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
502
|
+
display_message("\n⚡ PERFORMANCE METRICS", type: :info)
|
|
503
|
+
display_message(" Uptime: #{format_duration(@performance_metrics[:uptime] || 0)}", type: :info)
|
|
504
|
+
display_message(" Step Duration: #{format_duration(@performance_metrics[:step_duration] || 0)}", type: :info)
|
|
505
|
+
display_message(" Provider Switches: #{@performance_metrics[:provider_switch_count] || 0}", type: :info)
|
|
506
|
+
display_message(" Error Rate: #{format_percentage(@performance_metrics[:error_rate] || 0)}", type: :info)
|
|
500
507
|
|
|
501
508
|
if @performance_metrics[:throughput]
|
|
502
|
-
|
|
509
|
+
display_message(" Throughput: #{@performance_metrics[:throughput]} requests/min", type: :info)
|
|
503
510
|
end
|
|
504
511
|
end
|
|
505
512
|
|
|
@@ -509,21 +516,21 @@ module Aidp
|
|
|
509
516
|
error_summary = @error_summary[:error_summary]
|
|
510
517
|
return if error_summary[:total_errors] == 0
|
|
511
518
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
519
|
+
display_message("\n❌ ERROR INFORMATION", type: :error)
|
|
520
|
+
display_message(" Total Errors: #{error_summary[:total_errors]}", type: :error)
|
|
521
|
+
display_message(" Error Rate: #{format_percentage(error_summary[:error_rate] || 0)}", type: :error)
|
|
515
522
|
|
|
516
523
|
if error_summary[:errors_by_severity].respond_to?(:any?) && error_summary[:errors_by_severity].any?
|
|
517
|
-
|
|
524
|
+
display_message(" By Severity:", type: :info)
|
|
518
525
|
error_summary[:errors_by_severity].each do |severity, count|
|
|
519
|
-
|
|
526
|
+
display_message(" #{severity}: #{count}", type: :info)
|
|
520
527
|
end
|
|
521
528
|
end
|
|
522
529
|
|
|
523
530
|
if error_summary[:errors_by_provider].respond_to?(:any?) && error_summary[:errors_by_provider].any?
|
|
524
|
-
|
|
531
|
+
display_message(" By Provider:", type: :info)
|
|
525
532
|
error_summary[:errors_by_provider].each do |provider, count|
|
|
526
|
-
|
|
533
|
+
display_message(" #{provider}: #{count}", type: :info)
|
|
527
534
|
end
|
|
528
535
|
end
|
|
529
536
|
end
|
|
@@ -531,23 +538,23 @@ module Aidp
|
|
|
531
538
|
def display_circuit_breaker_info
|
|
532
539
|
return unless @circuit_breaker_status.any?
|
|
533
540
|
|
|
534
|
-
|
|
541
|
+
display_message("\n🔒 CIRCUIT BREAKER STATUS", type: :info)
|
|
535
542
|
@circuit_breaker_status.each do |key, status|
|
|
536
543
|
state_icons = {closed: "🟢", open: "🔴", half_open: "🟡"}
|
|
537
544
|
state_icon = state_icons[status[:state]] || "⚪"
|
|
538
|
-
|
|
545
|
+
display_message(" #{state_icon} #{key}: #{status[:state]} (failures: #{status[:failure_count]})", type: :info)
|
|
539
546
|
end
|
|
540
547
|
end
|
|
541
548
|
|
|
542
549
|
def display_token_usage
|
|
543
550
|
return unless @token_usage.any?
|
|
544
551
|
|
|
545
|
-
|
|
552
|
+
display_message("\n🎫 TOKEN USAGE", type: :info)
|
|
546
553
|
@token_usage.each do |provider, models|
|
|
547
|
-
|
|
554
|
+
display_message(" #{provider}:", type: :info)
|
|
548
555
|
models.each do |model, usage|
|
|
549
|
-
|
|
550
|
-
|
|
556
|
+
display_message(" #{model}: #{usage[:used]} used", type: :info)
|
|
557
|
+
display_message(" Remaining: #{usage[:remaining]}", type: :info) if usage[:remaining]
|
|
551
558
|
end
|
|
552
559
|
end
|
|
553
560
|
end
|
|
@@ -555,14 +562,14 @@ module Aidp
|
|
|
555
562
|
def display_rate_limit_info
|
|
556
563
|
return unless @rate_limit_status.any?
|
|
557
564
|
|
|
558
|
-
|
|
565
|
+
display_message("\n🚫 RATE LIMIT STATUS", type: :warning)
|
|
559
566
|
@rate_limit_status.each do |provider, models|
|
|
560
567
|
models.each do |model, status|
|
|
561
568
|
if status[:rate_limited]
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
569
|
+
display_message(" #{provider}:#{model}: Rate Limited", type: :warning)
|
|
570
|
+
display_message(" Reset Time: #{status[:reset_time]&.strftime("%H:%M:%S")}", type: :info)
|
|
571
|
+
display_message(" Retry After: #{status[:retry_after]}s", type: :info)
|
|
572
|
+
display_message(" Quota: #{status[:quota_remaining]}/#{status[:quota_limit]}", type: :info) if status[:quota_remaining]
|
|
566
573
|
end
|
|
567
574
|
end
|
|
568
575
|
end
|
|
@@ -571,12 +578,12 @@ module Aidp
|
|
|
571
578
|
def display_recovery_info
|
|
572
579
|
return unless @recovery_status.any?
|
|
573
580
|
|
|
574
|
-
|
|
581
|
+
display_message("\n🔄 RECOVERY STATUS", type: :info)
|
|
575
582
|
@recovery_status.each do |type, status|
|
|
576
|
-
|
|
583
|
+
display_message(" #{type}: #{status[:status]}", type: :info)
|
|
577
584
|
if status[:details].any?
|
|
578
585
|
status[:details].each do |key, value|
|
|
579
|
-
|
|
586
|
+
display_message(" #{key}: #{value}", type: :info)
|
|
580
587
|
end
|
|
581
588
|
end
|
|
582
589
|
end
|
|
@@ -585,12 +592,12 @@ module Aidp
|
|
|
585
592
|
def display_user_feedback_info
|
|
586
593
|
return unless @user_feedback_status.any?
|
|
587
594
|
|
|
588
|
-
|
|
595
|
+
display_message("\n💬 USER FEEDBACK STATUS", type: :info)
|
|
589
596
|
@user_feedback_status.each do |type, status|
|
|
590
|
-
|
|
597
|
+
display_message(" #{type}: #{status[:status]}", type: :info)
|
|
591
598
|
if status[:details].any?
|
|
592
599
|
status[:details].each do |key, value|
|
|
593
|
-
|
|
600
|
+
display_message(" #{key}: #{value}", type: :info)
|
|
594
601
|
end
|
|
595
602
|
end
|
|
596
603
|
end
|
|
@@ -599,24 +606,24 @@ module Aidp
|
|
|
599
606
|
def display_work_completion_info
|
|
600
607
|
return unless @work_completion_status.any?
|
|
601
608
|
|
|
602
|
-
|
|
609
|
+
display_message("\n✅ WORK COMPLETION STATUS", type: :info)
|
|
603
610
|
if @work_completion_status[:is_complete]
|
|
604
|
-
|
|
611
|
+
display_message(" Status: Complete", type: :success)
|
|
605
612
|
else
|
|
606
|
-
|
|
613
|
+
display_message(" Status: In Progress", type: :info)
|
|
607
614
|
end
|
|
608
|
-
|
|
615
|
+
display_message(" Steps Completed: #{@work_completion_status[:completed_steps]}/#{@work_completion_status[:total_steps]}", type: :info)
|
|
609
616
|
end
|
|
610
617
|
|
|
611
618
|
def display_alerts
|
|
612
619
|
alerts = get_alerts
|
|
613
620
|
return unless alerts.any?
|
|
614
621
|
|
|
615
|
-
|
|
622
|
+
display_message("\n🚨 ALERTS", type: :warning)
|
|
616
623
|
alerts.each do |alert|
|
|
617
624
|
severity_icons = {critical: "🔴", warning: "🟡", info: "🔵"}
|
|
618
625
|
severity_icon = severity_icons[alert[:severity]] || "⚪"
|
|
619
|
-
|
|
626
|
+
display_message(" #{severity_icon} #{alert[:message]}", type: :warning)
|
|
620
627
|
end
|
|
621
628
|
end
|
|
622
629
|
|
|
@@ -661,8 +668,8 @@ module Aidp
|
|
|
661
668
|
end
|
|
662
669
|
|
|
663
670
|
def handle_display_error(error)
|
|
664
|
-
|
|
665
|
-
|
|
671
|
+
display_message("\n❌ Display Error: #{error.message}", type: :error)
|
|
672
|
+
display_message(" Continuing with status updates...", type: :info)
|
|
666
673
|
end
|
|
667
674
|
|
|
668
675
|
def get_basic_status
|
|
@@ -737,9 +744,14 @@ module Aidp
|
|
|
737
744
|
end
|
|
738
745
|
|
|
739
746
|
def clear_display
|
|
740
|
-
# Clear the current line
|
|
741
|
-
|
|
742
|
-
|
|
747
|
+
# Clear the current line using TTY::Cursor
|
|
748
|
+
print_to_stderr(@cursor.clear_line, @cursor.column(1))
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
# Helper method to print to stderr with flush
|
|
752
|
+
def print_to_stderr(*parts)
|
|
753
|
+
parts.each { |part| $stderr.print part }
|
|
754
|
+
$stderr.flush
|
|
743
755
|
end
|
|
744
756
|
|
|
745
757
|
def format_duration(seconds)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module Aidp
|
|
6
|
+
module Harness
|
|
7
|
+
# Executes test and linter commands configured in aidp.yml
|
|
8
|
+
# Returns results with exit status and output
|
|
9
|
+
class TestRunner
|
|
10
|
+
def initialize(project_dir, config)
|
|
11
|
+
@project_dir = project_dir
|
|
12
|
+
@config = config
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Run all configured tests
|
|
16
|
+
# Returns: { success: boolean, output: string, failures: array }
|
|
17
|
+
def run_tests
|
|
18
|
+
test_commands = @config.test_commands || []
|
|
19
|
+
return {success: true, output: "", failures: []} if test_commands.empty?
|
|
20
|
+
|
|
21
|
+
results = test_commands.map { |cmd| execute_command(cmd, "test") }
|
|
22
|
+
aggregate_results(results, "Tests")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Run all configured linters
|
|
26
|
+
# Returns: { success: boolean, output: string, failures: array }
|
|
27
|
+
def run_linters
|
|
28
|
+
lint_commands = @config.lint_commands || []
|
|
29
|
+
return {success: true, output: "", failures: []} if lint_commands.empty?
|
|
30
|
+
|
|
31
|
+
results = lint_commands.map { |cmd| execute_command(cmd, "linter") }
|
|
32
|
+
aggregate_results(results, "Linters")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def execute_command(command, type)
|
|
38
|
+
stdout, stderr, status = Open3.capture3(command, chdir: @project_dir)
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
command: command,
|
|
42
|
+
type: type,
|
|
43
|
+
success: status.success?,
|
|
44
|
+
exit_code: status.exitstatus,
|
|
45
|
+
stdout: stdout,
|
|
46
|
+
stderr: stderr
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def aggregate_results(results, category)
|
|
51
|
+
failures = results.reject { |r| r[:success] }
|
|
52
|
+
success = failures.empty?
|
|
53
|
+
|
|
54
|
+
output = if success
|
|
55
|
+
"#{category}: All passed"
|
|
56
|
+
else
|
|
57
|
+
format_failures(failures, category)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
success: success,
|
|
62
|
+
output: output,
|
|
63
|
+
failures: failures
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def format_failures(failures, category)
|
|
68
|
+
output = ["#{category} Failures:", ""]
|
|
69
|
+
|
|
70
|
+
failures.each do |failure|
|
|
71
|
+
output << "Command: #{failure[:command]}"
|
|
72
|
+
output << "Exit Code: #{failure[:exit_code]}"
|
|
73
|
+
output << "--- Output ---"
|
|
74
|
+
output << failure[:stdout] unless failure[:stdout].strip.empty?
|
|
75
|
+
output << failure[:stderr] unless failure[:stderr].strip.empty?
|
|
76
|
+
output << ""
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
output.join("\n")
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -15,7 +15,9 @@ module Aidp
|
|
|
15
15
|
# Enhanced TUI system using TTY libraries, inspired by Claude Code and modern LLM agents
|
|
16
16
|
class EnhancedTUI
|
|
17
17
|
class TUIError < StandardError; end
|
|
18
|
+
|
|
18
19
|
class InputError < TUIError; end
|
|
20
|
+
|
|
19
21
|
class DisplayError < TUIError; end
|
|
20
22
|
|
|
21
23
|
def initialize(prompt: TTY::Prompt.new)
|
|
@@ -129,7 +131,7 @@ module Aidp
|
|
|
129
131
|
border: :thick,
|
|
130
132
|
padding: [1, 2]
|
|
131
133
|
)
|
|
132
|
-
|
|
134
|
+
@prompt.say(box)
|
|
133
135
|
end
|
|
134
136
|
|
|
135
137
|
# Enhanced step execution display
|
|
@@ -149,7 +151,7 @@ module Aidp
|
|
|
149
151
|
padding: [1, 2],
|
|
150
152
|
style: {border: {fg: :blue}}
|
|
151
153
|
)
|
|
152
|
-
|
|
154
|
+
@prompt.say(box)
|
|
153
155
|
|
|
154
156
|
when :running
|
|
155
157
|
content = []
|
|
@@ -165,7 +167,7 @@ module Aidp
|
|
|
165
167
|
padding: [1, 2],
|
|
166
168
|
style: {border: {fg: :yellow}}
|
|
167
169
|
)
|
|
168
|
-
|
|
170
|
+
@prompt.say(box)
|
|
169
171
|
|
|
170
172
|
when :completed
|
|
171
173
|
content = []
|
|
@@ -181,7 +183,7 @@ module Aidp
|
|
|
181
183
|
padding: [1, 2],
|
|
182
184
|
style: {border: {fg: :green}}
|
|
183
185
|
)
|
|
184
|
-
|
|
186
|
+
@prompt.say(box)
|
|
185
187
|
|
|
186
188
|
when :failed
|
|
187
189
|
content = []
|
|
@@ -222,7 +224,7 @@ module Aidp
|
|
|
222
224
|
style: {border: {fg: :red}},
|
|
223
225
|
width: 80
|
|
224
226
|
)
|
|
225
|
-
|
|
227
|
+
@prompt.say(box)
|
|
226
228
|
end
|
|
227
229
|
end
|
|
228
230
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "enhanced_tui"
|
|
4
|
+
require_relative "../../workflows/selector"
|
|
4
5
|
|
|
5
6
|
module Aidp
|
|
6
7
|
module Harness
|
|
@@ -12,6 +13,7 @@ module Aidp
|
|
|
12
13
|
def initialize(tui = nil)
|
|
13
14
|
@tui = tui || EnhancedTUI.new
|
|
14
15
|
@user_input = {}
|
|
16
|
+
@workflow_selector = Aidp::Workflows::Selector.new
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def select_workflow(harness_mode: false, mode: :analyze)
|
|
@@ -29,7 +31,7 @@ module Aidp
|
|
|
29
31
|
when :analyze
|
|
30
32
|
select_analyze_workflow_interactive
|
|
31
33
|
when :execute
|
|
32
|
-
|
|
34
|
+
select_execute_workflow_interactive_new(mode)
|
|
33
35
|
else
|
|
34
36
|
raise ArgumentError, "Unknown mode: #{mode}"
|
|
35
37
|
end
|
|
@@ -65,6 +67,22 @@ module Aidp
|
|
|
65
67
|
}
|
|
66
68
|
end
|
|
67
69
|
|
|
70
|
+
def select_execute_workflow_interactive_new(mode)
|
|
71
|
+
# Step 1: Collect project information
|
|
72
|
+
collect_project_info_interactive
|
|
73
|
+
|
|
74
|
+
# Step 2: Use new workflow selector
|
|
75
|
+
result = @workflow_selector.select_workflow(mode)
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
workflow_type: result[:workflow_key],
|
|
79
|
+
steps: result[:steps],
|
|
80
|
+
user_input: @user_input,
|
|
81
|
+
workflow: result[:workflow]
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Legacy method - kept for backward compatibility if needed
|
|
68
86
|
def select_execute_workflow_interactive
|
|
69
87
|
# Step 1: Collect project information
|
|
70
88
|
collect_project_info_interactive
|
|
@@ -160,10 +178,10 @@ module Aidp
|
|
|
160
178
|
|
|
161
179
|
def generate_exploration_steps
|
|
162
180
|
[
|
|
163
|
-
"00_PRD",
|
|
181
|
+
"00_PRD", # Generate PRD from user input (no manual gate)
|
|
164
182
|
"10_TESTING_STRATEGY", # Ensure we have tests
|
|
165
|
-
"11_STATIC_ANALYSIS",
|
|
166
|
-
"16_IMPLEMENTATION"
|
|
183
|
+
"11_STATIC_ANALYSIS", # Code quality
|
|
184
|
+
"16_IMPLEMENTATION" # Special step for actual development work
|
|
167
185
|
]
|
|
168
186
|
end
|
|
169
187
|
|