aidp 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +194 -25
- data/lib/aidp/analyze/kb_inspector.rb +2 -15
- data/lib/aidp/analyze/progress.rb +2 -1
- data/lib/aidp/analyze/ruby_maat_integration.rb +2 -15
- data/lib/aidp/analyze/runner.rb +64 -20
- data/lib/aidp/analyze/steps.rb +10 -8
- data/lib/aidp/analyze/tree_sitter_grammar_loader.rb +2 -13
- data/lib/aidp/analyze/tree_sitter_scan.rb +2 -13
- data/lib/aidp/cli/checkpoint_command.rb +98 -0
- data/lib/aidp/cli/first_run_wizard.rb +65 -94
- data/lib/aidp/cli/jobs_command.rb +249 -34
- data/lib/aidp/cli/mcp_dashboard.rb +205 -0
- data/lib/aidp/cli.rb +517 -43
- 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 +53 -24
- 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 +26 -17
- 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 +22 -1
- data/lib/aidp/harness/error_handler.rb +103 -28
- data/lib/aidp/harness/provider_factory.rb +4 -1
- data/lib/aidp/harness/provider_info.rb +366 -0
- data/lib/aidp/harness/provider_manager.rb +250 -15
- data/lib/aidp/harness/runner.rb +3 -14
- data/lib/aidp/harness/simple_user_interface.rb +2 -15
- data/lib/aidp/harness/status_display.rb +12 -17
- data/lib/aidp/harness/test_runner.rb +83 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +2 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +44 -5
- data/lib/aidp/harness/ui/error_handler.rb +4 -0
- data/lib/aidp/harness/ui/frame_manager.rb +10 -8
- data/lib/aidp/harness/ui/job_monitor.rb +2 -0
- data/lib/aidp/harness/ui/navigation/main_menu.rb +4 -2
- 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 +8 -12
- 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 +3 -1
- data/lib/aidp/harness/ui/workflow_controller.rb +2 -0
- data/lib/aidp/harness/user_interface.rb +12 -17
- data/lib/aidp/jobs/background_runner.rb +278 -0
- data/lib/aidp/message_display.rb +48 -0
- data/lib/aidp/provider_manager.rb +3 -1
- data/lib/aidp/providers/anthropic.rb +100 -17
- data/lib/aidp/providers/base.rb +42 -11
- data/lib/aidp/providers/codex.rb +248 -0
- data/lib/aidp/providers/cursor.rb +35 -42
- data/lib/aidp/providers/gemini.rb +25 -15
- data/lib/aidp/providers/github_copilot.rb +41 -42
- data/lib/aidp/providers/opencode.rb +34 -41
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/definitions.rb +357 -0
- data/lib/aidp/workflows/guided_agent.rb +400 -0
- data/lib/aidp/workflows/selector.rb +171 -0
- data/lib/aidp.rb +12 -0
- data/templates/planning/generate_llm_style_guide.md +119 -0
- metadata +41 -26
- /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
|
@@ -366,6 +366,46 @@ module Aidp
|
|
|
366
366
|
enum: ["provider_model", "provider", "model", "none"]
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
|
+
},
|
|
370
|
+
work_loop: {
|
|
371
|
+
type: :hash,
|
|
372
|
+
required: false,
|
|
373
|
+
default: {
|
|
374
|
+
enabled: true,
|
|
375
|
+
max_iterations: 50,
|
|
376
|
+
test_commands: [],
|
|
377
|
+
lint_commands: []
|
|
378
|
+
},
|
|
379
|
+
properties: {
|
|
380
|
+
enabled: {
|
|
381
|
+
type: :boolean,
|
|
382
|
+
required: false,
|
|
383
|
+
default: true
|
|
384
|
+
},
|
|
385
|
+
max_iterations: {
|
|
386
|
+
type: :integer,
|
|
387
|
+
required: false,
|
|
388
|
+
default: 50,
|
|
389
|
+
min: 1,
|
|
390
|
+
max: 200
|
|
391
|
+
},
|
|
392
|
+
test_commands: {
|
|
393
|
+
type: :array,
|
|
394
|
+
required: false,
|
|
395
|
+
default: [],
|
|
396
|
+
items: {
|
|
397
|
+
type: :string
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
lint_commands: {
|
|
401
|
+
type: :array,
|
|
402
|
+
required: false,
|
|
403
|
+
default: [],
|
|
404
|
+
items: {
|
|
405
|
+
type: :string
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
369
409
|
}
|
|
370
410
|
}
|
|
371
411
|
},
|
|
@@ -76,8 +76,9 @@ module Aidp
|
|
|
76
76
|
return false if config_exists?
|
|
77
77
|
|
|
78
78
|
example_config = ConfigSchema.generate_example
|
|
79
|
-
config_path = File.join(@project_dir, "aidp.yml")
|
|
79
|
+
config_path = File.join(@project_dir, ".aidp", "aidp.yml")
|
|
80
80
|
|
|
81
|
+
FileUtils.mkdir_p(File.dirname(config_path))
|
|
81
82
|
File.write(config_path, YAML.dump(example_config))
|
|
82
83
|
true
|
|
83
84
|
end
|
|
@@ -243,14 +244,10 @@ module Aidp
|
|
|
243
244
|
private
|
|
244
245
|
|
|
245
246
|
def find_config_file
|
|
246
|
-
|
|
247
|
-
config_file = File.join(@project_dir, "aidp.yml")
|
|
248
|
-
legacy_config_file = File.join(@project_dir, ".aidp.yml")
|
|
247
|
+
config_file = File.join(@project_dir, ".aidp", "aidp.yml")
|
|
249
248
|
|
|
250
249
|
if File.exist?(config_file)
|
|
251
250
|
config_file
|
|
252
|
-
elsif File.exist?(legacy_config_file)
|
|
253
|
-
legacy_config_file
|
|
254
251
|
end
|
|
255
252
|
end
|
|
256
253
|
|
|
@@ -144,6 +144,31 @@ module Aidp
|
|
|
144
144
|
harness_config[:session] || get_default_session_config
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
+
# Get work loop configuration
|
|
148
|
+
def work_loop_config
|
|
149
|
+
harness_config[:work_loop] || get_default_work_loop_config
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Check if work loops are enabled
|
|
153
|
+
def work_loop_enabled?
|
|
154
|
+
work_loop_config[:enabled]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Get maximum iterations for work loops
|
|
158
|
+
def work_loop_max_iterations
|
|
159
|
+
work_loop_config[:max_iterations]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Get test commands
|
|
163
|
+
def test_commands
|
|
164
|
+
work_loop_config[:test_commands] || []
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Get lint commands
|
|
168
|
+
def lint_commands
|
|
169
|
+
work_loop_config[:lint_commands] || []
|
|
170
|
+
end
|
|
171
|
+
|
|
147
172
|
# Get provider priority
|
|
148
173
|
def provider_priority(provider_name)
|
|
149
174
|
provider_config(provider_name)[:priority] || 0
|
|
@@ -186,7 +211,7 @@ module Aidp
|
|
|
186
211
|
|
|
187
212
|
# Get configuration path
|
|
188
213
|
def config_path
|
|
189
|
-
File.join(@project_dir, "aidp.yml")
|
|
214
|
+
File.join(@project_dir, ".aidp", "aidp.yml")
|
|
190
215
|
end
|
|
191
216
|
|
|
192
217
|
# Get logging configuration
|
|
@@ -416,6 +441,15 @@ module Aidp
|
|
|
416
441
|
}
|
|
417
442
|
end
|
|
418
443
|
|
|
444
|
+
def get_default_work_loop_config
|
|
445
|
+
{
|
|
446
|
+
enabled: true,
|
|
447
|
+
max_iterations: 50,
|
|
448
|
+
test_commands: [],
|
|
449
|
+
lint_commands: []
|
|
450
|
+
}
|
|
451
|
+
end
|
|
452
|
+
|
|
419
453
|
def get_default_logging_config
|
|
420
454
|
{
|
|
421
455
|
log_level: :info,
|
|
@@ -31,7 +31,7 @@ module Aidp
|
|
|
31
31
|
@current_step = nil
|
|
32
32
|
@current_provider = nil
|
|
33
33
|
@user_input = options[:user_input] || {}
|
|
34
|
-
@user_input = {} if @user_input.nil?
|
|
34
|
+
@user_input = {} if @user_input.nil? # Ensure it's never nil
|
|
35
35
|
@execution_log = []
|
|
36
36
|
|
|
37
37
|
# Store workflow configuration
|
|
@@ -55,6 +55,27 @@ module Aidp
|
|
|
55
55
|
@completion_checker = CompletionChecker.new(@project_dir, @workflow_type)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# Get current provider (delegate to provider manager)
|
|
59
|
+
def current_provider
|
|
60
|
+
@current_provider || @provider_manager&.current_provider || "unknown"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Get current step
|
|
64
|
+
attr_reader :current_step
|
|
65
|
+
|
|
66
|
+
# Get user input
|
|
67
|
+
def user_input
|
|
68
|
+
@user_input || {}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Get execution log
|
|
72
|
+
def execution_log
|
|
73
|
+
@execution_log || []
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Get provider manager
|
|
77
|
+
attr_reader :provider_manager
|
|
78
|
+
|
|
58
79
|
# Main execution method with enhanced TUI
|
|
59
80
|
def run
|
|
60
81
|
@state = STATES[:running]
|
|
@@ -69,6 +69,17 @@ module Aidp
|
|
|
69
69
|
error_type: error_info[:error_type],
|
|
70
70
|
reason: "Retry not applicable or exhausted"
|
|
71
71
|
})
|
|
72
|
+
if [:authentication, :permission_denied].include?(error_info[:error_type].to_sym)
|
|
73
|
+
# Mark provider unhealthy to avoid immediate re-selection
|
|
74
|
+
begin
|
|
75
|
+
if @provider_manager.respond_to?(:mark_provider_auth_failure)
|
|
76
|
+
@provider_manager.mark_provider_auth_failure(error_info[:provider])
|
|
77
|
+
debug_log("🔐 Marked provider #{error_info[:provider]} unhealthy due to auth error", level: :warn)
|
|
78
|
+
end
|
|
79
|
+
rescue => e
|
|
80
|
+
debug_log("⚠️ Failed to mark provider unhealthy after auth error", level: :warn, data: {error: e.message})
|
|
81
|
+
end
|
|
82
|
+
end
|
|
72
83
|
attempt_recovery(error_info, context)
|
|
73
84
|
|
|
74
85
|
end
|
|
@@ -76,35 +87,75 @@ module Aidp
|
|
|
76
87
|
|
|
77
88
|
# Execute a block with retry logic
|
|
78
89
|
def execute_with_retry(&block)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
attempt
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
providers_tried = []
|
|
91
|
+
|
|
92
|
+
loop do
|
|
93
|
+
max_attempts = @configuration.max_retries + 1
|
|
94
|
+
attempt = 0
|
|
95
|
+
|
|
96
|
+
begin
|
|
97
|
+
attempt += 1
|
|
98
|
+
return yield
|
|
99
|
+
rescue => error
|
|
100
|
+
current_provider = get_current_provider_safely
|
|
101
|
+
|
|
102
|
+
if attempt < max_attempts
|
|
103
|
+
error_info = {
|
|
104
|
+
error: error,
|
|
105
|
+
provider: current_provider,
|
|
106
|
+
model: get_current_model_safely,
|
|
107
|
+
error_type: @error_classifier.classify_error(error)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
strategy = get_retry_strategy(error_info[:error_type])
|
|
111
|
+
if should_retry?(error_info, strategy)
|
|
112
|
+
delay = @backoff_calculator.calculate_delay(attempt, strategy[:backoff_strategy] || :exponential, 1, 10)
|
|
113
|
+
debug_log("🔁 Retry attempt #{attempt} for #{current_provider}", level: :info, data: {delay: delay, error_type: error_info[:error_type]})
|
|
114
|
+
sleep(delay) if delay > 0
|
|
115
|
+
retry
|
|
116
|
+
end
|
|
117
|
+
end
|
|
93
118
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
119
|
+
# Provider exhausted – attempt recovery (may switch provider)
|
|
120
|
+
debug_log("🚫 Exhausted retries for provider, attempting recovery", level: :warn, data: {provider: current_provider, attempt: attempt, max_attempts: max_attempts})
|
|
121
|
+
handle_error(error, {
|
|
122
|
+
provider: current_provider,
|
|
123
|
+
model: get_current_model_safely,
|
|
124
|
+
exhausted_retries: true
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
new_provider = get_current_provider_safely
|
|
128
|
+
if new_provider != current_provider && !providers_tried.include?(new_provider)
|
|
129
|
+
providers_tried << current_provider
|
|
130
|
+
# Reset retry counts for the new provider
|
|
131
|
+
begin
|
|
132
|
+
reset_retry_counts(new_provider)
|
|
133
|
+
rescue => e
|
|
134
|
+
debug_log("⚠️ Failed to reset retry counts for new provider", level: :warn, data: {error: e.message})
|
|
135
|
+
end
|
|
136
|
+
debug_log("🔀 Switched provider after failure – re-executing block", level: :info, data: {from: current_provider, to: new_provider})
|
|
137
|
+
# Start retry loop fresh for new provider
|
|
138
|
+
next
|
|
100
139
|
end
|
|
101
|
-
end
|
|
102
140
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
# No new provider (or already tried) – return structured failure
|
|
142
|
+
debug_log("❌ No fallback provider available or all tried", level: :error, data: {providers_tried: providers_tried})
|
|
143
|
+
begin
|
|
144
|
+
if @provider_manager.respond_to?(:mark_provider_failure_exhausted)
|
|
145
|
+
@provider_manager.mark_provider_failure_exhausted(current_provider)
|
|
146
|
+
debug_log("🛑 Marked provider #{current_provider} unhealthy due to exhausted retries", level: :warn)
|
|
147
|
+
end
|
|
148
|
+
rescue => e
|
|
149
|
+
debug_log("⚠️ Failed to mark provider failure-exhausted", level: :warn, data: {error: e.message})
|
|
150
|
+
end
|
|
151
|
+
return {
|
|
152
|
+
status: "failed",
|
|
153
|
+
error: error,
|
|
154
|
+
message: error.message,
|
|
155
|
+
provider: current_provider,
|
|
156
|
+
providers_tried: providers_tried.dup
|
|
157
|
+
}
|
|
158
|
+
end
|
|
108
159
|
end
|
|
109
160
|
end
|
|
110
161
|
|
|
@@ -579,9 +630,12 @@ module Aidp
|
|
|
579
630
|
priority: :high
|
|
580
631
|
}
|
|
581
632
|
when :authentication, :permission_denied
|
|
633
|
+
# Previously we escalated immediately. Instead, attempt a provider switch
|
|
634
|
+
# so workflows can continue with alternate providers (e.g., Gemini, Cursor)
|
|
635
|
+
# while the user resolves credentials for the failing provider.
|
|
582
636
|
{
|
|
583
|
-
action: :
|
|
584
|
-
reason: "Authentication
|
|
637
|
+
action: :switch_provider,
|
|
638
|
+
reason: "Authentication/permission issue – switching provider to continue",
|
|
585
639
|
priority: :critical
|
|
586
640
|
}
|
|
587
641
|
when :timeout
|
|
@@ -611,6 +665,27 @@ module Aidp
|
|
|
611
665
|
end
|
|
612
666
|
end
|
|
613
667
|
end
|
|
668
|
+
|
|
669
|
+
# Safe access to provider manager methods that may not exist
|
|
670
|
+
def get_current_provider_safely
|
|
671
|
+
return "unknown" unless @provider_manager
|
|
672
|
+
return "unknown" unless @provider_manager.respond_to?(:current_provider)
|
|
673
|
+
|
|
674
|
+
@provider_manager.current_provider || "unknown"
|
|
675
|
+
rescue => e
|
|
676
|
+
debug_log("⚠️ Failed to get current provider", level: :warn, data: {error: e.message})
|
|
677
|
+
"unknown"
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
def get_current_model_safely
|
|
681
|
+
return "unknown" unless @provider_manager
|
|
682
|
+
return "unknown" unless @provider_manager.respond_to?(:current_model)
|
|
683
|
+
|
|
684
|
+
@provider_manager.current_model || "unknown"
|
|
685
|
+
rescue => e
|
|
686
|
+
debug_log("⚠️ Failed to get current model", level: :warn, data: {error: e.message})
|
|
687
|
+
"unknown"
|
|
688
|
+
end
|
|
614
689
|
end
|
|
615
690
|
end
|
|
616
691
|
end
|
|
@@ -8,6 +8,7 @@ require_relative "../providers/gemini"
|
|
|
8
8
|
require_relative "../providers/macos_ui"
|
|
9
9
|
require_relative "../providers/opencode"
|
|
10
10
|
require_relative "../providers/github_copilot"
|
|
11
|
+
require_relative "../providers/codex"
|
|
11
12
|
|
|
12
13
|
module Aidp
|
|
13
14
|
module Harness
|
|
@@ -16,10 +17,12 @@ module Aidp
|
|
|
16
17
|
PROVIDER_CLASSES = {
|
|
17
18
|
"cursor" => Aidp::Providers::Cursor,
|
|
18
19
|
"anthropic" => Aidp::Providers::Anthropic,
|
|
20
|
+
"claude" => Aidp::Providers::Anthropic,
|
|
19
21
|
"gemini" => Aidp::Providers::Gemini,
|
|
20
22
|
"macos" => Aidp::Providers::MacOSUI,
|
|
21
23
|
"opencode" => Aidp::Providers::Opencode,
|
|
22
|
-
"github_copilot" => Aidp::Providers::GithubCopilot
|
|
24
|
+
"github_copilot" => Aidp::Providers::GithubCopilot,
|
|
25
|
+
"codex" => Aidp::Providers::Codex
|
|
23
26
|
}.freeze
|
|
24
27
|
|
|
25
28
|
def initialize(config_manager = nil)
|