aidp 0.34.0 → 0.39.3
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 +14 -14
- data/lib/aidp/agent_harness_adapter.rb +309 -0
- data/lib/aidp/cli/issue_importer.rb +20 -6
- data/lib/aidp/cli/jobs_command.rb +1 -1
- data/lib/aidp/cli/models_command.rb +9 -16
- data/lib/aidp/cli/prompts_command.rb +253 -0
- data/lib/aidp/cli/security_command.rb +4 -10
- data/lib/aidp/cli/storage_command.rb +277 -0
- data/lib/aidp/cli/temporal_command.rb +460 -0
- data/lib/aidp/cli.rb +24 -2
- data/lib/aidp/config.rb +15 -0
- data/lib/aidp/config_paths.rb +12 -2
- data/lib/aidp/database/migrations.rb +114 -0
- data/lib/aidp/database/repositories/checkpoint_repository.rb +174 -0
- data/lib/aidp/database/repositories/deprecated_models_repository.rb +206 -0
- data/lib/aidp/database/repositories/evaluation_repository.rb +208 -0
- data/lib/aidp/database/repositories/harness_state_repository.rb +140 -0
- data/lib/aidp/database/repositories/job_repository.rb +278 -0
- data/lib/aidp/database/repositories/model_cache_repository.rb +194 -0
- data/lib/aidp/database/repositories/progress_repository.rb +210 -0
- data/lib/aidp/database/repositories/prompt_archive_repository.rb +195 -0
- data/lib/aidp/database/repositories/prompt_feedback_repository.rb +266 -0
- data/lib/aidp/database/repositories/provider_info_cache_repository.rb +208 -0
- data/lib/aidp/database/repositories/provider_metrics_repository.rb +245 -0
- data/lib/aidp/database/repositories/secrets_repository.rb +187 -0
- data/lib/aidp/database/repositories/task_repository.rb +231 -0
- data/lib/aidp/database/repositories/template_version_repository.rb +383 -0
- data/lib/aidp/database/repositories/watch_state_repository.rb +472 -0
- data/lib/aidp/database/repositories/workstream_repository.rb +310 -0
- data/lib/aidp/database/repositories/worktree_repository.rb +240 -0
- data/lib/aidp/database/repository.rb +166 -0
- data/lib/aidp/database/schema.rb +347 -0
- data/lib/aidp/database/storage_migrator.rb +693 -0
- data/lib/aidp/database.rb +139 -0
- data/lib/aidp/debug_mixin.rb +2 -2
- data/lib/aidp/execute/checkpoint.rb +26 -0
- data/lib/aidp/execute/checkpoint_display.rb +16 -0
- data/lib/aidp/execute/prompt_evaluator.rb +30 -57
- data/lib/aidp/execute/work_loop_runner.rb +294 -46
- data/lib/aidp/firewall/provider_requirements_collector.rb +7 -23
- data/lib/aidp/harness/agent_harness_provider_manager.rb +275 -0
- data/lib/aidp/harness/ai_decision_engine.rb +78 -296
- data/lib/aidp/harness/config_schema.rb +59 -0
- data/lib/aidp/harness/configuration.rb +229 -10
- data/lib/aidp/harness/deprecation_cache.rb +53 -11
- data/lib/aidp/harness/enhanced_runner.rb +1 -1
- data/lib/aidp/harness/error_handler.rb +11 -5
- data/lib/aidp/harness/provider_config.rb +36 -0
- data/lib/aidp/harness/provider_factory.rb +26 -24
- data/lib/aidp/harness/provider_info.rb +9 -5
- data/lib/aidp/harness/provider_manager.rb +2 -2
- data/lib/aidp/harness/provider_metrics.rb +103 -1
- data/lib/aidp/harness/rspec_command_optimizer.rb +166 -0
- data/lib/aidp/harness/ruby_llm_registry.rb +97 -8
- data/lib/aidp/harness/runner.rb +7 -2
- data/lib/aidp/harness/state_manager.rb +1 -1
- data/lib/aidp/harness/test_runner.rb +167 -11
- data/lib/aidp/harness/thinking_depth_manager.rb +564 -5
- data/lib/aidp/harness/ui.rb +11 -0
- data/lib/aidp/harness/usage_limit.rb +179 -0
- data/lib/aidp/harness/usage_limit_enforcer.rb +240 -0
- data/lib/aidp/harness/usage_limit_tracker.rb +308 -0
- data/lib/aidp/harness/usage_period.rb +234 -0
- data/lib/aidp/init/agent_instructions_generator.rb +317 -0
- data/lib/aidp/init/runner.rb +25 -4
- data/lib/aidp/interfaces/activity_monitor_interface.rb +234 -0
- data/lib/aidp/interfaces/binary_checker_interface.rb +232 -0
- data/lib/aidp/interfaces/command_executor_interface.rb +216 -0
- data/lib/aidp/interfaces/logger_interface.rb +150 -0
- data/lib/aidp/interfaces/ui_interface.rb +254 -0
- data/lib/aidp/logger.rb +25 -7
- data/lib/aidp/orchestration_adapter.rb +279 -0
- data/lib/aidp/pr_worktree_manager.rb +4 -15
- data/lib/aidp/prompts/feedback_collector.rb +198 -0
- data/lib/aidp/prompts/prompt_template_manager.rb +415 -0
- data/lib/aidp/prompts/template_evolver.rb +305 -0
- data/lib/aidp/prompts/template_version_manager.rb +325 -0
- data/lib/aidp/setup/in_memory_config_adapter.rb +257 -0
- data/lib/aidp/setup/in_memory_config_manager.rb +262 -0
- data/lib/aidp/setup/wizard.rb +616 -176
- data/lib/aidp/shell_executor.rb +58 -0
- data/lib/aidp/style_guide/selector.rb +56 -1
- data/lib/aidp/temporal/activities/analyze_issue_activity.rb +198 -0
- data/lib/aidp/temporal/activities/analyze_sub_task_activity.rb +163 -0
- data/lib/aidp/temporal/activities/base_activity.rb +78 -0
- data/lib/aidp/temporal/activities/create_plan_activity.rb +115 -0
- data/lib/aidp/temporal/activities/create_pr_activity.rb +193 -0
- data/lib/aidp/temporal/activities/create_prompt_activity.rb +118 -0
- data/lib/aidp/temporal/activities/diagnose_failure_activity.rb +228 -0
- data/lib/aidp/temporal/activities/prepare_next_iteration_activity.rb +147 -0
- data/lib/aidp/temporal/activities/record_checkpoint_activity.rb +81 -0
- data/lib/aidp/temporal/activities/run_agent_activity.rb +139 -0
- data/lib/aidp/temporal/activities/run_tests_activity.rb +114 -0
- data/lib/aidp/temporal/activities/run_work_loop_iteration_activity.rb +249 -0
- data/lib/aidp/temporal/configuration.rb +169 -0
- data/lib/aidp/temporal/connection.rb +93 -0
- data/lib/aidp/temporal/worker.rb +119 -0
- data/lib/aidp/temporal/workflow_client.rb +171 -0
- data/lib/aidp/temporal/workflows/base_workflow.rb +73 -0
- data/lib/aidp/temporal/workflows/issue_to_pr_workflow.rb +278 -0
- data/lib/aidp/temporal/workflows/sub_issue_workflow.rb +253 -0
- data/lib/aidp/temporal/workflows/work_loop_workflow.rb +321 -0
- data/lib/aidp/temporal.rb +120 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/base_processor.rb +35 -0
- data/lib/aidp/watch/build_processor.rb +132 -0
- data/lib/aidp/watch/github_state_extractor.rb +0 -8
- data/lib/aidp/watch/rebase_processor.rb +245 -0
- data/lib/aidp/watch/round_robin_scheduler.rb +150 -0
- data/lib/aidp/watch/runner.rb +366 -285
- data/lib/aidp/watch/state_store.rb +80 -0
- data/lib/aidp/watch/work_item.rb +96 -0
- data/lib/aidp/watch/worktree_cleanup_job.rb +226 -0
- data/lib/aidp/watch/worktree_reconciler.rb +643 -0
- data/lib/aidp/workflows/guided_agent.rb +1 -1
- data/lib/aidp/worktree.rb +62 -0
- data/templates/aidp.yml.example +70 -0
- metadata +118 -16
- data/lib/aidp/analyze/json_file_storage.rb +0 -292
- data/lib/aidp/execute/future_work_backlog.rb +0 -411
- data/lib/aidp/providers/adapter.rb +0 -239
- data/lib/aidp/providers/aider.rb +0 -264
- data/lib/aidp/providers/anthropic.rb +0 -614
- data/lib/aidp/providers/base.rb +0 -617
- data/lib/aidp/providers/capability_registry.rb +0 -204
- data/lib/aidp/providers/codex.rb +0 -267
- data/lib/aidp/providers/cursor.rb +0 -304
- data/lib/aidp/providers/error_taxonomy.rb +0 -195
- data/lib/aidp/providers/gemini.rb +0 -110
- data/lib/aidp/providers/github_copilot.rb +0 -227
- data/lib/aidp/providers/kilocode.rb +0 -157
- data/lib/aidp/providers/opencode.rb +0 -139
|
@@ -4,18 +4,82 @@ require "open3"
|
|
|
4
4
|
require_relative "../tooling_detector"
|
|
5
5
|
require_relative "output_filter"
|
|
6
6
|
require_relative "output_filter_config"
|
|
7
|
+
require_relative "rspec_command_optimizer"
|
|
7
8
|
|
|
8
9
|
module Aidp
|
|
9
10
|
module Harness
|
|
10
11
|
# Executes test and linter commands configured in aidp.yml
|
|
11
12
|
# Returns results with exit status and output
|
|
12
13
|
# Applies intelligent output filtering to reduce token consumption
|
|
14
|
+
#
|
|
15
|
+
# Supports both legacy category-specific commands (test_commands, lint_commands, etc.)
|
|
16
|
+
# and the new generic commands array with run_after phases.
|
|
13
17
|
class TestRunner
|
|
14
18
|
def initialize(project_dir, config)
|
|
15
19
|
@project_dir = project_dir
|
|
16
20
|
@config = config
|
|
17
21
|
@iteration_count = 0
|
|
18
22
|
@filter_stats = {total_input_bytes: 0, total_output_bytes: 0}
|
|
23
|
+
@previous_iteration_had_test_failures = false
|
|
24
|
+
@rspec_optimizer = RSpecCommandOptimizer.new(project_dir)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Run all commands configured for a specific execution phase
|
|
28
|
+
# @param phase [Symbol] :each_unit, :full_loop, or :on_completion
|
|
29
|
+
# @return [Hash] Aggregated results with success status and outputs by command
|
|
30
|
+
def run_commands_for_phase(phase)
|
|
31
|
+
@iteration_count += 1
|
|
32
|
+
commands = @config.commands_for_phase(phase)
|
|
33
|
+
|
|
34
|
+
Aidp.log_debug("test_runner", "running_commands_for_phase",
|
|
35
|
+
phase: phase,
|
|
36
|
+
command_count: commands.length,
|
|
37
|
+
iteration: @iteration_count)
|
|
38
|
+
|
|
39
|
+
return empty_results if commands.empty?
|
|
40
|
+
|
|
41
|
+
results_by_command = {}
|
|
42
|
+
all_failures = []
|
|
43
|
+
required_failures = []
|
|
44
|
+
|
|
45
|
+
commands.each do |cmd_config|
|
|
46
|
+
result = execute_command(cmd_config[:command], cmd_config[:category].to_s)
|
|
47
|
+
result[:name] = cmd_config[:name]
|
|
48
|
+
result[:category] = cmd_config[:category]
|
|
49
|
+
result[:required] = cmd_config[:required]
|
|
50
|
+
|
|
51
|
+
results_by_command[cmd_config[:name]] = result
|
|
52
|
+
|
|
53
|
+
unless result[:success]
|
|
54
|
+
all_failures << result
|
|
55
|
+
required_failures << result if cmd_config[:required]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
success = required_failures.empty?
|
|
60
|
+
output = if all_failures.empty?
|
|
61
|
+
"All #{commands.length} commands passed"
|
|
62
|
+
else
|
|
63
|
+
format_phase_failures(all_failures, phase)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
{
|
|
67
|
+
success: success,
|
|
68
|
+
output: output,
|
|
69
|
+
failures: all_failures,
|
|
70
|
+
required_failures: required_failures,
|
|
71
|
+
results_by_command: results_by_command
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get all commands organized by phase
|
|
76
|
+
# @return [Hash] Commands grouped by run_after phase
|
|
77
|
+
def commands_by_phase
|
|
78
|
+
{
|
|
79
|
+
each_unit: @config.commands_for_phase(:each_unit),
|
|
80
|
+
full_loop: @config.commands_for_phase(:full_loop),
|
|
81
|
+
on_completion: @config.commands_for_phase(:on_completion)
|
|
82
|
+
}
|
|
19
83
|
end
|
|
20
84
|
|
|
21
85
|
# Run all configured tests
|
|
@@ -68,13 +132,44 @@ module Aidp
|
|
|
68
132
|
# Get filtering statistics
|
|
69
133
|
attr_reader :filter_stats
|
|
70
134
|
|
|
135
|
+
# Get RSpec command optimizer (for inspection/testing)
|
|
136
|
+
attr_reader :rspec_optimizer
|
|
137
|
+
|
|
138
|
+
# Track if previous iteration had test failures (for --only-failures optimization)
|
|
139
|
+
attr_reader :previous_iteration_had_test_failures
|
|
140
|
+
|
|
71
141
|
# Reset iteration counter (useful for testing)
|
|
72
142
|
def reset_iteration_count
|
|
73
143
|
@iteration_count = 0
|
|
144
|
+
@previous_iteration_had_test_failures = false
|
|
145
|
+
@rspec_optimizer.reset_caches!
|
|
74
146
|
end
|
|
75
147
|
|
|
76
148
|
private
|
|
77
149
|
|
|
150
|
+
# Return empty results structure
|
|
151
|
+
def empty_results
|
|
152
|
+
{success: true, output: "", failures: [], required_failures: [], results_by_command: {}}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Format failures for phase-based execution
|
|
156
|
+
def format_phase_failures(failures, phase)
|
|
157
|
+
output = ["#{phase.to_s.tr("_", " ").capitalize} Phase Failures:", ""]
|
|
158
|
+
|
|
159
|
+
failures.each do |failure|
|
|
160
|
+
required_label = failure[:required] ? "[REQUIRED]" : "[OPTIONAL]"
|
|
161
|
+
output << "#{required_label} #{failure[:name]} (#{failure[:category]})"
|
|
162
|
+
output << "Command: #{failure[:command]}"
|
|
163
|
+
output << "Exit Code: #{failure[:exit_code]}"
|
|
164
|
+
output << "--- Output ---"
|
|
165
|
+
output << failure[:stdout] unless failure[:stdout].to_s.strip.empty?
|
|
166
|
+
output << failure[:stderr] unless failure[:stderr].to_s.strip.empty?
|
|
167
|
+
output << ""
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
output.join("\n")
|
|
171
|
+
end
|
|
172
|
+
|
|
78
173
|
# Run commands for a specific category (test, lint, formatter, build, documentation)
|
|
79
174
|
def run_command_category(category, display_name)
|
|
80
175
|
commands = resolved_commands(category)
|
|
@@ -85,54 +180,115 @@ module Aidp
|
|
|
85
180
|
# Determine output mode based on category
|
|
86
181
|
mode = determine_output_mode(category)
|
|
87
182
|
|
|
183
|
+
# Enable RSpec optimization for test commands
|
|
184
|
+
optimize_rspec = (category == :test)
|
|
185
|
+
|
|
88
186
|
Aidp.log_debug("test_runner", "running_category",
|
|
89
187
|
category: category,
|
|
90
188
|
command_count: commands.length,
|
|
91
189
|
iteration: @iteration_count,
|
|
92
|
-
output_mode: mode
|
|
190
|
+
output_mode: mode,
|
|
191
|
+
optimize_rspec: optimize_rspec,
|
|
192
|
+
previous_had_failures: @previous_iteration_had_test_failures)
|
|
93
193
|
|
|
94
194
|
# Execute all commands
|
|
95
195
|
results = commands.map do |cmd_config|
|
|
96
196
|
# Handle both string commands (legacy) and hash format (new)
|
|
97
197
|
if cmd_config.is_a?(String)
|
|
98
|
-
result = execute_command(cmd_config, category.to_s)
|
|
198
|
+
result = execute_command(cmd_config, category.to_s, optimize_rspec: optimize_rspec)
|
|
99
199
|
result.merge(required: true)
|
|
100
200
|
else
|
|
101
|
-
result = execute_command(cmd_config[:command], category.to_s)
|
|
201
|
+
result = execute_command(cmd_config[:command], category.to_s, optimize_rspec: optimize_rspec)
|
|
102
202
|
result.merge(required: cmd_config[:required])
|
|
103
203
|
end
|
|
104
204
|
end
|
|
105
205
|
|
|
106
|
-
aggregate_results(results, display_name, mode: mode)
|
|
206
|
+
aggregated = aggregate_results(results, display_name, mode: mode)
|
|
207
|
+
|
|
208
|
+
# Track test failures for next iteration's --only-failures optimization
|
|
209
|
+
if category == :test
|
|
210
|
+
@previous_iteration_had_test_failures = !aggregated[:success]
|
|
211
|
+
@rspec_optimizer.reset_caches! if aggregated[:success]
|
|
212
|
+
|
|
213
|
+
Aidp.log_debug("test_runner", "test_failure_tracking",
|
|
214
|
+
iteration: @iteration_count,
|
|
215
|
+
had_failures: @previous_iteration_had_test_failures,
|
|
216
|
+
failure_count: aggregated[:failures]&.length || 0)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
aggregated
|
|
107
220
|
rescue NameError
|
|
108
221
|
# Logging not available
|
|
109
222
|
commands = resolved_commands(category)
|
|
110
223
|
return {success: true, output: "", failures: [], required_failures: []} if commands.empty?
|
|
111
224
|
|
|
225
|
+
optimize_rspec = (category == :test)
|
|
112
226
|
mode = determine_output_mode(category)
|
|
113
227
|
results = commands.map do |cmd_config|
|
|
114
228
|
if cmd_config.is_a?(String)
|
|
115
|
-
result = execute_command(cmd_config, category.to_s)
|
|
229
|
+
result = execute_command(cmd_config, category.to_s, optimize_rspec: optimize_rspec)
|
|
116
230
|
result.merge(required: true)
|
|
117
231
|
else
|
|
118
|
-
result = execute_command(cmd_config[:command], category.to_s)
|
|
232
|
+
result = execute_command(cmd_config[:command], category.to_s, optimize_rspec: optimize_rspec)
|
|
119
233
|
result.merge(required: cmd_config[:required])
|
|
120
234
|
end
|
|
121
235
|
end
|
|
122
236
|
|
|
123
|
-
aggregate_results(results, display_name, mode: mode)
|
|
237
|
+
aggregated = aggregate_results(results, display_name, mode: mode)
|
|
238
|
+
|
|
239
|
+
# Track test failures for next iteration (without logging)
|
|
240
|
+
if category == :test
|
|
241
|
+
@previous_iteration_had_test_failures = !aggregated[:success]
|
|
242
|
+
@rspec_optimizer.reset_caches! if aggregated[:success]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
aggregated
|
|
124
246
|
end
|
|
125
247
|
|
|
126
|
-
def execute_command(command, type)
|
|
127
|
-
|
|
248
|
+
def execute_command(command, type, optimize_rspec: false)
|
|
249
|
+
actual_command = command
|
|
250
|
+
optimization_info = nil
|
|
251
|
+
|
|
252
|
+
# Apply RSpec --only-failures optimization for test commands on subsequent iterations
|
|
253
|
+
if optimize_rspec && type == "test"
|
|
254
|
+
optimization_info = @rspec_optimizer.optimize_command(
|
|
255
|
+
command,
|
|
256
|
+
iteration: @iteration_count,
|
|
257
|
+
had_failures: @previous_iteration_had_test_failures
|
|
258
|
+
)
|
|
259
|
+
actual_command = optimization_info[:command]
|
|
260
|
+
|
|
261
|
+
if optimization_info[:optimized]
|
|
262
|
+
Aidp.log_info("test_runner", "rspec_optimized",
|
|
263
|
+
original: command,
|
|
264
|
+
optimized: actual_command,
|
|
265
|
+
iteration: @iteration_count,
|
|
266
|
+
reason: optimization_info[:reason])
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
stdout, stderr, status = Open3.capture3(actual_command, chdir: @project_dir)
|
|
271
|
+
|
|
272
|
+
# Handle special case: --only-failures with no failures to rerun
|
|
273
|
+
# RSpec exits with 0 and says "All examples were filtered out"
|
|
274
|
+
if optimization_info&.dig(:optimized) && status.success? && stdout.include?("All examples were filtered out")
|
|
275
|
+
Aidp.log_info("test_runner", "rspec_only_failures_empty",
|
|
276
|
+
message: "No failures to rerun, running full suite")
|
|
277
|
+
|
|
278
|
+
# Fall back to full RSpec run
|
|
279
|
+
stdout, stderr, status = Open3.capture3(command, chdir: @project_dir)
|
|
280
|
+
actual_command = command
|
|
281
|
+
end
|
|
128
282
|
|
|
129
283
|
{
|
|
130
|
-
command:
|
|
284
|
+
command: actual_command,
|
|
285
|
+
original_command: command,
|
|
131
286
|
type: type,
|
|
132
287
|
success: status.success?,
|
|
133
288
|
exit_code: status.exitstatus,
|
|
134
289
|
stdout: stdout,
|
|
135
|
-
stderr: stderr
|
|
290
|
+
stderr: stderr,
|
|
291
|
+
rspec_optimized: optimization_info&.dig(:optimized) || false
|
|
136
292
|
}
|
|
137
293
|
end
|
|
138
294
|
|