aidp 0.49.11 → 0.49.13
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/lib/aidp/harness/ai_filter_factory.rb +4 -5
- data/lib/aidp/harness/test_runner.rb +24 -6
- data/lib/aidp/shell_executor.rb +32 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +9 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5840a5dd1754c05dcb6fb0c8d2b96fecf2a093896caf19704d80397ad97f829c
|
|
4
|
+
data.tar.gz: '008354478b95ae1e16b8064ae0485c44aa930edec611e0b0aaa1a04da18ccaca'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a3ca1a4fc8923f0599a85ea630a0d39e429790c1a718891e40e5e56d4d5a9170c72e03bf2d083567686e168391897dc15b8a3e4fc28c83569cb6aa0b2f7bac7
|
|
7
|
+
data.tar.gz: beb27cca39345af8ed6f546bd284ab1a90dd0b52336479cfe4399a1166ba70aa826f4108556ddbc33522de2a40033dff9791652a7d253043de4a5741cd441114
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require_relative "../shell_executor"
|
|
4
5
|
require_relative "filter_definition"
|
|
5
6
|
require_relative "provider_factory"
|
|
6
7
|
require_relative "thinking_depth_manager"
|
|
@@ -264,13 +265,11 @@ module Aidp
|
|
|
264
265
|
end
|
|
265
266
|
|
|
266
267
|
def capture_sample_output(command, project_dir)
|
|
267
|
-
# Run command and capture output
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
stdout, stderr, _ = Open3.capture3(command, chdir: project_dir)
|
|
268
|
+
# Run command without shell interpretation and capture output
|
|
269
|
+
result = ShellExecutor.new.run_line(command, chdir: project_dir)
|
|
271
270
|
|
|
272
271
|
# Combine stdout and stderr for analysis
|
|
273
|
-
output = stdout + stderr
|
|
272
|
+
output = result.stdout + result.stderr
|
|
274
273
|
output.empty? ? nil : output
|
|
275
274
|
rescue => e
|
|
276
275
|
Aidp.log_debug("ai_filter_factory", "Failed to capture sample output",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "open3"
|
|
4
3
|
require_relative "../tooling_detector"
|
|
4
|
+
require_relative "../shell_executor"
|
|
5
5
|
require_relative "output_filter"
|
|
6
6
|
require_relative "output_filter_config"
|
|
7
7
|
require_relative "rspec_command_optimizer"
|
|
@@ -267,16 +267,16 @@ module Aidp
|
|
|
267
267
|
end
|
|
268
268
|
end
|
|
269
269
|
|
|
270
|
-
stdout, stderr,
|
|
270
|
+
stdout, stderr, result = execute_command_line(actual_command)
|
|
271
271
|
|
|
272
272
|
# Handle special case: --only-failures with no failures to rerun
|
|
273
273
|
# RSpec exits with 0 and says "All examples were filtered out"
|
|
274
|
-
if optimization_info&.dig(:optimized) &&
|
|
274
|
+
if optimization_info&.dig(:optimized) && result.success? && stdout.include?("All examples were filtered out")
|
|
275
275
|
Aidp.log_info("test_runner", "rspec_only_failures_empty",
|
|
276
276
|
message: "No failures to rerun, running full suite")
|
|
277
277
|
|
|
278
278
|
# Fall back to full RSpec run
|
|
279
|
-
stdout, stderr,
|
|
279
|
+
stdout, stderr, result = execute_command_line(command)
|
|
280
280
|
actual_command = command
|
|
281
281
|
end
|
|
282
282
|
|
|
@@ -284,14 +284,32 @@ module Aidp
|
|
|
284
284
|
command: actual_command,
|
|
285
285
|
original_command: command,
|
|
286
286
|
type: type,
|
|
287
|
-
success:
|
|
288
|
-
exit_code:
|
|
287
|
+
success: result.success?,
|
|
288
|
+
exit_code: result.exit_status,
|
|
289
289
|
stdout: stdout,
|
|
290
290
|
stderr: stderr,
|
|
291
291
|
rspec_optimized: optimization_info&.dig(:optimized) || false
|
|
292
292
|
}
|
|
293
293
|
end
|
|
294
294
|
|
|
295
|
+
# Execute a configured command line without shell interpretation so
|
|
296
|
+
# shell metacharacters in configuration values are treated as data.
|
|
297
|
+
# Execution failures (missing executables, rejected shell operators)
|
|
298
|
+
# are reported as a failed command rather than raised, so a bad
|
|
299
|
+
# aidp.yml entry surfaces as a failed check instead of crashing the
|
|
300
|
+
# work loop.
|
|
301
|
+
def execute_command_line(command)
|
|
302
|
+
result = command_runner.run_line(command, chdir: @project_dir)
|
|
303
|
+
[result.stdout, result.stderr, result]
|
|
304
|
+
rescue ArgumentError, Errno::ENOENT => e
|
|
305
|
+
result = ShellExecutor::Result.new(stdout: "", stderr: e.message, exit_status: 1)
|
|
306
|
+
[result.stdout, result.stderr, result]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def command_runner
|
|
310
|
+
@command_runner ||= ShellExecutor.new
|
|
311
|
+
end
|
|
312
|
+
|
|
295
313
|
def aggregate_results(results, category, mode: :full)
|
|
296
314
|
# Separate required and optional command failures
|
|
297
315
|
all_failures = results.reject { |r| r[:success] }
|
data/lib/aidp/shell_executor.rb
CHANGED
|
@@ -67,6 +67,38 @@ module Aidp
|
|
|
67
67
|
Result.new(stdout: stdout, stderr: stderr, exit_status: status.exitstatus)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
# Run a command line without shell interpretation and capture its output
|
|
71
|
+
#
|
|
72
|
+
# The line is tokenized with Shellwords, so quoting in the command
|
|
73
|
+
# string is honored as argument boundaries, but the resulting argv is
|
|
74
|
+
# passed directly to the operating system. Shell metacharacters
|
|
75
|
+
# (operators, redirections, substitutions) are never interpreted,
|
|
76
|
+
# which makes this safe for command lines built from untrusted input.
|
|
77
|
+
#
|
|
78
|
+
# @param command [String] the command line to run
|
|
79
|
+
# @param opts [Hash] options forwarded to Open3.capture3 (e.g. chdir:)
|
|
80
|
+
# @return [Result] captured stdout/stderr with the exit status
|
|
81
|
+
# @raise [ArgumentError] when the command line is blank, has
|
|
82
|
+
# unbalanced quotes, or uses shell operators/redirections
|
|
83
|
+
def run_line(command, **opts)
|
|
84
|
+
require "open3"
|
|
85
|
+
require "shellwords"
|
|
86
|
+
argv = Shellwords.split(command.to_s)
|
|
87
|
+
raise ArgumentError, "command must not be blank" if argv.empty?
|
|
88
|
+
|
|
89
|
+
# Operator tokens signal an intent to use shell features, which are
|
|
90
|
+
# intentionally unsupported here; reject them loudly rather than
|
|
91
|
+
# running them as literal arguments.
|
|
92
|
+
if argv.any? { |token| %w[&& || ; |].include?(token) || token.match?(/^[<>&]/) }
|
|
93
|
+
raise ArgumentError,
|
|
94
|
+
"shell operators are not supported in configured commands; " \
|
|
95
|
+
"split into separate commands instead: #{command.inspect}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
stdout, stderr, status = Open3.capture3(*argv, **opts)
|
|
99
|
+
Result.new(stdout: stdout, stderr: stderr, exit_status: status.exitstatus)
|
|
100
|
+
end
|
|
101
|
+
|
|
70
102
|
# Run a command via system(), optionally suppressing output
|
|
71
103
|
#
|
|
72
104
|
# When suppress_output is true, output is redirected to /dev/null
|
data/lib/aidp/version.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative "../message_display"
|
|
|
8
8
|
require_relative "../execute/prompt_manager"
|
|
9
9
|
require_relative "../harness/runner"
|
|
10
10
|
require_relative "../harness/state_manager"
|
|
11
|
+
require_relative "../shell_executor"
|
|
11
12
|
require_relative "../worktree"
|
|
12
13
|
require_relative "../execute/progress"
|
|
13
14
|
require_relative "github_state_extractor"
|
|
@@ -1125,8 +1126,7 @@ module Aidp
|
|
|
1125
1126
|
next if command.nil? || command.empty?
|
|
1126
1127
|
|
|
1127
1128
|
Aidp.log_debug("build_processor", "quick_validation_running_test", command: command)
|
|
1128
|
-
|
|
1129
|
-
unless status.success?
|
|
1129
|
+
unless quick_validation_runner.run_line(command).success?
|
|
1130
1130
|
Aidp.log_debug("build_processor", "quick_validation_test_failed", command: command)
|
|
1131
1131
|
return false
|
|
1132
1132
|
end
|
|
@@ -1141,8 +1141,7 @@ module Aidp
|
|
|
1141
1141
|
next if command.nil? || command.empty?
|
|
1142
1142
|
|
|
1143
1143
|
Aidp.log_debug("build_processor", "quick_validation_running_lint", command: command)
|
|
1144
|
-
|
|
1145
|
-
unless status.success?
|
|
1144
|
+
unless quick_validation_runner.run_line(command).success?
|
|
1146
1145
|
Aidp.log_debug("build_processor", "quick_validation_lint_failed", command: command)
|
|
1147
1146
|
return false
|
|
1148
1147
|
end
|
|
@@ -1155,6 +1154,12 @@ module Aidp
|
|
|
1155
1154
|
Aidp.log_warn("build_processor", "quick_validation_error", error: e.message)
|
|
1156
1155
|
false
|
|
1157
1156
|
end
|
|
1157
|
+
|
|
1158
|
+
# Commands come from project configuration, so run them through a
|
|
1159
|
+
# shell-free executor that treats metacharacters as literal data
|
|
1160
|
+
def quick_validation_runner
|
|
1161
|
+
@quick_validation_runner ||= ShellExecutor.new
|
|
1162
|
+
end
|
|
1158
1163
|
end
|
|
1159
1164
|
end
|
|
1160
1165
|
end
|