aidp 0.32.0 → 0.34.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 +35 -0
- data/lib/aidp/analyze/feature_analyzer.rb +322 -320
- data/lib/aidp/analyze/tree_sitter_scan.rb +3 -0
- data/lib/aidp/auto_update/coordinator.rb +97 -7
- data/lib/aidp/auto_update.rb +0 -12
- data/lib/aidp/cli/devcontainer_commands.rb +0 -5
- data/lib/aidp/cli/eval_command.rb +399 -0
- data/lib/aidp/cli/harness_command.rb +1 -1
- data/lib/aidp/cli/security_command.rb +416 -0
- data/lib/aidp/cli/tools_command.rb +6 -4
- data/lib/aidp/cli.rb +172 -4
- data/lib/aidp/comment_consolidator.rb +78 -0
- data/lib/aidp/concurrency/exec.rb +3 -0
- data/lib/aidp/concurrency.rb +0 -3
- data/lib/aidp/config.rb +113 -1
- data/lib/aidp/config_paths.rb +91 -0
- data/lib/aidp/daemon/runner.rb +8 -4
- data/lib/aidp/errors.rb +134 -0
- data/lib/aidp/evaluations/context_capture.rb +205 -0
- data/lib/aidp/evaluations/evaluation_record.rb +114 -0
- data/lib/aidp/evaluations/evaluation_storage.rb +250 -0
- data/lib/aidp/evaluations.rb +23 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +4 -1
- data/lib/aidp/execute/interactive_repl.rb +6 -2
- data/lib/aidp/execute/prompt_evaluator.rb +359 -0
- data/lib/aidp/execute/repl_macros.rb +100 -1
- data/lib/aidp/execute/work_loop_runner.rb +719 -58
- data/lib/aidp/execute/work_loop_state.rb +4 -1
- data/lib/aidp/execute/workflow_selector.rb +3 -0
- data/lib/aidp/harness/ai_decision_engine.rb +79 -0
- data/lib/aidp/harness/ai_filter_factory.rb +285 -0
- data/lib/aidp/harness/capability_registry.rb +2 -0
- data/lib/aidp/harness/condition_detector.rb +3 -0
- data/lib/aidp/harness/config_loader.rb +3 -0
- data/lib/aidp/harness/config_schema.rb +97 -1
- data/lib/aidp/harness/config_validator.rb +1 -1
- data/lib/aidp/harness/configuration.rb +61 -5
- data/lib/aidp/harness/enhanced_runner.rb +14 -11
- data/lib/aidp/harness/error_handler.rb +3 -0
- data/lib/aidp/harness/filter_definition.rb +212 -0
- data/lib/aidp/harness/generated_filter_strategy.rb +197 -0
- data/lib/aidp/harness/output_filter.rb +50 -25
- data/lib/aidp/harness/output_filter_config.rb +129 -0
- data/lib/aidp/harness/provider_factory.rb +3 -0
- data/lib/aidp/harness/provider_manager.rb +96 -2
- data/lib/aidp/harness/runner.rb +5 -12
- data/lib/aidp/harness/state/persistence.rb +3 -0
- data/lib/aidp/harness/state_manager.rb +3 -0
- data/lib/aidp/harness/status_display.rb +28 -20
- data/lib/aidp/harness/test_runner.rb +179 -41
- data/lib/aidp/harness/thinking_depth_manager.rb +44 -28
- data/lib/aidp/harness/ui/enhanced_tui.rb +4 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +4 -0
- data/lib/aidp/harness/ui/error_handler.rb +3 -0
- data/lib/aidp/harness/ui/job_monitor.rb +4 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +2 -2
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +6 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +3 -0
- data/lib/aidp/harness/ui/workflow_controller.rb +3 -0
- data/lib/aidp/harness/user_interface.rb +3 -0
- data/lib/aidp/loader.rb +195 -0
- data/lib/aidp/logger.rb +3 -0
- data/lib/aidp/message_display.rb +31 -0
- data/lib/aidp/metadata/compiler.rb +29 -17
- data/lib/aidp/metadata/query.rb +1 -1
- data/lib/aidp/metadata/scanner.rb +8 -1
- data/lib/aidp/metadata/tool_metadata.rb +13 -13
- data/lib/aidp/metadata/validator.rb +10 -0
- data/lib/aidp/metadata.rb +16 -0
- data/lib/aidp/pr_worktree_manager.rb +20 -8
- data/lib/aidp/provider_manager.rb +4 -7
- data/lib/aidp/providers/base.rb +2 -0
- data/lib/aidp/security/rule_of_two_enforcer.rb +210 -0
- data/lib/aidp/security/secrets_proxy.rb +328 -0
- data/lib/aidp/security/secrets_registry.rb +227 -0
- data/lib/aidp/security/trifecta_state.rb +220 -0
- data/lib/aidp/security/watch_mode_handler.rb +306 -0
- data/lib/aidp/security/work_loop_adapter.rb +277 -0
- data/lib/aidp/security.rb +56 -0
- data/lib/aidp/setup/wizard.rb +283 -11
- data/lib/aidp/skills.rb +0 -5
- data/lib/aidp/storage/csv_storage.rb +3 -0
- data/lib/aidp/style_guide/selector.rb +360 -0
- data/lib/aidp/tooling_detector.rb +283 -16
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/auto_merger.rb +274 -0
- data/lib/aidp/watch/auto_pr_processor.rb +125 -7
- data/lib/aidp/watch/build_processor.rb +16 -1
- data/lib/aidp/watch/change_request_processor.rb +682 -150
- data/lib/aidp/watch/ci_fix_processor.rb +262 -4
- data/lib/aidp/watch/feedback_collector.rb +191 -0
- data/lib/aidp/watch/hierarchical_pr_strategy.rb +256 -0
- data/lib/aidp/watch/implementation_verifier.rb +142 -1
- data/lib/aidp/watch/plan_generator.rb +70 -13
- data/lib/aidp/watch/plan_processor.rb +12 -5
- data/lib/aidp/watch/projects_processor.rb +286 -0
- data/lib/aidp/watch/repository_client.rb +871 -22
- data/lib/aidp/watch/review_processor.rb +33 -6
- data/lib/aidp/watch/runner.rb +80 -29
- data/lib/aidp/watch/state_store.rb +233 -0
- data/lib/aidp/watch/sub_issue_creator.rb +221 -0
- data/lib/aidp/watch.rb +5 -7
- data/lib/aidp/workflows/guided_agent.rb +4 -0
- data/lib/aidp/workstream_cleanup.rb +0 -2
- data/lib/aidp/workstream_executor.rb +3 -4
- data/lib/aidp/worktree.rb +61 -12
- data/lib/aidp/worktree_branch_manager.rb +347 -101
- data/lib/aidp.rb +21 -106
- data/templates/implementation/iterative_implementation.md +46 -3
- metadata +91 -36
- data/lib/aidp/config/paths.rb +0 -131
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aidp
|
|
4
|
+
module Harness
|
|
5
|
+
# Value object for output filter configuration
|
|
6
|
+
# Provides validation and type-safe access to filtering options
|
|
7
|
+
class OutputFilterConfig
|
|
8
|
+
VALID_MODES = %i[full failures_only minimal].freeze
|
|
9
|
+
DEFAULT_MODE = :full
|
|
10
|
+
DEFAULT_INCLUDE_CONTEXT = true
|
|
11
|
+
DEFAULT_CONTEXT_LINES = 3
|
|
12
|
+
DEFAULT_MAX_LINES = 500
|
|
13
|
+
MIN_CONTEXT_LINES = 0
|
|
14
|
+
MAX_CONTEXT_LINES = 20
|
|
15
|
+
MIN_MAX_LINES = 10
|
|
16
|
+
MAX_MAX_LINES = 10_000
|
|
17
|
+
|
|
18
|
+
attr_reader :mode, :include_context, :context_lines, :max_lines
|
|
19
|
+
|
|
20
|
+
# Create a new OutputFilterConfig
|
|
21
|
+
# @param mode [Symbol] Output mode (:full, :failures_only, :minimal)
|
|
22
|
+
# @param include_context [Boolean] Include surrounding lines
|
|
23
|
+
# @param context_lines [Integer] Number of context lines (0-20)
|
|
24
|
+
# @param max_lines [Integer] Maximum output lines (10-10000)
|
|
25
|
+
# @raise [ArgumentError] If any parameter is invalid
|
|
26
|
+
def initialize(mode: DEFAULT_MODE, include_context: DEFAULT_INCLUDE_CONTEXT,
|
|
27
|
+
context_lines: DEFAULT_CONTEXT_LINES, max_lines: DEFAULT_MAX_LINES)
|
|
28
|
+
@mode = validate_mode(mode)
|
|
29
|
+
@include_context = validate_boolean(include_context, "include_context")
|
|
30
|
+
@context_lines = validate_context_lines(context_lines)
|
|
31
|
+
@max_lines = validate_max_lines(max_lines)
|
|
32
|
+
|
|
33
|
+
freeze
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Create from a hash (useful for configuration loading)
|
|
37
|
+
# @param hash [Hash] Configuration hash
|
|
38
|
+
# @return [OutputFilterConfig] New config instance
|
|
39
|
+
def self.from_hash(hash)
|
|
40
|
+
hash = hash.transform_keys(&:to_sym) if hash.respond_to?(:transform_keys)
|
|
41
|
+
|
|
42
|
+
new(
|
|
43
|
+
mode: hash[:mode] || DEFAULT_MODE,
|
|
44
|
+
include_context: hash.fetch(:include_context, DEFAULT_INCLUDE_CONTEXT),
|
|
45
|
+
context_lines: hash[:context_lines] || DEFAULT_CONTEXT_LINES,
|
|
46
|
+
max_lines: hash[:max_lines] || DEFAULT_MAX_LINES
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Convert to hash (useful for serialization)
|
|
51
|
+
# @return [Hash] Configuration as hash
|
|
52
|
+
def to_h
|
|
53
|
+
{
|
|
54
|
+
mode: @mode,
|
|
55
|
+
include_context: @include_context,
|
|
56
|
+
context_lines: @context_lines,
|
|
57
|
+
max_lines: @max_lines
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Check if filtering is enabled
|
|
62
|
+
# @return [Boolean] True if mode is not :full
|
|
63
|
+
def filtering_enabled?
|
|
64
|
+
@mode != :full
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Compare with another config
|
|
68
|
+
# @param other [OutputFilterConfig] Other config to compare
|
|
69
|
+
# @return [Boolean] True if equal
|
|
70
|
+
def ==(other)
|
|
71
|
+
return false unless other.is_a?(OutputFilterConfig)
|
|
72
|
+
|
|
73
|
+
@mode == other.mode &&
|
|
74
|
+
@include_context == other.include_context &&
|
|
75
|
+
@context_lines == other.context_lines &&
|
|
76
|
+
@max_lines == other.max_lines
|
|
77
|
+
end
|
|
78
|
+
alias_method :eql?, :==
|
|
79
|
+
|
|
80
|
+
# Hash for use in Hash/Set
|
|
81
|
+
def hash
|
|
82
|
+
[@mode, @include_context, @context_lines, @max_lines].hash
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def validate_mode(mode)
|
|
88
|
+
mode = mode.to_sym if mode.respond_to?(:to_sym)
|
|
89
|
+
|
|
90
|
+
unless VALID_MODES.include?(mode)
|
|
91
|
+
raise ArgumentError,
|
|
92
|
+
"Invalid mode: #{mode.inspect}. Must be one of #{VALID_MODES.join(", ")}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
mode
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def validate_boolean(value, name)
|
|
99
|
+
unless [true, false].include?(value)
|
|
100
|
+
raise ArgumentError, "#{name} must be a boolean, got: #{value.inspect}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
value
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validate_context_lines(value)
|
|
107
|
+
value = value.to_i if value.respond_to?(:to_i) && !value.is_a?(Integer)
|
|
108
|
+
|
|
109
|
+
unless value.is_a?(Integer) && value >= MIN_CONTEXT_LINES && value <= MAX_CONTEXT_LINES
|
|
110
|
+
raise ArgumentError,
|
|
111
|
+
"context_lines must be an integer between #{MIN_CONTEXT_LINES} and #{MAX_CONTEXT_LINES}, got: #{value.inspect}"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
value
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def validate_max_lines(value)
|
|
118
|
+
value = value.to_i if value.respond_to?(:to_i) && !value.is_a?(Integer)
|
|
119
|
+
|
|
120
|
+
unless value.is_a?(Integer) && value >= MIN_MAX_LINES && value <= MAX_MAX_LINES
|
|
121
|
+
raise ArgumentError,
|
|
122
|
+
"max_lines must be an integer between #{MIN_MAX_LINES} and #{MAX_MAX_LINES}, got: #{value.inspect}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
value
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -15,6 +15,9 @@ module Aidp
|
|
|
15
15
|
module Harness
|
|
16
16
|
# Factory for creating configured provider instances
|
|
17
17
|
class ProviderFactory
|
|
18
|
+
# Expose for testability
|
|
19
|
+
attr_reader :provider_instances, :provider_configs
|
|
20
|
+
|
|
18
21
|
PROVIDER_CLASSES = {
|
|
19
22
|
"cursor" => Aidp::Providers::Cursor,
|
|
20
23
|
"anthropic" => Aidp::Providers::Anthropic,
|
|
@@ -13,6 +13,12 @@ module Aidp
|
|
|
13
13
|
include Aidp::MessageDisplay
|
|
14
14
|
include Aidp::RescueLogging
|
|
15
15
|
|
|
16
|
+
# Expose state for testability
|
|
17
|
+
attr_accessor :sticky_sessions, :load_balancing_enabled
|
|
18
|
+
attr_writer :current_model
|
|
19
|
+
attr_accessor :provider_health, :provider_metrics, :rate_limit_info
|
|
20
|
+
attr_reader :binary_check_cache, :binary_check_ttl
|
|
21
|
+
|
|
16
22
|
def initialize(configuration, prompt: TTY::Prompt.new, binary_checker: Aidp::Util)
|
|
17
23
|
@configuration = configuration
|
|
18
24
|
@prompt = prompt
|
|
@@ -1240,6 +1246,11 @@ module Aidp
|
|
|
1240
1246
|
total_tokens: m[:total_tokens] || 0,
|
|
1241
1247
|
last_used: m[:last_used]
|
|
1242
1248
|
}
|
|
1249
|
+
|
|
1250
|
+
# Set reason if currently rate limited (for display in Reason column)
|
|
1251
|
+
if rl && reset_in && reset_in > 0
|
|
1252
|
+
row[:unhealthy_reason] ||= "rate_limited"
|
|
1253
|
+
end
|
|
1243
1254
|
# Incorporate CLI check outcome into reason/availability if failing
|
|
1244
1255
|
unless cli_ok_prefetch
|
|
1245
1256
|
row[:available] = false
|
|
@@ -1416,9 +1427,43 @@ module Aidp
|
|
|
1416
1427
|
|
|
1417
1428
|
# Execute a prompt with a specific provider
|
|
1418
1429
|
def execute_with_provider(provider_type, prompt, options = {})
|
|
1430
|
+
options = options.dup
|
|
1431
|
+
|
|
1419
1432
|
# Extract model from options if provided
|
|
1420
1433
|
model_name = options.delete(:model)
|
|
1421
|
-
retry_on_rate_limit = options.
|
|
1434
|
+
retry_on_rate_limit = if options.key?(:retry_on_rate_limit)
|
|
1435
|
+
options.delete(:retry_on_rate_limit) != false
|
|
1436
|
+
else
|
|
1437
|
+
true
|
|
1438
|
+
end
|
|
1439
|
+
retry_on_unsupported = if options.key?(:retry_on_unsupported)
|
|
1440
|
+
options.delete(:retry_on_unsupported) != false
|
|
1441
|
+
else
|
|
1442
|
+
true
|
|
1443
|
+
end
|
|
1444
|
+
tier = options[:tier]
|
|
1445
|
+
base_options = options.dup
|
|
1446
|
+
|
|
1447
|
+
if model_name && model_denied?(provider_type, model_name)
|
|
1448
|
+
alternate_model = select_alternate_model(provider_type, tier: tier, current_model: model_name)
|
|
1449
|
+
if alternate_model
|
|
1450
|
+
Aidp.logger.warn("provider_manager", "Model is denylisted, selecting alternate",
|
|
1451
|
+
provider: provider_type,
|
|
1452
|
+
model: model_name,
|
|
1453
|
+
alternate_model: alternate_model,
|
|
1454
|
+
tier: tier)
|
|
1455
|
+
|
|
1456
|
+
return execute_with_provider(
|
|
1457
|
+
provider_type,
|
|
1458
|
+
prompt,
|
|
1459
|
+
base_options.merge(
|
|
1460
|
+
model: alternate_model,
|
|
1461
|
+
retry_on_rate_limit: retry_on_rate_limit,
|
|
1462
|
+
retry_on_unsupported: false
|
|
1463
|
+
)
|
|
1464
|
+
)
|
|
1465
|
+
end
|
|
1466
|
+
end
|
|
1422
1467
|
|
|
1423
1468
|
# Create provider factory instance
|
|
1424
1469
|
provider_factory = ProviderFactory.new
|
|
@@ -1440,7 +1485,7 @@ module Aidp
|
|
|
1440
1485
|
prompt_length: prompt.length)
|
|
1441
1486
|
|
|
1442
1487
|
# Execute the prompt with the provider
|
|
1443
|
-
result = provider.send_message(prompt: prompt, session: nil)
|
|
1488
|
+
result = provider.send_message(prompt: prompt, session: nil, options: options)
|
|
1444
1489
|
|
|
1445
1490
|
# Return structured result
|
|
1446
1491
|
{
|
|
@@ -1460,6 +1505,28 @@ module Aidp
|
|
|
1460
1505
|
|
|
1461
1506
|
if unsupported_model_error?(e, model_name)
|
|
1462
1507
|
deny_model(provider_type, model_name, error: e)
|
|
1508
|
+
|
|
1509
|
+
if retry_on_unsupported
|
|
1510
|
+
alternate_model = select_alternate_model(provider_type, tier: tier, current_model: model_name)
|
|
1511
|
+
|
|
1512
|
+
if alternate_model
|
|
1513
|
+
Aidp.logger.info("provider_manager", "Retrying with alternate model after unsupported model error",
|
|
1514
|
+
provider: provider_type,
|
|
1515
|
+
original_model: model_name,
|
|
1516
|
+
alternate_model: alternate_model,
|
|
1517
|
+
tier: tier)
|
|
1518
|
+
|
|
1519
|
+
return execute_with_provider(
|
|
1520
|
+
provider_type,
|
|
1521
|
+
prompt,
|
|
1522
|
+
base_options.merge(
|
|
1523
|
+
model: alternate_model,
|
|
1524
|
+
retry_on_rate_limit: retry_on_rate_limit,
|
|
1525
|
+
retry_on_unsupported: false
|
|
1526
|
+
)
|
|
1527
|
+
)
|
|
1528
|
+
end
|
|
1529
|
+
end
|
|
1463
1530
|
end
|
|
1464
1531
|
|
|
1465
1532
|
# Detect rate limit / quota errors and attempt fallback
|
|
@@ -1615,12 +1682,39 @@ module Aidp
|
|
|
1615
1682
|
|
|
1616
1683
|
message = error&.message.to_s.downcase
|
|
1617
1684
|
return false if message.empty?
|
|
1685
|
+
return false unless message.include?(model_name.to_s.downcase)
|
|
1618
1686
|
|
|
1619
1687
|
(message.include?("unsupported") && message.include?("model")) ||
|
|
1620
1688
|
(message.include?("model") && message.include?("not supported")) ||
|
|
1621
1689
|
message.include?("invalid model")
|
|
1622
1690
|
end
|
|
1623
1691
|
|
|
1692
|
+
# Select an alternate model for the provider and tier, excluding denylisted/current models
|
|
1693
|
+
def select_alternate_model(provider_name, tier:, current_model: nil)
|
|
1694
|
+
candidates = []
|
|
1695
|
+
|
|
1696
|
+
if tier && @configuration.respond_to?(:models_for_tier)
|
|
1697
|
+
tier_models = Array(@configuration.models_for_tier(tier, provider_name)).map(&:to_s)
|
|
1698
|
+
candidates.concat(tier_models)
|
|
1699
|
+
end
|
|
1700
|
+
|
|
1701
|
+
if candidates.empty? && @configuration.respond_to?(:provider_models)
|
|
1702
|
+
provider_models = Array(@configuration.provider_models(provider_name)).map(&:to_s)
|
|
1703
|
+
candidates.concat(provider_models)
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
candidates = candidates.uniq
|
|
1707
|
+
return nil if candidates.empty?
|
|
1708
|
+
|
|
1709
|
+
excluded = Array(current_model).compact + Array(@model_denylist[provider_name])
|
|
1710
|
+
candidates.reject! { |model| excluded.include?(model) }
|
|
1711
|
+
candidates.first
|
|
1712
|
+
rescue => e
|
|
1713
|
+
log_rescue(e, component: "provider_manager", action: "select_alternate_model", fallback: nil,
|
|
1714
|
+
provider: provider_name, tier: tier, current_model: current_model)
|
|
1715
|
+
nil
|
|
1716
|
+
end
|
|
1717
|
+
|
|
1624
1718
|
public
|
|
1625
1719
|
|
|
1626
1720
|
# Log provider switch
|
data/lib/aidp/harness/runner.rb
CHANGED
|
@@ -2,16 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "timeout"
|
|
4
4
|
require "json"
|
|
5
|
-
require_relative "configuration"
|
|
6
|
-
require_relative "state_manager"
|
|
7
|
-
require_relative "condition_detector"
|
|
8
|
-
require_relative "provider_manager"
|
|
9
|
-
require_relative "simple_user_interface"
|
|
10
|
-
require_relative "error_handler"
|
|
11
|
-
require_relative "status_display"
|
|
12
|
-
require_relative "completion_checker"
|
|
13
|
-
require_relative "../concurrency"
|
|
14
|
-
require_relative "../errors"
|
|
15
5
|
|
|
16
6
|
module Aidp
|
|
17
7
|
module Harness
|
|
@@ -33,7 +23,11 @@ module Aidp
|
|
|
33
23
|
}.freeze
|
|
34
24
|
|
|
35
25
|
# Public accessors for testing and integration
|
|
36
|
-
attr_reader :
|
|
26
|
+
attr_reader :clarification_questions, :last_error
|
|
27
|
+
attr_accessor :current_provider, :current_step, :user_input, :execution_log, :provider_manager
|
|
28
|
+
attr_accessor :state, :mode, :project_dir, :configuration, :condition_detector
|
|
29
|
+
attr_accessor :state_manager, :user_interface, :error_handler, :status_display
|
|
30
|
+
attr_writer :completion_checker, :workflow_type, :non_interactive
|
|
37
31
|
|
|
38
32
|
def initialize(project_dir, mode = :analyze, options = {})
|
|
39
33
|
@project_dir = project_dir
|
|
@@ -61,7 +55,6 @@ module Aidp
|
|
|
61
55
|
# Use ZFC-enabled condition detector
|
|
62
56
|
# ZfcConditionDetector will create its own ProviderFactory if needed
|
|
63
57
|
# Falls back to legacy pattern matching when ZFC is disabled
|
|
64
|
-
require_relative "zfc_condition_detector"
|
|
65
58
|
@condition_detector = ZfcConditionDetector.new(@configuration)
|
|
66
59
|
|
|
67
60
|
@user_interface = SimpleUserInterface.new
|
|
@@ -9,6 +9,17 @@ module Aidp
|
|
|
9
9
|
class StatusDisplay
|
|
10
10
|
include Aidp::MessageDisplay
|
|
11
11
|
|
|
12
|
+
# Expose state for testability
|
|
13
|
+
attr_accessor :current_step, :current_provider, :current_model
|
|
14
|
+
attr_accessor :start_time, :running
|
|
15
|
+
attr_accessor :performance_metrics, :error_summary
|
|
16
|
+
attr_accessor :provider_status, :token_usage, :circuit_breaker_status
|
|
17
|
+
attr_accessor :rate_limit_status, :recovery_status, :user_feedback_status
|
|
18
|
+
attr_accessor :work_completion_status, :display_config
|
|
19
|
+
attr_reader :status_formatter, :metrics_calculator, :alert_manager, :display_animator
|
|
20
|
+
# Internal status hash (separate from computed status_data method)
|
|
21
|
+
attr_accessor :internal_status_data
|
|
22
|
+
|
|
12
23
|
def initialize(provider_manager = nil, metrics_manager = nil, circuit_breaker_manager = nil, error_logger = nil, prompt: TTY::Prompt.new)
|
|
13
24
|
@provider_manager = provider_manager
|
|
14
25
|
@metrics_manager = metrics_manager
|
|
@@ -27,6 +38,7 @@ module Aidp
|
|
|
27
38
|
@update_interval = 2
|
|
28
39
|
@last_update = Time.now
|
|
29
40
|
@status_data = {}
|
|
41
|
+
@internal_status_data = @status_data # Alias for testability
|
|
30
42
|
@performance_metrics = {}
|
|
31
43
|
@error_summary = {}
|
|
32
44
|
@provider_status = {}
|
|
@@ -167,16 +179,24 @@ module Aidp
|
|
|
167
179
|
@error_summary[:last_updated] = Time.now
|
|
168
180
|
end
|
|
169
181
|
|
|
170
|
-
#
|
|
171
|
-
def display_mode(mode)
|
|
172
|
-
|
|
173
|
-
|
|
182
|
+
# Get or set display mode
|
|
183
|
+
def display_mode(mode = nil)
|
|
184
|
+
if mode.nil?
|
|
185
|
+
@display_mode
|
|
186
|
+
else
|
|
187
|
+
@display_mode = mode
|
|
188
|
+
@display_config[:mode] = mode
|
|
189
|
+
end
|
|
174
190
|
end
|
|
175
191
|
|
|
176
|
-
#
|
|
177
|
-
def update_interval(interval)
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
# Get or set update interval
|
|
193
|
+
def update_interval(interval = nil)
|
|
194
|
+
if interval.nil?
|
|
195
|
+
@update_interval
|
|
196
|
+
else
|
|
197
|
+
@update_interval = interval
|
|
198
|
+
@display_config[:update_interval] = interval
|
|
199
|
+
end
|
|
180
200
|
end
|
|
181
201
|
|
|
182
202
|
# Configure display settings
|
|
@@ -686,8 +706,6 @@ module Aidp
|
|
|
686
706
|
}
|
|
687
707
|
end
|
|
688
708
|
|
|
689
|
-
attr_reader :provider_status
|
|
690
|
-
|
|
691
709
|
def performance_status
|
|
692
710
|
@performance_metrics
|
|
693
711
|
end
|
|
@@ -696,20 +714,10 @@ module Aidp
|
|
|
696
714
|
@error_summary
|
|
697
715
|
end
|
|
698
716
|
|
|
699
|
-
attr_reader :circuit_breaker_status
|
|
700
|
-
|
|
701
717
|
def token_status
|
|
702
718
|
@token_usage
|
|
703
719
|
end
|
|
704
720
|
|
|
705
|
-
attr_reader :rate_limit_status
|
|
706
|
-
|
|
707
|
-
attr_reader :recovery_status
|
|
708
|
-
|
|
709
|
-
attr_reader :user_feedback_status
|
|
710
|
-
|
|
711
|
-
attr_reader :work_completion_status
|
|
712
|
-
|
|
713
721
|
def alerts
|
|
714
722
|
@alert_manager.active_alerts
|
|
715
723
|
end
|