aidp 0.49.15 → 0.49.17
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/issue_importer.rb +12 -8
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/repository_client.rb +30 -25
- data/lib/aidp/watch/repository_safety_checker.rb +1 -1
- data/lib/aidp/worktree.rb +8 -3
- data/lib/aidp/worktree_branch_manager.rb +14 -13
- 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: 58a524647b6ac1b6ef0c819508de7693794689414d6f5bde4f1cba5cddf8799f
|
|
4
|
+
data.tar.gz: 6c7da67512e7c04941c0afa6db927b348fcd9f31809526723a107b419ab91866
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56a49eaffe7e9f81e0fa4457634814622867fb335e54ac182b4fd31b05c3063ad726790c7376820101e6b57bd2b07c7b4ac6c3ac8b0f69220f248681a0ba8e65
|
|
7
|
+
data.tar.gz: 610e7e0a8e151208fd5c623a3937974ec3cdab2ca72741d421bb6bab003cb6514ff8dc449d35f52c06ca0083dd3e40b2ef114a54269703137ed00cc95bfefe0b
|
|
@@ -120,14 +120,15 @@ module Aidp
|
|
|
120
120
|
end
|
|
121
121
|
|
|
122
122
|
def fetch_via_gh_cli(owner, repo, number)
|
|
123
|
-
|
|
123
|
+
# Keep the gh CLI and its flags as separate argv entries so the
|
|
124
|
+
# library-provided owner/repo values are never interpreted by a shell.
|
|
125
|
+
Aidp.log_debug(COMPONENT, "Running gh cli", owner: owner, repo: repo, number: number, command: "gh issue view")
|
|
126
|
+
stdout, stderr, status = capture3_with_timeout(
|
|
124
127
|
"gh", "issue", "view", number,
|
|
125
128
|
"--repo", "#{owner}/#{repo}",
|
|
126
|
-
"--json", "title,body,labels,milestone,comments,state,assignees,number,url"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Aidp.log_debug(COMPONENT, "Running gh cli", owner: owner, repo: repo, number: number, command: cmd.join(" "))
|
|
130
|
-
stdout, stderr, status = capture3_with_timeout(*cmd, timeout: gh_cli_timeout)
|
|
129
|
+
"--json", "title,body,labels,milestone,comments,state,assignees,number,url",
|
|
130
|
+
timeout: gh_cli_timeout
|
|
131
|
+
)
|
|
131
132
|
Aidp.log_debug(COMPONENT, "Completed gh cli", owner: owner, repo: repo, number: number, exitstatus: status.exitstatus)
|
|
132
133
|
|
|
133
134
|
unless status.success?
|
|
@@ -320,14 +321,17 @@ module Aidp
|
|
|
320
321
|
false
|
|
321
322
|
end
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
# Run a command without shell interpretation: the executable is passed as
|
|
325
|
+
# a separate leading argument, so shell metacharacters in any argument
|
|
326
|
+
# value are treated as literal data.
|
|
327
|
+
def capture3_with_timeout(command, *args, timeout:)
|
|
324
328
|
stdout_str = +""
|
|
325
329
|
stderr_str = +""
|
|
326
330
|
status = nil
|
|
327
331
|
wait_thr = nil
|
|
328
332
|
|
|
329
333
|
Timeout.timeout(timeout) do
|
|
330
|
-
Open3.popen3(*
|
|
334
|
+
Open3.popen3(command, *args) do |stdin, stdout_io, stderr_io, thread|
|
|
331
335
|
wait_thr = thread
|
|
332
336
|
stdin.close
|
|
333
337
|
stdout_str = stdout_io.read
|
data/lib/aidp/version.rb
CHANGED
|
@@ -23,6 +23,11 @@ module Aidp
|
|
|
23
23
|
|
|
24
24
|
attr_reader :owner, :repo
|
|
25
25
|
|
|
26
|
+
# `gh` commands are executed in argument form: the executable is passed
|
|
27
|
+
# as a literal leading argument and every remaining token is a separate
|
|
28
|
+
# argument, so shell metacharacters in library-provided values
|
|
29
|
+
# (owner/repo, issue numbers, labels, comment bodies) are treated as
|
|
30
|
+
# literal data rather than interpreted by a shell.
|
|
26
31
|
def self.parse_issues_url(issues_url)
|
|
27
32
|
case issues_url
|
|
28
33
|
when %r{\Ahttps://github\.com/([^/]+)/([^/]+)(?:/issues)?/?\z}
|
|
@@ -382,7 +387,7 @@ module Aidp
|
|
|
382
387
|
cmd += ["--label", label]
|
|
383
388
|
end
|
|
384
389
|
|
|
385
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
390
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
386
391
|
unless status.success?
|
|
387
392
|
warn("GitHub CLI list failed: #{stderr}")
|
|
388
393
|
return []
|
|
@@ -416,7 +421,7 @@ module Aidp
|
|
|
416
421
|
fields = %w[number title body comments labels state assignees url updatedAt author]
|
|
417
422
|
cmd = ["gh", "issue", "view", number.to_s, "--repo", full_repo, "--json", fields.join(",")]
|
|
418
423
|
|
|
419
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
424
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
420
425
|
raise "GitHub CLI error: #{stderr.strip}" unless status.success?
|
|
421
426
|
|
|
422
427
|
data = JSON.parse(stdout)
|
|
@@ -442,7 +447,7 @@ module Aidp
|
|
|
442
447
|
with_gh_retry("post_comment") do
|
|
443
448
|
cmd = ["gh", "api", "repos/#{full_repo}/issues/#{number}/comments",
|
|
444
449
|
"-X", "POST", "-f", "body=#{body}"]
|
|
445
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
450
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
446
451
|
raise "Failed to post comment via gh: #{stderr.strip}" unless status.success?
|
|
447
452
|
|
|
448
453
|
response = JSON.parse(stdout)
|
|
@@ -467,7 +472,7 @@ module Aidp
|
|
|
467
472
|
values.each { |value| cmd.concat([flag, value]) }
|
|
468
473
|
end
|
|
469
474
|
|
|
470
|
-
_stdout, stderr, status = Open3.capture3(*cmd)
|
|
475
|
+
_stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
471
476
|
raise "Failed to update issue via gh: #{stderr.strip}" unless status.success?
|
|
472
477
|
|
|
473
478
|
true
|
|
@@ -533,7 +538,7 @@ module Aidp
|
|
|
533
538
|
|
|
534
539
|
def update_comment_via_gh(comment_id, body)
|
|
535
540
|
cmd = ["gh", "api", "repos/#{full_repo}/issues/comments/#{comment_id}", "-X", "PATCH", "-f", "body=#{body}"]
|
|
536
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
541
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
537
542
|
raise "Failed to update comment via gh: #{stderr.strip}" unless status.success?
|
|
538
543
|
|
|
539
544
|
stdout.strip
|
|
@@ -557,7 +562,7 @@ module Aidp
|
|
|
557
562
|
def fetch_comment_reactions_via_gh(comment_id)
|
|
558
563
|
with_gh_retry("fetch_comment_reactions") do
|
|
559
564
|
cmd = ["gh", "api", "repos/#{full_repo}/issues/comments/#{comment_id}/reactions"]
|
|
560
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
565
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
561
566
|
raise "Failed to fetch reactions via gh: #{stderr.strip}" unless status.success?
|
|
562
567
|
|
|
563
568
|
reactions = JSON.parse(stdout)
|
|
@@ -651,7 +656,7 @@ module Aidp
|
|
|
651
656
|
command: cmd.join(" ")
|
|
652
657
|
)
|
|
653
658
|
|
|
654
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
659
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
655
660
|
|
|
656
661
|
Aidp.log_debug(
|
|
657
662
|
"repository_client",
|
|
@@ -700,7 +705,7 @@ module Aidp
|
|
|
700
705
|
cmd = ["gh", "issue", "edit", number.to_s, "--repo", full_repo]
|
|
701
706
|
labels.each { |label| cmd += ["--add-label", label] }
|
|
702
707
|
|
|
703
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
708
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
704
709
|
raise "Failed to add labels via gh: #{stderr.strip}" unless status.success?
|
|
705
710
|
|
|
706
711
|
stdout.strip
|
|
@@ -729,7 +734,7 @@ module Aidp
|
|
|
729
734
|
cmd = ["gh", "issue", "edit", number.to_s, "--repo", full_repo]
|
|
730
735
|
labels.each { |label| cmd += ["--remove-label", label] }
|
|
731
736
|
|
|
732
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
737
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
733
738
|
raise "Failed to remove labels via gh: #{stderr.strip}" unless status.success?
|
|
734
739
|
|
|
735
740
|
stdout.strip
|
|
@@ -784,7 +789,7 @@ module Aidp
|
|
|
784
789
|
"-F", "number=#{number}"
|
|
785
790
|
]
|
|
786
791
|
|
|
787
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
792
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
788
793
|
unless status.success?
|
|
789
794
|
Aidp.log_warn("repository_client", "Failed to fetch label events via GraphQL", error: stderr.strip)
|
|
790
795
|
return nil
|
|
@@ -815,7 +820,7 @@ module Aidp
|
|
|
815
820
|
cmd += ["--label", label]
|
|
816
821
|
end
|
|
817
822
|
|
|
818
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
823
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
819
824
|
unless status.success?
|
|
820
825
|
warn("GitHub CLI PR list failed: #{stderr}")
|
|
821
826
|
return []
|
|
@@ -848,7 +853,7 @@ module Aidp
|
|
|
848
853
|
fields = %w[number title body labels state url headRefName baseRefName headRefOid commits author mergeable mergeStateStatus]
|
|
849
854
|
cmd = ["gh", "pr", "view", number.to_s, "--repo", full_repo, "--json", fields.join(",")]
|
|
850
855
|
|
|
851
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
856
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
852
857
|
raise "GitHub CLI error: #{stderr.strip}" unless status.success?
|
|
853
858
|
|
|
854
859
|
data = JSON.parse(stdout)
|
|
@@ -868,7 +873,7 @@ module Aidp
|
|
|
868
873
|
|
|
869
874
|
def fetch_pull_request_diff_via_gh(number)
|
|
870
875
|
cmd = ["gh", "pr", "diff", number.to_s, "--repo", full_repo]
|
|
871
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
876
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
872
877
|
raise "Failed to fetch PR diff via gh: #{stderr.strip}" unless status.success?
|
|
873
878
|
|
|
874
879
|
stdout
|
|
@@ -891,7 +896,7 @@ module Aidp
|
|
|
891
896
|
def fetch_pull_request_files_via_gh(number)
|
|
892
897
|
# Use gh api to fetch changed files
|
|
893
898
|
cmd = ["gh", "api", "repos/#{full_repo}/pulls/#{number}/files", "--jq", "."]
|
|
894
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
899
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
895
900
|
raise "Failed to fetch PR files via gh: #{stderr.strip}" unless status.success?
|
|
896
901
|
|
|
897
902
|
JSON.parse(stdout).map { |file| normalize_pr_file(file) }
|
|
@@ -916,7 +921,7 @@ module Aidp
|
|
|
916
921
|
|
|
917
922
|
# Fetch check runs for the commit
|
|
918
923
|
cmd = ["gh", "api", "repos/#{full_repo}/commits/#{head_sha}/check-runs", "--jq", "."]
|
|
919
|
-
stdout, _stderr, status = Open3.capture3(*cmd)
|
|
924
|
+
stdout, _stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
920
925
|
|
|
921
926
|
check_runs = if status.success?
|
|
922
927
|
data = JSON.parse(stdout)
|
|
@@ -975,7 +980,7 @@ module Aidp
|
|
|
975
980
|
else
|
|
976
981
|
# Post general review comment
|
|
977
982
|
cmd = ["gh", "pr", "comment", number.to_s, "--repo", full_repo, "--body", body]
|
|
978
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
983
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
979
984
|
raise "Failed to post review comment via gh: #{stderr.strip}" unless status.success?
|
|
980
985
|
|
|
981
986
|
stdout.strip
|
|
@@ -1025,7 +1030,7 @@ module Aidp
|
|
|
1025
1030
|
|
|
1026
1031
|
def fetch_pr_comments_via_gh(number)
|
|
1027
1032
|
cmd = ["gh", "api", "repos/#{full_repo}/issues/#{number}/comments", "--jq", "."]
|
|
1028
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
1033
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1029
1034
|
raise "Failed to fetch PR comments via gh: #{stderr.strip}" unless status.success?
|
|
1030
1035
|
|
|
1031
1036
|
JSON.parse(stdout).map { |raw| normalize_pr_comment(raw) }
|
|
@@ -1046,7 +1051,7 @@ module Aidp
|
|
|
1046
1051
|
|
|
1047
1052
|
def mark_pr_ready_for_review_via_gh(number)
|
|
1048
1053
|
cmd = ["gh", "pr", "ready", number.to_s, "--repo", full_repo]
|
|
1049
|
-
_stdout, stderr, status = Open3.capture3(*cmd)
|
|
1054
|
+
_stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1050
1055
|
|
|
1051
1056
|
unless status.success?
|
|
1052
1057
|
Aidp.log_warn("repository_client", "mark_pr_ready_failed",
|
|
@@ -1065,7 +1070,7 @@ module Aidp
|
|
|
1065
1070
|
def request_reviewers_via_gh(number, reviewers:)
|
|
1066
1071
|
reviewer_args = reviewers.flat_map { |r| ["--add-reviewer", r] }
|
|
1067
1072
|
cmd = ["gh", "pr", "edit", number.to_s, "--repo", full_repo] + reviewer_args
|
|
1068
|
-
_stdout, stderr, status = Open3.capture3(*cmd)
|
|
1073
|
+
_stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1069
1074
|
|
|
1070
1075
|
unless status.success?
|
|
1071
1076
|
Aidp.log_warn("repository_client", "request_reviewers_failed",
|
|
@@ -1111,7 +1116,7 @@ module Aidp
|
|
|
1111
1116
|
"-F", "number=#{number}"
|
|
1112
1117
|
]
|
|
1113
1118
|
|
|
1114
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
1119
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1115
1120
|
unless status.success?
|
|
1116
1121
|
Aidp.log_warn("repository_client", "pr_label_actor_query_failed",
|
|
1117
1122
|
pr: number, error: stderr.strip)
|
|
@@ -1210,7 +1215,7 @@ module Aidp
|
|
|
1210
1215
|
|
|
1211
1216
|
def fetch_commit_statuses_via_gh(head_sha)
|
|
1212
1217
|
cmd = ["gh", "api", "repos/#{full_repo}/commits/#{head_sha}/status", "--jq", "."]
|
|
1213
|
-
stdout, _stderr, status = Open3.capture3(*cmd)
|
|
1218
|
+
stdout, _stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1214
1219
|
|
|
1215
1220
|
if status.success?
|
|
1216
1221
|
data = JSON.parse(stdout)
|
|
@@ -1918,7 +1923,7 @@ module Aidp
|
|
|
1918
1923
|
labels.each { |label| cmd += ["--label", label] }
|
|
1919
1924
|
assignees.each { |assignee| cmd += ["--assignee", assignee] }
|
|
1920
1925
|
|
|
1921
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
1926
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1922
1927
|
raise "Failed to create issue via gh: #{stderr.strip}" unless status.success?
|
|
1923
1928
|
|
|
1924
1929
|
# Parse the issue URL to get the number
|
|
@@ -1936,7 +1941,7 @@ module Aidp
|
|
|
1936
1941
|
Aidp.log_debug("repository_client", "close_issue", issue_number: number)
|
|
1937
1942
|
|
|
1938
1943
|
cmd = ["gh", "issue", "close", number.to_s, "--repo", full_repo]
|
|
1939
|
-
_stdout, stderr, status = Open3.capture3(*cmd)
|
|
1944
|
+
_stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1940
1945
|
raise "Failed to close issue via gh: #{stderr.strip}" unless status.success?
|
|
1941
1946
|
|
|
1942
1947
|
Aidp.log_debug("repository_client", "close_issue_complete", issue_number: number)
|
|
@@ -1963,7 +1968,7 @@ module Aidp
|
|
|
1963
1968
|
# Add auto-delete branch flag
|
|
1964
1969
|
cmd << "--delete-branch"
|
|
1965
1970
|
|
|
1966
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
1971
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1967
1972
|
raise "Failed to merge PR via gh: #{stderr.strip}" unless status.success?
|
|
1968
1973
|
|
|
1969
1974
|
Aidp.log_debug("repository_client", "merge_pull_request_complete", number: number)
|
|
@@ -1980,7 +1985,7 @@ module Aidp
|
|
|
1980
1985
|
cmd += [flag, "#{key}=#{value}"]
|
|
1981
1986
|
end
|
|
1982
1987
|
|
|
1983
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
1988
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
1984
1989
|
unless status.success?
|
|
1985
1990
|
Aidp.log_warn("repository_client", "GraphQL query failed", error: stderr.strip)
|
|
1986
1991
|
raise "GraphQL query failed: #{stderr.strip}"
|
|
@@ -128,7 +128,7 @@ module Aidp
|
|
|
128
128
|
|
|
129
129
|
def check_visibility_via_gh
|
|
130
130
|
cmd = ["gh", "repo", "view", @repository_client.full_repo, "--json", "visibility"]
|
|
131
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
131
|
+
stdout, stderr, status = Open3.capture3("gh", *cmd[1..])
|
|
132
132
|
|
|
133
133
|
unless status.success?
|
|
134
134
|
Aidp.log_warn("repository_safety", "failed to check repo visibility via gh",
|
data/lib/aidp/worktree.rb
CHANGED
|
@@ -344,7 +344,10 @@ module Aidp
|
|
|
344
344
|
worktree_path: worktree_path,
|
|
345
345
|
base_branch: effective_base_branch
|
|
346
346
|
)
|
|
347
|
-
|
|
347
|
+
# Pass the git subcommand as a separate leading argument so the
|
|
348
|
+
# library-provided branch and path values are never interpreted
|
|
349
|
+
# by a shell.
|
|
350
|
+
stdout, stderr, status = Dir.chdir(project_dir) { Open3.capture3("git", *cmd) }
|
|
348
351
|
|
|
349
352
|
return if status.success?
|
|
350
353
|
|
|
@@ -367,11 +370,13 @@ module Aidp
|
|
|
367
370
|
end
|
|
368
371
|
end
|
|
369
372
|
|
|
373
|
+
# Build the worktree creation arguments (without the leading "git"),
|
|
374
|
+
# so the caller can pass them as separate argv entries.
|
|
370
375
|
def build_worktree_command(branch_exists:, branch:, worktree_path:, base_branch:)
|
|
371
376
|
if branch_exists
|
|
372
|
-
["
|
|
377
|
+
["worktree", "add", worktree_path, branch]
|
|
373
378
|
else
|
|
374
|
-
cmd = ["
|
|
379
|
+
cmd = ["worktree", "add", "-b", branch, worktree_path]
|
|
375
380
|
cmd << base_branch if base_branch
|
|
376
381
|
cmd
|
|
377
382
|
end
|
|
@@ -68,7 +68,7 @@ module Aidp
|
|
|
68
68
|
# 3. Use git worktree list for broader search
|
|
69
69
|
-> {
|
|
70
70
|
begin
|
|
71
|
-
worktree_list_output = run_git_command(
|
|
71
|
+
worktree_list_output = run_git_command("git", "worktree", "list")
|
|
72
72
|
worktree_list_output.split("\n").each do |line|
|
|
73
73
|
path, branch_info = line.split(" ", 2)
|
|
74
74
|
return path if branch_info&.include?(branch)
|
|
@@ -152,7 +152,7 @@ module Aidp
|
|
|
152
152
|
if force_recreate
|
|
153
153
|
# Attempt to remove existing worktree
|
|
154
154
|
begin
|
|
155
|
-
run_git_command(
|
|
155
|
+
run_git_command("git", "worktree", "remove", existing_worktree)
|
|
156
156
|
Aidp.log_debug("worktree_branch_manager", "existing_worktree_removed",
|
|
157
157
|
path: existing_worktree)
|
|
158
158
|
rescue => e
|
|
@@ -187,8 +187,8 @@ module Aidp
|
|
|
187
187
|
Aidp.log_debug("worktree_branch_manager", "create_strategy_remote_tracking",
|
|
188
188
|
branch: effective_branch,
|
|
189
189
|
base_branch: resolved_base_branch)
|
|
190
|
-
run_git_command(
|
|
191
|
-
run_git_command(
|
|
190
|
+
run_git_command("git", "fetch", "origin", resolved_base_branch)
|
|
191
|
+
run_git_command("git", "worktree", "add", "-b", effective_branch, worktree_path, "origin/#{resolved_base_branch}")
|
|
192
192
|
},
|
|
193
193
|
|
|
194
194
|
# Strategy 2: Create without remote tracking
|
|
@@ -196,7 +196,7 @@ module Aidp
|
|
|
196
196
|
Aidp.log_debug("worktree_branch_manager", "create_strategy_local_branch",
|
|
197
197
|
branch: effective_branch,
|
|
198
198
|
base_branch: resolved_base_branch)
|
|
199
|
-
run_git_command(
|
|
199
|
+
run_git_command("git", "worktree", "add", "-b", effective_branch, worktree_path, resolved_base_branch)
|
|
200
200
|
},
|
|
201
201
|
|
|
202
202
|
# Strategy 3: Checkout existing branch (for when branch already exists)
|
|
@@ -204,7 +204,7 @@ module Aidp
|
|
|
204
204
|
Aidp.log_debug("worktree_branch_manager", "create_strategy_existing_branch",
|
|
205
205
|
branch: effective_branch,
|
|
206
206
|
base_branch: resolved_base_branch)
|
|
207
|
-
run_git_command(
|
|
207
|
+
run_git_command("git", "worktree", "add", worktree_path, effective_branch)
|
|
208
208
|
}
|
|
209
209
|
]
|
|
210
210
|
|
|
@@ -317,7 +317,7 @@ module Aidp
|
|
|
317
317
|
# If PR number is provided, try to get base branch from GitHub
|
|
318
318
|
if pr_number
|
|
319
319
|
begin
|
|
320
|
-
pr_info_output = run_git_command(
|
|
320
|
+
pr_info_output = run_git_command("gh", "pr", "view", pr_number.to_s, "--json", "baseRefName")
|
|
321
321
|
pr_base_branch = JSON.parse(pr_info_output)["baseRefName"]
|
|
322
322
|
return pr_base_branch if pr_base_branch && !pr_base_branch.empty?
|
|
323
323
|
rescue => e
|
|
@@ -328,7 +328,7 @@ module Aidp
|
|
|
328
328
|
|
|
329
329
|
# Try to fetch origin branches
|
|
330
330
|
begin
|
|
331
|
-
run_git_command(
|
|
331
|
+
run_git_command("git", "fetch", "origin", default_base_branch)
|
|
332
332
|
rescue => e
|
|
333
333
|
Aidp.log_debug("worktree_branch_manager", "base_branch_fetch_failed",
|
|
334
334
|
base_branch: default_base_branch, error: e.message)
|
|
@@ -352,11 +352,12 @@ module Aidp
|
|
|
352
352
|
end
|
|
353
353
|
end
|
|
354
354
|
|
|
355
|
-
|
|
355
|
+
# Run a command with argv execution so shell metacharacters in any
|
|
356
|
+
# library-provided value (branch names, paths) are treated as literal
|
|
357
|
+
# data instead of being interpreted by a shell.
|
|
358
|
+
def run_git_command(command, *args)
|
|
356
359
|
Dir.chdir(@project_dir) do
|
|
357
|
-
|
|
358
|
-
args = cmd.is_a?(Array) ? cmd : cmd.split
|
|
359
|
-
output, status = Open3.capture2e(*args)
|
|
360
|
+
output, status = Open3.capture2e(command, *args)
|
|
360
361
|
raise StandardError, output unless status.success?
|
|
361
362
|
output
|
|
362
363
|
end
|
|
@@ -444,7 +445,7 @@ module Aidp
|
|
|
444
445
|
|
|
445
446
|
# Fetch pull request information from GitHub
|
|
446
447
|
begin
|
|
447
|
-
pr_info_output = run_git_command(
|
|
448
|
+
pr_info_output = run_git_command("gh", "pr", "view", pr_number.to_s, "--json", "headRefName")
|
|
448
449
|
pr_branch = JSON.parse(pr_info_output)["headRefName"]
|
|
449
450
|
|
|
450
451
|
if pr_branch.nil? || pr_branch.empty?
|