aider-ce 0.88.20__py3-none-any.whl → 0.88.38__py3-none-any.whl
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.
- aider/__init__.py +1 -1
- aider/_version.py +2 -2
- aider/args.py +63 -43
- aider/coders/agent_coder.py +331 -79
- aider/coders/agent_prompts.py +3 -15
- aider/coders/architect_coder.py +21 -5
- aider/coders/base_coder.py +661 -413
- aider/coders/base_prompts.py +6 -3
- aider/coders/chat_chunks.py +39 -17
- aider/commands.py +79 -15
- aider/diffs.py +10 -9
- aider/exceptions.py +1 -1
- aider/helpers/coroutines.py +8 -0
- aider/helpers/requests.py +45 -0
- aider/history.py +5 -0
- aider/io.py +179 -25
- aider/main.py +86 -35
- aider/models.py +16 -8
- aider/queries/tree-sitter-language-pack/c-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/clojure-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/csharp-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/dart-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elm-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/go-tags.scm +7 -0
- aider/queries/tree-sitter-language-pack/java-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-language-pack/lua-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/python-tags.scm +10 -0
- aider/queries/tree-sitter-language-pack/r-tags.scm +6 -0
- aider/queries/tree-sitter-language-pack/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/rust-tags.scm +3 -0
- aider/queries/tree-sitter-language-pack/solidity-tags.scm +1 -1
- aider/queries/tree-sitter-language-pack/swift-tags.scm +4 -1
- aider/queries/tree-sitter-languages/c-tags.scm +3 -0
- aider/queries/tree-sitter-languages/c_sharp-tags.scm +6 -0
- aider/queries/tree-sitter-languages/cpp-tags.scm +3 -0
- aider/queries/tree-sitter-languages/dart-tags.scm +2 -1
- aider/queries/tree-sitter-languages/elixir-tags.scm +5 -0
- aider/queries/tree-sitter-languages/elm-tags.scm +3 -0
- aider/queries/tree-sitter-languages/fortran-tags.scm +3 -0
- aider/queries/tree-sitter-languages/go-tags.scm +6 -0
- aider/queries/tree-sitter-languages/haskell-tags.scm +2 -0
- aider/queries/tree-sitter-languages/java-tags.scm +6 -0
- aider/queries/tree-sitter-languages/javascript-tags.scm +8 -0
- aider/queries/tree-sitter-languages/julia-tags.scm +2 -2
- aider/queries/tree-sitter-languages/kotlin-tags.scm +3 -0
- aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +6 -0
- aider/queries/tree-sitter-languages/php-tags.scm +6 -0
- aider/queries/tree-sitter-languages/python-tags.scm +10 -0
- aider/queries/tree-sitter-languages/ruby-tags.scm +5 -0
- aider/queries/tree-sitter-languages/rust-tags.scm +3 -0
- aider/queries/tree-sitter-languages/scala-tags.scm +2 -3
- aider/queries/tree-sitter-languages/typescript-tags.scm +3 -0
- aider/queries/tree-sitter-languages/zig-tags.scm +20 -3
- aider/repomap.py +71 -11
- aider/resources/model-metadata.json +27335 -635
- aider/resources/model-settings.yml +190 -0
- aider/scrape.py +2 -0
- aider/tools/__init__.py +2 -0
- aider/tools/command.py +84 -94
- aider/tools/command_interactive.py +95 -110
- aider/tools/delete_block.py +131 -159
- aider/tools/delete_line.py +97 -132
- aider/tools/delete_lines.py +120 -160
- aider/tools/extract_lines.py +288 -312
- aider/tools/finished.py +30 -43
- aider/tools/git_branch.py +107 -109
- aider/tools/git_diff.py +44 -56
- aider/tools/git_log.py +39 -53
- aider/tools/git_remote.py +37 -51
- aider/tools/git_show.py +33 -47
- aider/tools/git_status.py +30 -44
- aider/tools/grep.py +214 -242
- aider/tools/indent_lines.py +175 -201
- aider/tools/insert_block.py +220 -253
- aider/tools/list_changes.py +65 -80
- aider/tools/ls.py +64 -80
- aider/tools/make_editable.py +57 -73
- aider/tools/make_readonly.py +50 -66
- aider/tools/remove.py +64 -80
- aider/tools/replace_all.py +96 -109
- aider/tools/replace_line.py +118 -156
- aider/tools/replace_lines.py +160 -197
- aider/tools/replace_text.py +159 -160
- aider/tools/show_numbered_context.py +115 -141
- aider/tools/thinking.py +52 -0
- aider/tools/undo_change.py +78 -91
- aider/tools/update_todo_list.py +130 -138
- aider/tools/utils/base_tool.py +64 -0
- aider/tools/utils/output.py +118 -0
- aider/tools/view.py +38 -54
- aider/tools/view_files_matching.py +131 -134
- aider/tools/view_files_with_symbol.py +108 -120
- aider/urls.py +1 -1
- aider/versioncheck.py +4 -3
- aider/website/docs/config/adv-model-settings.md +237 -0
- aider/website/docs/config/agent-mode.md +36 -3
- aider/website/docs/config/model-aliases.md +2 -1
- aider/website/docs/faq.md +6 -11
- aider/website/docs/languages.md +2 -2
- aider/website/docs/more/infinite-output.md +27 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/METADATA +112 -70
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/RECORD +112 -107
- aider_ce-0.88.38.dist-info/entry_points.txt +6 -0
- aider_ce-0.88.20.dist-info/entry_points.txt +0 -2
- /aider/tools/{tool_utils.py → utils/helpers.py} +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/WHEEL +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/licenses/LICENSE.txt +0 -0
- {aider_ce-0.88.20.dist-info → aider_ce-0.88.38.dist-info}/top_level.txt +0 -0
aider/tools/git_show.py
CHANGED
|
@@ -1,51 +1,37 @@
|
|
|
1
1
|
from aider.repo import ANY_GIT_ERROR
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Tool(BaseTool):
|
|
6
|
+
NORM_NAME = "gitshow"
|
|
7
|
+
SCHEMA = {
|
|
8
|
+
"type": "function",
|
|
9
|
+
"function": {
|
|
10
|
+
"name": "GitShow",
|
|
11
|
+
"description": "Show various types of objects (blobs, trees, tags, and commits).",
|
|
12
|
+
"parameters": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {
|
|
15
|
+
"object": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "The object to show. Defaults to HEAD.",
|
|
18
|
+
},
|
|
14
19
|
},
|
|
20
|
+
"required": [],
|
|
15
21
|
},
|
|
16
|
-
"required": [],
|
|
17
22
|
},
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return coder.repo.repo.git.show(object)
|
|
34
|
-
except ANY_GIT_ERROR as e:
|
|
35
|
-
coder.io.tool_error(f"Error running git show: {e}")
|
|
36
|
-
return f"Error running git show: {e}"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def process_response(coder, params):
|
|
40
|
-
"""
|
|
41
|
-
Process the GitShow tool response.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
coder: The Coder instance
|
|
45
|
-
params: Dictionary of parameters
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
str: Result message
|
|
49
|
-
"""
|
|
50
|
-
object = params.get("object", "HEAD")
|
|
51
|
-
return _execute_git_show(coder, object)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def execute(cls, coder, object="HEAD"):
|
|
27
|
+
"""
|
|
28
|
+
Show various types of objects (blobs, trees, tags, and commits).
|
|
29
|
+
"""
|
|
30
|
+
if not coder.repo:
|
|
31
|
+
return "Not in a git repository."
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
return coder.repo.repo.git.show(object)
|
|
35
|
+
except ANY_GIT_ERROR as e:
|
|
36
|
+
coder.io.tool_error(f"Error running git show: {e}")
|
|
37
|
+
return f"Error running git show: {e}"
|
aider/tools/git_status.py
CHANGED
|
@@ -1,46 +1,32 @@
|
|
|
1
1
|
from aider.repo import ANY_GIT_ERROR
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
"
|
|
2
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Tool(BaseTool):
|
|
6
|
+
NORM_NAME = "gitstatus"
|
|
7
|
+
SCHEMA = {
|
|
8
|
+
"type": "function",
|
|
9
|
+
"function": {
|
|
10
|
+
"name": "GitStatus",
|
|
11
|
+
"description": "Show the working tree status.",
|
|
12
|
+
"parameters": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"properties": {},
|
|
15
|
+
"required": [],
|
|
16
|
+
},
|
|
12
17
|
},
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return coder.repo.repo.git.status()
|
|
29
|
-
except ANY_GIT_ERROR as e:
|
|
30
|
-
coder.io.tool_error(f"Error running git status: {e}")
|
|
31
|
-
return f"Error running git status: {e}"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def process_response(coder, params):
|
|
35
|
-
"""
|
|
36
|
-
Process the GitStatus tool response.
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
coder: The Coder instance
|
|
40
|
-
params: Dictionary of parameters (should be empty for GitStatus)
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
str: Result message
|
|
44
|
-
"""
|
|
45
|
-
# GitStatus tool has no parameters to validate
|
|
46
|
-
return _execute_git_status(coder)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def execute(cls, coder):
|
|
22
|
+
"""
|
|
23
|
+
Show the working tree status.
|
|
24
|
+
"""
|
|
25
|
+
if not coder.repo:
|
|
26
|
+
return "Not in a git repository."
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
return coder.repo.repo.git.status()
|
|
30
|
+
except ANY_GIT_ERROR as e:
|
|
31
|
+
coder.io.tool_error(f"Error running git status: {e}")
|
|
32
|
+
return f"Error running git status: {e}"
|
aider/tools/grep.py
CHANGED
|
@@ -4,253 +4,225 @@ from pathlib import Path
|
|
|
4
4
|
import oslex
|
|
5
5
|
|
|
6
6
|
from aider.run_cmd import run_cmd_subprocess
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
7
|
+
from aider.tools.utils.base_tool import BaseTool
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Tool(BaseTool):
|
|
11
|
+
NORM_NAME = "grep"
|
|
12
|
+
SCHEMA = {
|
|
13
|
+
"type": "function",
|
|
14
|
+
"function": {
|
|
15
|
+
"name": "Grep",
|
|
16
|
+
"description": "Search for a pattern in files.",
|
|
17
|
+
"parameters": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"pattern": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "The pattern to search for.",
|
|
23
|
+
},
|
|
24
|
+
"file_pattern": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Glob pattern for files to search. Defaults to '*'.",
|
|
27
|
+
},
|
|
28
|
+
"directory": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Directory to search in. Defaults to '.'.",
|
|
31
|
+
},
|
|
32
|
+
"use_regex": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"description": "Whether to use regex. Defaults to False.",
|
|
35
|
+
},
|
|
36
|
+
"case_insensitive": {
|
|
37
|
+
"type": "boolean",
|
|
38
|
+
"description": (
|
|
39
|
+
"Whether to perform a case-insensitive search. Defaults to False."
|
|
40
|
+
),
|
|
41
|
+
},
|
|
42
|
+
"context_before": {
|
|
43
|
+
"type": "integer",
|
|
44
|
+
"description": "Number of lines to show before a match. Defaults to 5.",
|
|
45
|
+
},
|
|
46
|
+
"context_after": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"description": "Number of lines to show after a match. Defaults to 5.",
|
|
49
|
+
},
|
|
45
50
|
},
|
|
51
|
+
"required": ["pattern"],
|
|
46
52
|
},
|
|
47
|
-
"required": ["pattern"],
|
|
48
53
|
},
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
elif shutil.which("ag"):
|
|
61
|
-
return "ag", shutil.which("ag")
|
|
62
|
-
elif shutil.which("grep"):
|
|
63
|
-
return "grep", shutil.which("grep")
|
|
64
|
-
else:
|
|
65
|
-
return None, None
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def _execute_grep(
|
|
69
|
-
coder,
|
|
70
|
-
pattern,
|
|
71
|
-
file_pattern="*",
|
|
72
|
-
directory=".",
|
|
73
|
-
use_regex=False,
|
|
74
|
-
case_insensitive=False,
|
|
75
|
-
context_before=5,
|
|
76
|
-
context_after=5,
|
|
77
|
-
):
|
|
78
|
-
"""
|
|
79
|
-
Search for lines matching a pattern in files within the project repository.
|
|
80
|
-
Uses rg (ripgrep), ag (the silver searcher), or grep, whichever is available.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
coder: The Coder instance.
|
|
84
|
-
pattern (str): The pattern to search for.
|
|
85
|
-
file_pattern (str, optional): Glob pattern to filter files. Defaults to "*".
|
|
86
|
-
directory (str, optional): Directory to search within relative to repo root. Defaults to ".".
|
|
87
|
-
use_regex (bool, optional): Whether the pattern is a regular expression. Defaults to False.
|
|
88
|
-
case_insensitive (bool, optional): Whether the search should be case-insensitive. Defaults to False.
|
|
89
|
-
context_before (int, optional): Number of context lines to show before matches. Defaults to 5.
|
|
90
|
-
context_after (int, optional): Number of context lines to show after matches. Defaults to 5.
|
|
91
|
-
|
|
92
|
-
Returns:
|
|
93
|
-
str: Formatted result indicating success or failure, including matching lines or error message.
|
|
94
|
-
"""
|
|
95
|
-
repo = coder.repo
|
|
96
|
-
if not repo:
|
|
97
|
-
coder.io.tool_error("Not in a git repository.")
|
|
98
|
-
return "Error: Not in a git repository."
|
|
99
|
-
|
|
100
|
-
tool_name, tool_path = _find_search_tool()
|
|
101
|
-
if not tool_path:
|
|
102
|
-
coder.io.tool_error("No search tool (rg, ag, grep) found in PATH.")
|
|
103
|
-
return "Error: No search tool (rg, ag, grep) found."
|
|
104
|
-
|
|
105
|
-
try:
|
|
106
|
-
search_dir_path = Path(repo.root) / directory
|
|
107
|
-
if not search_dir_path.is_dir():
|
|
108
|
-
coder.io.tool_error(f"Directory not found: {directory}")
|
|
109
|
-
return f"Error: Directory not found: {directory}"
|
|
110
|
-
|
|
111
|
-
# Build the command arguments based on the available tool
|
|
112
|
-
cmd_args = [tool_path]
|
|
113
|
-
|
|
114
|
-
# Common options or tool-specific equivalents
|
|
115
|
-
if tool_name in ["rg", "grep"]:
|
|
116
|
-
cmd_args.append("-n") # Line numbers for rg and grep
|
|
117
|
-
# ag includes line numbers by default
|
|
118
|
-
|
|
119
|
-
if tool_name in ["rg"]:
|
|
120
|
-
cmd_args.append("--heading") # Filename above output for ripgrep
|
|
121
|
-
|
|
122
|
-
# Context lines (Before and After)
|
|
123
|
-
if context_before > 0:
|
|
124
|
-
# All tools use -B for lines before
|
|
125
|
-
cmd_args.extend(["-B", str(context_before)])
|
|
126
|
-
if context_after > 0:
|
|
127
|
-
# All tools use -A for lines after
|
|
128
|
-
cmd_args.extend(["-A", str(context_after)])
|
|
129
|
-
|
|
130
|
-
# Case sensitivity
|
|
131
|
-
if case_insensitive:
|
|
132
|
-
cmd_args.append("-i") # Add case-insensitivity flag for all tools
|
|
133
|
-
|
|
134
|
-
# Pattern type (regex vs fixed string)
|
|
135
|
-
if use_regex:
|
|
136
|
-
if tool_name == "grep":
|
|
137
|
-
cmd_args.append("-E") # Use extended regex for grep
|
|
138
|
-
# rg and ag use regex by default, no flag needed for basic ERE
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def _find_search_tool(self):
|
|
58
|
+
"""Find the best available command-line search tool (rg, ag, grep)."""
|
|
59
|
+
if shutil.which("rg"):
|
|
60
|
+
return "rg", shutil.which("rg")
|
|
61
|
+
elif shutil.which("ag"):
|
|
62
|
+
return "ag", shutil.which("ag")
|
|
63
|
+
elif shutil.which("grep"):
|
|
64
|
+
return "grep", shutil.which("grep")
|
|
139
65
|
else:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
66
|
+
return None, None
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def execute(
|
|
70
|
+
cls,
|
|
71
|
+
coder,
|
|
72
|
+
pattern,
|
|
73
|
+
file_pattern="*",
|
|
74
|
+
directory=".",
|
|
75
|
+
use_regex=False,
|
|
76
|
+
case_insensitive=False,
|
|
77
|
+
context_before=5,
|
|
78
|
+
context_after=5,
|
|
79
|
+
):
|
|
80
|
+
"""
|
|
81
|
+
Search for lines matching a pattern in files within the project repository.
|
|
82
|
+
Uses rg (ripgrep), ag (the silver searcher), or grep, whichever is available.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
coder: The Coder instance.
|
|
86
|
+
pattern (str): The pattern to search for.
|
|
87
|
+
file_pattern (str, optional): Glob pattern to filter files. Defaults to "*".
|
|
88
|
+
directory (str, optional): Directory to search within relative to repo root. Defaults to ".".
|
|
89
|
+
use_regex (bool, optional): Whether the pattern is a regular expression. Defaults to False.
|
|
90
|
+
case_insensitive (bool, optional): Whether the search should be case-insensitive. Defaults to False.
|
|
91
|
+
context_before (int, optional): Number of context lines to show before matches. Defaults to 5.
|
|
92
|
+
context_after (int, optional): Number of context lines to show after matches. Defaults to 5.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
str: Formatted result indicating success or failure, including matching lines or error message.
|
|
96
|
+
"""
|
|
97
|
+
repo = coder.repo
|
|
98
|
+
if not repo:
|
|
99
|
+
coder.io.tool_error("Not in a git repository.")
|
|
100
|
+
return "Error: Not in a git repository."
|
|
101
|
+
|
|
102
|
+
tool_name, tool_path = cls._find_search_tool()
|
|
103
|
+
if not tool_path:
|
|
104
|
+
coder.io.tool_error("No search tool (rg, ag, grep) found in PATH.")
|
|
105
|
+
return "Error: No search tool (rg, ag, grep) found."
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
search_dir_path = Path(repo.root) / directory
|
|
109
|
+
if not search_dir_path.is_dir():
|
|
110
|
+
coder.io.tool_error(f"Directory not found: {directory}")
|
|
111
|
+
return f"Error: Directory not found: {directory}"
|
|
112
|
+
|
|
113
|
+
# Build the command arguments based on the available tool
|
|
114
|
+
cmd_args = [tool_path]
|
|
115
|
+
|
|
116
|
+
# Common options or tool-specific equivalents
|
|
117
|
+
if tool_name in ["rg", "grep"]:
|
|
118
|
+
cmd_args.append("-n") # Line numbers for rg and grep
|
|
119
|
+
# ag includes line numbers by default
|
|
120
|
+
|
|
121
|
+
if tool_name in ["rg"]:
|
|
122
|
+
cmd_args.append("--heading") # Filename above output for ripgrep
|
|
123
|
+
|
|
124
|
+
# Context lines (Before and After)
|
|
125
|
+
if context_before > 0:
|
|
126
|
+
# All tools use -B for lines before
|
|
127
|
+
cmd_args.extend(["-B", str(context_before)])
|
|
128
|
+
if context_after > 0:
|
|
129
|
+
# All tools use -A for lines after
|
|
130
|
+
cmd_args.extend(["-A", str(context_after)])
|
|
131
|
+
|
|
132
|
+
# Case sensitivity
|
|
133
|
+
if case_insensitive:
|
|
134
|
+
cmd_args.append("-i") # Add case-insensitivity flag for all tools
|
|
135
|
+
|
|
136
|
+
# Pattern type (regex vs fixed string)
|
|
137
|
+
if use_regex:
|
|
138
|
+
if tool_name == "grep":
|
|
139
|
+
cmd_args.append("-E") # Use extended regex for grep
|
|
140
|
+
# rg and ag use regex by default, no flag needed for basic ERE
|
|
141
|
+
else:
|
|
142
|
+
if tool_name == "rg":
|
|
143
|
+
cmd_args.append("-F") # Fixed strings for rg
|
|
144
|
+
elif tool_name == "ag":
|
|
145
|
+
cmd_args.append("-Q") # Literal/fixed strings for ag
|
|
146
|
+
elif tool_name == "grep":
|
|
147
|
+
cmd_args.append("-F") # Fixed strings for grep
|
|
148
|
+
|
|
149
|
+
# File filtering
|
|
150
|
+
if (
|
|
151
|
+
file_pattern != "*"
|
|
152
|
+
): # Avoid adding glob if it's the default '*' which might behave differently
|
|
153
|
+
if tool_name == "rg":
|
|
154
|
+
cmd_args.extend(["-g", file_pattern])
|
|
155
|
+
elif tool_name == "ag":
|
|
156
|
+
cmd_args.extend(["-G", file_pattern])
|
|
157
|
+
elif tool_name == "grep":
|
|
158
|
+
# grep needs recursive flag when filtering
|
|
159
|
+
cmd_args.append("-r")
|
|
160
|
+
cmd_args.append(f"--include={file_pattern}")
|
|
155
161
|
elif tool_name == "grep":
|
|
156
|
-
# grep needs recursive flag
|
|
162
|
+
# grep needs recursive flag even without include filter
|
|
157
163
|
cmd_args.append("-r")
|
|
158
|
-
cmd_args.append(f"--include={file_pattern}")
|
|
159
|
-
elif tool_name == "grep":
|
|
160
|
-
# grep needs recursive flag even without include filter
|
|
161
|
-
cmd_args.append("-r")
|
|
162
|
-
|
|
163
|
-
# Directory exclusion (rg and ag respect .gitignore/.git by default)
|
|
164
|
-
if tool_name == "grep":
|
|
165
|
-
cmd_args.append("--exclude-dir=.git")
|
|
166
|
-
|
|
167
|
-
# Add pattern and directory path
|
|
168
|
-
cmd_args.extend([pattern, str(search_dir_path)])
|
|
169
164
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
command_string
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
165
|
+
# Directory exclusion (rg and ag respect .gitignore/.git by default)
|
|
166
|
+
if tool_name == "grep":
|
|
167
|
+
cmd_args.append("--exclude-dir=.git")
|
|
168
|
+
|
|
169
|
+
# Add pattern and directory path
|
|
170
|
+
cmd_args.extend([pattern, str(search_dir_path)])
|
|
171
|
+
|
|
172
|
+
# Convert list to command string for run_cmd_subprocess
|
|
173
|
+
command_string = oslex.join(cmd_args)
|
|
174
|
+
|
|
175
|
+
coder.io.tool_output(f"⚙️ Executing {tool_name}: {command_string}")
|
|
176
|
+
|
|
177
|
+
# Use run_cmd_subprocess for execution
|
|
178
|
+
# Note: rg, ag, and grep return 1 if no matches are found, which is not an error for this tool.
|
|
179
|
+
exit_status, combined_output = run_cmd_subprocess(
|
|
180
|
+
command_string, verbose=coder.verbose, cwd=coder.root # Execute in the project root
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Format the output for the result message
|
|
184
|
+
output_content = combined_output or ""
|
|
185
|
+
|
|
186
|
+
# Handle exit codes (consistent across rg, ag, grep)
|
|
187
|
+
if exit_status == 0:
|
|
188
|
+
# Limit output size if necessary
|
|
189
|
+
max_output_lines = 50 # Consider making this configurable
|
|
190
|
+
output_lines = output_content.splitlines()
|
|
191
|
+
if len(output_lines) > max_output_lines:
|
|
192
|
+
truncated_output = "\n".join(output_lines[:max_output_lines])
|
|
193
|
+
result_message = (
|
|
194
|
+
f"Found matches (truncated):\n```text\n{truncated_output}\n..."
|
|
195
|
+
f" ({len(output_lines) - max_output_lines} more lines)\n```"
|
|
196
|
+
)
|
|
197
|
+
elif not output_content:
|
|
198
|
+
# Should not happen if return code is 0, but handle defensively
|
|
199
|
+
coder.io.tool_warning(f"{tool_name} returned 0 but produced no output.")
|
|
200
|
+
result_message = "No matches found (unexpected)."
|
|
201
|
+
else:
|
|
202
|
+
result_message = f"Found matches:\n```text\n{output_content}\n```"
|
|
203
|
+
return result_message
|
|
204
|
+
|
|
205
|
+
elif exit_status == 1:
|
|
206
|
+
# Exit code 1 means no matches found - this is expected behavior, not an error.
|
|
207
|
+
return "No matches found."
|
|
199
208
|
else:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
cmd_str_info = f"'{command_string}' " if "command_string" in locals() else ""
|
|
221
|
-
coder.io.tool_error(f"Error executing {tool_name} command {cmd_str_info}: {str(e)}")
|
|
222
|
-
return f"Error executing {tool_name}: {str(e)}"
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def process_response(coder, params):
|
|
226
|
-
"""
|
|
227
|
-
Process the Grep tool response.
|
|
228
|
-
|
|
229
|
-
Args:
|
|
230
|
-
coder: The Coder instance
|
|
231
|
-
params: Dictionary of parameters
|
|
232
|
-
|
|
233
|
-
Returns:
|
|
234
|
-
str: Result message
|
|
235
|
-
"""
|
|
236
|
-
pattern = params.get("pattern")
|
|
237
|
-
file_pattern = params.get("file_pattern", "*") # Default to all files
|
|
238
|
-
directory = params.get("directory", ".") # Default to current directory
|
|
239
|
-
use_regex = params.get("use_regex", False) # Default to literal search
|
|
240
|
-
case_insensitive = params.get("case_insensitive", False) # Default to case-sensitive
|
|
241
|
-
context_before = params.get("context_before", 5)
|
|
242
|
-
context_after = params.get("context_after", 5)
|
|
243
|
-
|
|
244
|
-
if pattern is not None:
|
|
245
|
-
return _execute_grep(
|
|
246
|
-
coder,
|
|
247
|
-
pattern,
|
|
248
|
-
file_pattern,
|
|
249
|
-
directory,
|
|
250
|
-
use_regex,
|
|
251
|
-
case_insensitive,
|
|
252
|
-
context_before,
|
|
253
|
-
context_after,
|
|
254
|
-
)
|
|
255
|
-
else:
|
|
256
|
-
return "Error: Missing required 'pattern' parameter for Grep"
|
|
209
|
+
# Exit code > 1 indicates an actual error
|
|
210
|
+
error_message = (
|
|
211
|
+
f"{tool_name.capitalize()} command failed with exit code {exit_status}."
|
|
212
|
+
)
|
|
213
|
+
if output_content:
|
|
214
|
+
# Truncate error output as well if it's too long
|
|
215
|
+
error_limit = 1000 # Example limit for error output
|
|
216
|
+
if len(output_content) > error_limit:
|
|
217
|
+
output_content = (
|
|
218
|
+
output_content[:error_limit] + "\n... (error output truncated)"
|
|
219
|
+
)
|
|
220
|
+
error_message += f" Output:\n{output_content}"
|
|
221
|
+
coder.io.tool_error(error_message)
|
|
222
|
+
return f"Error: {error_message}"
|
|
223
|
+
|
|
224
|
+
except Exception as e:
|
|
225
|
+
# Add command_string to the error message if it's defined
|
|
226
|
+
cmd_str_info = f"'{command_string}' " if "command_string" in locals() else ""
|
|
227
|
+
coder.io.tool_error(f"Error executing {tool_name} command {cmd_str_info}: {str(e)}")
|
|
228
|
+
return f"Error executing {tool_name}: {str(e)}"
|