aidp 0.49.10 → 0.49.12
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/cli/security_command.rb +8 -7
- data/lib/aidp/execute/checkpoint.rb +3 -1
- data/lib/aidp/execute/interactive_repl.rb +4 -3
- data/lib/aidp/execute/work_loop_runner.rb +4 -2
- data/lib/aidp/harness/completion_checker.rb +9 -9
- data/lib/aidp/init/runner.rb +2 -2
- data/lib/aidp/pr_worktree_manager.rb +19 -16
- data/lib/aidp/shell_executor.rb +3 -10
- data/lib/aidp/version.rb +1 -1
- 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: 7aebc32c94a99c769c32718c0d1831888e9d7e9e16eb2968f64e9fd8e1d04b23
|
|
4
|
+
data.tar.gz: 10380f1bfa01c5154d3aa19be32a67b8e757a66c27b1e8bb128769787357d194
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e5b4b81a0662bbc8e5d6b2a4ecdbc0104f14cef44898cd01c219ed1a09ae53218afa89cb5178acc2a4361eee3d0ff1081fd32cdf225a4df3862168081b3140d5
|
|
7
|
+
data.tar.gz: '02699b7be327242d960f268f972b6fd38984d251878bca63b2075dceeae3383ac3ca82a42f182755da16263754e5a701581a5d6eeb3436980df7ff4c1c85384f'
|
|
@@ -342,12 +342,13 @@ module Aidp
|
|
|
342
342
|
return 0
|
|
343
343
|
end
|
|
344
344
|
|
|
345
|
-
# Run RSpec with timeout protection
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
# Run RSpec with timeout protection, passing arguments without shell
|
|
346
|
+
# interpretation of the library-provided project path
|
|
347
|
+
command_args = ["bundle", "exec", "rspec", rspec_path, "--format", "failures"]
|
|
348
|
+
@prompt.say("$ #{command_args.join(" ")}\n")
|
|
348
349
|
@prompt.say("(timeout: #{AUDIT_TIMEOUT_SECONDS / 60} minutes)\n")
|
|
349
350
|
|
|
350
|
-
exit_status = run_with_timeout(
|
|
351
|
+
exit_status = run_with_timeout(command_args, AUDIT_TIMEOUT_SECONDS)
|
|
351
352
|
|
|
352
353
|
case exit_status
|
|
353
354
|
when 0
|
|
@@ -365,11 +366,11 @@ module Aidp
|
|
|
365
366
|
private
|
|
366
367
|
|
|
367
368
|
# Run a command with timeout protection
|
|
368
|
-
# @param
|
|
369
|
+
# @param command_args [Array<String>] The command and its arguments
|
|
369
370
|
# @param timeout [Integer] Timeout in seconds
|
|
370
371
|
# @return [Integer, Symbol] Exit status or :timeout
|
|
371
|
-
def run_with_timeout(
|
|
372
|
-
pid = spawn(
|
|
372
|
+
def run_with_timeout(command_args, timeout)
|
|
373
|
+
pid = Process.spawn(*command_args)
|
|
373
374
|
start_time = Time.now
|
|
374
375
|
|
|
375
376
|
loop do
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "yaml"
|
|
4
4
|
require "time"
|
|
5
5
|
require "json"
|
|
6
|
+
require "open3"
|
|
6
7
|
require "aidp/rescue_logging"
|
|
7
8
|
|
|
8
9
|
module Aidp
|
|
@@ -183,7 +184,8 @@ module Aidp
|
|
|
183
184
|
def run_rubocop_check
|
|
184
185
|
# Run rubocop and parse output to get a quality score
|
|
185
186
|
# This is a simplified version - could be enhanced
|
|
186
|
-
|
|
187
|
+
stdout, _stderr, _status = Open3.capture3("rubocop", "--format", "json", chdir: @project_dir)
|
|
188
|
+
result = stdout
|
|
187
189
|
return nil if result.empty?
|
|
188
190
|
|
|
189
191
|
data = JSON.parse(result)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "tty-prompt"
|
|
4
4
|
require "tty-spinner"
|
|
5
|
+
require "open3"
|
|
5
6
|
require_relative "async_work_loop_runner"
|
|
6
7
|
require_relative "repl_macros"
|
|
7
8
|
require_relative "../rescue_logging"
|
|
@@ -307,9 +308,9 @@ module Aidp
|
|
|
307
308
|
}
|
|
308
309
|
end
|
|
309
310
|
|
|
310
|
-
# Execute reset
|
|
311
|
-
output =
|
|
312
|
-
success =
|
|
311
|
+
# Execute reset without shell interpretation of the rollback count
|
|
312
|
+
output, status = Open3.capture2e("git", "reset", "--hard", "HEAD~#{count}")
|
|
313
|
+
success = status.success?
|
|
313
314
|
|
|
314
315
|
{
|
|
315
316
|
success: success,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "open3"
|
|
3
4
|
require_relative "prompt_manager"
|
|
4
5
|
require_relative "prompt_evaluator"
|
|
5
6
|
require_relative "checkpoint"
|
|
@@ -2359,8 +2360,9 @@ module Aidp
|
|
|
2359
2360
|
|
|
2360
2361
|
stats = {}
|
|
2361
2362
|
files.each do |file|
|
|
2362
|
-
# Use git diff to get line counts
|
|
2363
|
-
|
|
2363
|
+
# Use git diff to get line counts without shell interpretation of file names
|
|
2364
|
+
stdout, _stderr, _status = Open3.capture3("git", "diff", "--numstat", "HEAD", "--", file.to_s)
|
|
2365
|
+
output = stdout.strip
|
|
2364
2366
|
next if output.empty?
|
|
2365
2367
|
|
|
2366
2368
|
parts = output.split("\t")
|
|
@@ -64,27 +64,27 @@ module Aidp
|
|
|
64
64
|
test_commands = detect_test_commands
|
|
65
65
|
return true if test_commands.empty?
|
|
66
66
|
|
|
67
|
-
test_commands.any?
|
|
68
|
-
system("cd #{@project_dir} && #{cmd} > /dev/null 2>&1")
|
|
69
|
-
end
|
|
67
|
+
test_commands.any? { |cmd| run_project_command(cmd) }
|
|
70
68
|
end
|
|
71
69
|
|
|
72
70
|
def linting_clean?
|
|
73
71
|
lint_commands = detect_lint_commands
|
|
74
72
|
return true if lint_commands.empty?
|
|
75
73
|
|
|
76
|
-
lint_commands.all?
|
|
77
|
-
system("cd #{@project_dir} && #{cmd} > /dev/null 2>&1")
|
|
78
|
-
end
|
|
74
|
+
lint_commands.all? { |cmd| run_project_command(cmd) }
|
|
79
75
|
end
|
|
80
76
|
|
|
81
77
|
def build_successful?
|
|
82
78
|
build_commands = detect_build_commands
|
|
83
79
|
return true if build_commands.empty?
|
|
84
80
|
|
|
85
|
-
build_commands.any?
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
build_commands.any? { |cmd| run_project_command(cmd) }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Run a detected command in the project directory without building a
|
|
85
|
+
# shell command string from the library-provided project path
|
|
86
|
+
def run_project_command(cmd)
|
|
87
|
+
system(cmd, chdir: @project_dir, out: File::NULL, err: File::NULL)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def documentation_complete?
|
data/lib/aidp/init/runner.rb
CHANGED
|
@@ -357,9 +357,9 @@ module Aidp
|
|
|
357
357
|
|
|
358
358
|
next unless tool_command
|
|
359
359
|
|
|
360
|
-
# Check if command exists
|
|
360
|
+
# Check if command exists without shell interpretation
|
|
361
361
|
begin
|
|
362
|
-
unless system("which
|
|
362
|
+
unless system("which", tool_command, out: File::NULL, err: File::NULL)
|
|
363
363
|
warnings << " ⚠️ #{format_tool(tool_data[:tool])} detected but command '#{tool_command}' not found in PATH"
|
|
364
364
|
end
|
|
365
365
|
rescue IOError
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require "json"
|
|
2
2
|
require "fileutils"
|
|
3
|
-
require "shellwords"
|
|
4
3
|
|
|
5
4
|
module Aidp
|
|
6
5
|
# Manages worktrees specifically for Pull Request branches
|
|
@@ -151,17 +150,18 @@ module Aidp
|
|
|
151
150
|
branch == "* #{base_branch}"
|
|
152
151
|
end
|
|
153
152
|
|
|
154
|
-
# Enhance branch tracking and fetching
|
|
153
|
+
# Enhance branch tracking and fetching; argv execution keeps the
|
|
154
|
+
# library-provided branch name from being interpreted by a shell
|
|
155
155
|
unless base_branch_exists
|
|
156
156
|
# Try multiple fetch strategies
|
|
157
157
|
fetch_commands = [
|
|
158
|
-
"git fetch origin #{base_branch}:#{base_branch}
|
|
159
|
-
"git fetch origin
|
|
160
|
-
"git fetch --all
|
|
158
|
+
["git", "fetch", "origin", "#{base_branch}:#{base_branch}"],
|
|
159
|
+
["git", "fetch", "origin"],
|
|
160
|
+
["git", "fetch", "--all"]
|
|
161
161
|
]
|
|
162
162
|
|
|
163
|
-
fetch_commands.each do |
|
|
164
|
-
@shell_executor.system(
|
|
163
|
+
fetch_commands.each do |fetch_args|
|
|
164
|
+
@shell_executor.system(*fetch_args, err: File::NULL)
|
|
165
165
|
branch_list_output = `git branch -a`.split("\n").map(&:strip)
|
|
166
166
|
base_branch_exists = branch_list_output.any? do |branch|
|
|
167
167
|
branch.end_with?("/#{base_branch}", "remotes/origin/#{base_branch}") ||
|
|
@@ -174,14 +174,15 @@ module Aidp
|
|
|
174
174
|
|
|
175
175
|
raise ArgumentError, "Base branch '#{base_branch}' does not exist in the repository" unless base_branch_exists
|
|
176
176
|
|
|
177
|
-
# Robust worktree creation with enhanced error handling and logging
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
# Robust worktree creation with enhanced error handling and logging;
|
|
178
|
+
# argv execution keeps library-provided branches and paths literal
|
|
179
|
+
worktree_create_args = ["git", "worktree", "add", worktree_path, "-b", head_branch, base_branch]
|
|
180
|
+
unless @shell_executor.system(*worktree_create_args)
|
|
180
181
|
error_details = {
|
|
181
182
|
pr_number: pr_number,
|
|
182
183
|
base_branch: base_branch,
|
|
183
184
|
head_branch: head_branch,
|
|
184
|
-
command:
|
|
185
|
+
command: worktree_create_args.join(" ")
|
|
185
186
|
}
|
|
186
187
|
Aidp.log_error(
|
|
187
188
|
"pr_worktree_manager", "worktree_creation_failed",
|
|
@@ -377,9 +378,9 @@ module Aidp
|
|
|
377
378
|
end
|
|
378
379
|
end
|
|
379
380
|
|
|
380
|
-
# Stage only successfully modified files
|
|
381
|
+
# Stage only successfully modified files without shell interpretation
|
|
381
382
|
unless successful_files.empty?
|
|
382
|
-
@shell_executor.system("git add
|
|
383
|
+
@shell_executor.system("git", "add", "--", *successful_files)
|
|
383
384
|
end
|
|
384
385
|
end
|
|
385
386
|
|
|
@@ -428,7 +429,7 @@ module Aidp
|
|
|
428
429
|
|
|
429
430
|
Dir.chdir(worktree_path) do
|
|
430
431
|
# Check staged changes with more robust capture
|
|
431
|
-
staged_changes_output = @shell_executor.
|
|
432
|
+
staged_changes_output = @shell_executor.run_argv("git", "diff", "--staged", "--name-only").stdout.strip
|
|
432
433
|
|
|
433
434
|
if !staged_changes_output.empty?
|
|
434
435
|
push_result[:git_actions][:staged_changes] = true
|
|
@@ -493,8 +494,10 @@ module Aidp
|
|
|
493
494
|
existing_worktree = @worktrees[pr_number.to_s]
|
|
494
495
|
return false unless existing_worktree
|
|
495
496
|
|
|
496
|
-
# Remove git worktree
|
|
497
|
-
|
|
497
|
+
# Remove git worktree without shell interpretation of registry data
|
|
498
|
+
if File.exist?(existing_worktree["path"])
|
|
499
|
+
@shell_executor.system("git", "worktree", "remove", existing_worktree["path"])
|
|
500
|
+
end
|
|
498
501
|
|
|
499
502
|
# Remove from registry and save
|
|
500
503
|
@worktrees.delete(pr_number.to_s)
|
data/lib/aidp/shell_executor.rb
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
module Aidp
|
|
4
4
|
# Shell command executor wrapper for testability
|
|
5
5
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# Commands are always executed in argument form so shell
|
|
7
|
+
# metacharacters in any value are treated as literal data:
|
|
8
|
+
# 1. `run_argv(*command)` - Captures output without shell interpretation
|
|
8
9
|
# 2. `system(*args)` - Wraps Kernel.system() with optional output suppression
|
|
9
10
|
#
|
|
10
11
|
# In tests, set `ShellExecutor.suppress_output = true` to suppress all
|
|
@@ -51,14 +52,6 @@ module Aidp
|
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
|
|
54
|
-
# Run a command and capture its output
|
|
55
|
-
#
|
|
56
|
-
# @param command [String] The shell command to run
|
|
57
|
-
# @return [String] The command's stdout output
|
|
58
|
-
def run(command)
|
|
59
|
-
`#{command}`
|
|
60
|
-
end
|
|
61
|
-
|
|
62
55
|
# Run a command without shell interpretation and capture its output
|
|
63
56
|
#
|
|
64
57
|
# The command and its arguments are passed directly to the operating
|
data/lib/aidp/version.rb
CHANGED