aider-ce 0.88.20__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 +20 -0
- aider/__main__.py +4 -0
- aider/_version.py +34 -0
- aider/analytics.py +258 -0
- aider/args.py +1056 -0
- aider/args_formatter.py +228 -0
- aider/change_tracker.py +133 -0
- aider/coders/__init__.py +36 -0
- aider/coders/agent_coder.py +2166 -0
- aider/coders/agent_prompts.py +104 -0
- aider/coders/architect_coder.py +48 -0
- aider/coders/architect_prompts.py +40 -0
- aider/coders/ask_coder.py +9 -0
- aider/coders/ask_prompts.py +35 -0
- aider/coders/base_coder.py +3613 -0
- aider/coders/base_prompts.py +87 -0
- aider/coders/chat_chunks.py +64 -0
- aider/coders/context_coder.py +53 -0
- aider/coders/context_prompts.py +75 -0
- aider/coders/editblock_coder.py +657 -0
- aider/coders/editblock_fenced_coder.py +10 -0
- aider/coders/editblock_fenced_prompts.py +143 -0
- aider/coders/editblock_func_coder.py +141 -0
- aider/coders/editblock_func_prompts.py +27 -0
- aider/coders/editblock_prompts.py +175 -0
- aider/coders/editor_diff_fenced_coder.py +9 -0
- aider/coders/editor_diff_fenced_prompts.py +11 -0
- aider/coders/editor_editblock_coder.py +9 -0
- aider/coders/editor_editblock_prompts.py +21 -0
- aider/coders/editor_whole_coder.py +9 -0
- aider/coders/editor_whole_prompts.py +12 -0
- aider/coders/help_coder.py +16 -0
- aider/coders/help_prompts.py +46 -0
- aider/coders/patch_coder.py +706 -0
- aider/coders/patch_prompts.py +159 -0
- aider/coders/search_replace.py +757 -0
- aider/coders/shell.py +37 -0
- aider/coders/single_wholefile_func_coder.py +102 -0
- aider/coders/single_wholefile_func_prompts.py +27 -0
- aider/coders/udiff_coder.py +429 -0
- aider/coders/udiff_prompts.py +115 -0
- aider/coders/udiff_simple.py +14 -0
- aider/coders/udiff_simple_prompts.py +25 -0
- aider/coders/wholefile_coder.py +144 -0
- aider/coders/wholefile_func_coder.py +134 -0
- aider/coders/wholefile_func_prompts.py +27 -0
- aider/coders/wholefile_prompts.py +65 -0
- aider/commands.py +2173 -0
- aider/copypaste.py +72 -0
- aider/deprecated.py +126 -0
- aider/diffs.py +128 -0
- aider/dump.py +29 -0
- aider/editor.py +147 -0
- aider/exceptions.py +115 -0
- aider/format_settings.py +26 -0
- aider/gui.py +545 -0
- aider/help.py +163 -0
- aider/help_pats.py +19 -0
- aider/helpers/__init__.py +9 -0
- aider/helpers/similarity.py +98 -0
- aider/history.py +180 -0
- aider/io.py +1608 -0
- aider/linter.py +304 -0
- aider/llm.py +55 -0
- aider/main.py +1415 -0
- aider/mcp/__init__.py +174 -0
- aider/mcp/server.py +149 -0
- aider/mdstream.py +243 -0
- aider/models.py +1313 -0
- aider/onboarding.py +429 -0
- aider/openrouter.py +129 -0
- aider/prompts.py +56 -0
- aider/queries/tree-sitter-language-pack/README.md +7 -0
- aider/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/c-tags.scm +9 -0
- aider/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
- aider/queries/tree-sitter-language-pack/clojure-tags.scm +7 -0
- aider/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
- aider/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
- aider/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
- aider/queries/tree-sitter-language-pack/d-tags.scm +26 -0
- aider/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
- aider/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
- aider/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
- aider/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
- aider/queries/tree-sitter-language-pack/go-tags.scm +42 -0
- aider/queries/tree-sitter-language-pack/java-tags.scm +20 -0
- aider/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
- aider/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
- aider/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
- aider/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
- aider/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
- aider/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
- aider/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
- aider/queries/tree-sitter-language-pack/python-tags.scm +14 -0
- aider/queries/tree-sitter-language-pack/r-tags.scm +21 -0
- aider/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
- aider/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
- aider/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
- aider/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
- aider/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
- aider/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
- aider/queries/tree-sitter-languages/README.md +24 -0
- aider/queries/tree-sitter-languages/c-tags.scm +9 -0
- aider/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
- aider/queries/tree-sitter-languages/cpp-tags.scm +15 -0
- aider/queries/tree-sitter-languages/dart-tags.scm +91 -0
- aider/queries/tree-sitter-languages/elisp-tags.scm +8 -0
- aider/queries/tree-sitter-languages/elixir-tags.scm +54 -0
- aider/queries/tree-sitter-languages/elm-tags.scm +19 -0
- aider/queries/tree-sitter-languages/fortran-tags.scm +15 -0
- aider/queries/tree-sitter-languages/go-tags.scm +30 -0
- aider/queries/tree-sitter-languages/haskell-tags.scm +3 -0
- aider/queries/tree-sitter-languages/hcl-tags.scm +77 -0
- aider/queries/tree-sitter-languages/java-tags.scm +20 -0
- aider/queries/tree-sitter-languages/javascript-tags.scm +88 -0
- aider/queries/tree-sitter-languages/julia-tags.scm +60 -0
- aider/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
- aider/queries/tree-sitter-languages/matlab-tags.scm +10 -0
- aider/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
- aider/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
- aider/queries/tree-sitter-languages/php-tags.scm +26 -0
- aider/queries/tree-sitter-languages/python-tags.scm +12 -0
- aider/queries/tree-sitter-languages/ql-tags.scm +26 -0
- aider/queries/tree-sitter-languages/ruby-tags.scm +64 -0
- aider/queries/tree-sitter-languages/rust-tags.scm +60 -0
- aider/queries/tree-sitter-languages/scala-tags.scm +65 -0
- aider/queries/tree-sitter-languages/typescript-tags.scm +41 -0
- aider/queries/tree-sitter-languages/zig-tags.scm +3 -0
- aider/reasoning_tags.py +82 -0
- aider/repo.py +621 -0
- aider/repomap.py +1174 -0
- aider/report.py +260 -0
- aider/resources/__init__.py +3 -0
- aider/resources/model-metadata.json +776 -0
- aider/resources/model-settings.yml +2068 -0
- aider/run_cmd.py +133 -0
- aider/scrape.py +293 -0
- aider/sendchat.py +242 -0
- aider/sessions.py +256 -0
- aider/special.py +203 -0
- aider/tools/__init__.py +72 -0
- aider/tools/command.py +105 -0
- aider/tools/command_interactive.py +122 -0
- aider/tools/delete_block.py +182 -0
- aider/tools/delete_line.py +155 -0
- aider/tools/delete_lines.py +184 -0
- aider/tools/extract_lines.py +341 -0
- aider/tools/finished.py +48 -0
- aider/tools/git_branch.py +129 -0
- aider/tools/git_diff.py +60 -0
- aider/tools/git_log.py +57 -0
- aider/tools/git_remote.py +53 -0
- aider/tools/git_show.py +51 -0
- aider/tools/git_status.py +46 -0
- aider/tools/grep.py +256 -0
- aider/tools/indent_lines.py +221 -0
- aider/tools/insert_block.py +288 -0
- aider/tools/list_changes.py +86 -0
- aider/tools/ls.py +93 -0
- aider/tools/make_editable.py +85 -0
- aider/tools/make_readonly.py +69 -0
- aider/tools/remove.py +91 -0
- aider/tools/replace_all.py +126 -0
- aider/tools/replace_line.py +173 -0
- aider/tools/replace_lines.py +217 -0
- aider/tools/replace_text.py +187 -0
- aider/tools/show_numbered_context.py +147 -0
- aider/tools/tool_utils.py +313 -0
- aider/tools/undo_change.py +95 -0
- aider/tools/update_todo_list.py +156 -0
- aider/tools/view.py +57 -0
- aider/tools/view_files_matching.py +141 -0
- aider/tools/view_files_with_symbol.py +129 -0
- aider/urls.py +17 -0
- aider/utils.py +456 -0
- aider/versioncheck.py +113 -0
- aider/voice.py +205 -0
- aider/waiting.py +38 -0
- aider/watch.py +318 -0
- aider/watch_prompts.py +12 -0
- aider/website/Gemfile +8 -0
- aider/website/_includes/blame.md +162 -0
- aider/website/_includes/get-started.md +22 -0
- aider/website/_includes/help-tip.md +5 -0
- aider/website/_includes/help.md +24 -0
- aider/website/_includes/install.md +5 -0
- aider/website/_includes/keys.md +4 -0
- aider/website/_includes/model-warnings.md +67 -0
- aider/website/_includes/multi-line.md +22 -0
- aider/website/_includes/python-m-aider.md +5 -0
- aider/website/_includes/recording.css +228 -0
- aider/website/_includes/recording.md +34 -0
- aider/website/_includes/replit-pipx.md +9 -0
- aider/website/_includes/works-best.md +1 -0
- aider/website/_sass/custom/custom.scss +103 -0
- aider/website/docs/config/adv-model-settings.md +2261 -0
- aider/website/docs/config/agent-mode.md +194 -0
- aider/website/docs/config/aider_conf.md +548 -0
- aider/website/docs/config/api-keys.md +90 -0
- aider/website/docs/config/dotenv.md +493 -0
- aider/website/docs/config/editor.md +127 -0
- aider/website/docs/config/mcp.md +95 -0
- aider/website/docs/config/model-aliases.md +104 -0
- aider/website/docs/config/options.md +890 -0
- aider/website/docs/config/reasoning.md +210 -0
- aider/website/docs/config.md +44 -0
- aider/website/docs/faq.md +384 -0
- aider/website/docs/git.md +76 -0
- aider/website/docs/index.md +47 -0
- aider/website/docs/install/codespaces.md +39 -0
- aider/website/docs/install/docker.md +57 -0
- aider/website/docs/install/optional.md +100 -0
- aider/website/docs/install/replit.md +8 -0
- aider/website/docs/install.md +115 -0
- aider/website/docs/languages.md +264 -0
- aider/website/docs/legal/contributor-agreement.md +111 -0
- aider/website/docs/legal/privacy.md +104 -0
- aider/website/docs/llms/anthropic.md +77 -0
- aider/website/docs/llms/azure.md +48 -0
- aider/website/docs/llms/bedrock.md +132 -0
- aider/website/docs/llms/cohere.md +34 -0
- aider/website/docs/llms/deepseek.md +32 -0
- aider/website/docs/llms/gemini.md +49 -0
- aider/website/docs/llms/github.md +111 -0
- aider/website/docs/llms/groq.md +36 -0
- aider/website/docs/llms/lm-studio.md +39 -0
- aider/website/docs/llms/ollama.md +75 -0
- aider/website/docs/llms/openai-compat.md +39 -0
- aider/website/docs/llms/openai.md +58 -0
- aider/website/docs/llms/openrouter.md +78 -0
- aider/website/docs/llms/other.md +117 -0
- aider/website/docs/llms/vertex.md +50 -0
- aider/website/docs/llms/warnings.md +10 -0
- aider/website/docs/llms/xai.md +53 -0
- aider/website/docs/llms.md +54 -0
- aider/website/docs/more/analytics.md +127 -0
- aider/website/docs/more/edit-formats.md +116 -0
- aider/website/docs/more/infinite-output.md +165 -0
- aider/website/docs/more-info.md +8 -0
- aider/website/docs/recordings/auto-accept-architect.md +31 -0
- aider/website/docs/recordings/dont-drop-original-read-files.md +35 -0
- aider/website/docs/recordings/index.md +21 -0
- aider/website/docs/recordings/model-accepts-settings.md +69 -0
- aider/website/docs/recordings/tree-sitter-language-pack.md +80 -0
- aider/website/docs/repomap.md +112 -0
- aider/website/docs/scripting.md +100 -0
- aider/website/docs/sessions.md +203 -0
- aider/website/docs/troubleshooting/aider-not-found.md +24 -0
- aider/website/docs/troubleshooting/edit-errors.md +76 -0
- aider/website/docs/troubleshooting/imports.md +62 -0
- aider/website/docs/troubleshooting/models-and-keys.md +54 -0
- aider/website/docs/troubleshooting/support.md +79 -0
- aider/website/docs/troubleshooting/token-limits.md +96 -0
- aider/website/docs/troubleshooting/warnings.md +12 -0
- aider/website/docs/troubleshooting.md +11 -0
- aider/website/docs/usage/browser.md +57 -0
- aider/website/docs/usage/caching.md +49 -0
- aider/website/docs/usage/commands.md +133 -0
- aider/website/docs/usage/conventions.md +119 -0
- aider/website/docs/usage/copypaste.md +121 -0
- aider/website/docs/usage/images-urls.md +48 -0
- aider/website/docs/usage/lint-test.md +118 -0
- aider/website/docs/usage/modes.md +211 -0
- aider/website/docs/usage/not-code.md +179 -0
- aider/website/docs/usage/notifications.md +87 -0
- aider/website/docs/usage/tips.md +79 -0
- aider/website/docs/usage/tutorials.md +30 -0
- aider/website/docs/usage/voice.md +121 -0
- aider/website/docs/usage/watch.md +294 -0
- aider/website/docs/usage.md +102 -0
- aider/website/share/index.md +101 -0
- aider_ce-0.88.20.dist-info/METADATA +187 -0
- aider_ce-0.88.20.dist-info/RECORD +279 -0
- aider_ce-0.88.20.dist-info/WHEEL +5 -0
- aider_ce-0.88.20.dist-info/entry_points.txt +2 -0
- aider_ce-0.88.20.dist-info/licenses/LICENSE.txt +202 -0
- aider_ce-0.88.20.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import traceback
|
|
3
|
+
|
|
4
|
+
from .tool_utils import generate_unified_diff_snippet
|
|
5
|
+
|
|
6
|
+
schema = {
|
|
7
|
+
"type": "function",
|
|
8
|
+
"function": {
|
|
9
|
+
"name": "ExtractLines",
|
|
10
|
+
"description": "Extract lines from a source file and append them to a target file.",
|
|
11
|
+
"parameters": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"source_file_path": {"type": "string"},
|
|
15
|
+
"target_file_path": {"type": "string"},
|
|
16
|
+
"start_pattern": {"type": "string"},
|
|
17
|
+
"end_pattern": {"type": "string"},
|
|
18
|
+
"line_count": {"type": "integer"},
|
|
19
|
+
"near_context": {"type": "string"},
|
|
20
|
+
"occurrence": {"type": "integer", "default": 1},
|
|
21
|
+
"dry_run": {"type": "boolean", "default": False},
|
|
22
|
+
},
|
|
23
|
+
"required": ["source_file_path", "target_file_path", "start_pattern"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Normalized tool name for lookup
|
|
29
|
+
NORM_NAME = "extractlines"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _execute_extract_lines(
|
|
33
|
+
coder,
|
|
34
|
+
source_file_path,
|
|
35
|
+
target_file_path,
|
|
36
|
+
start_pattern,
|
|
37
|
+
end_pattern=None,
|
|
38
|
+
line_count=None,
|
|
39
|
+
near_context=None,
|
|
40
|
+
occurrence=1,
|
|
41
|
+
dry_run=False,
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Extract a range of lines from a source file and move them to a target file.
|
|
45
|
+
|
|
46
|
+
Parameters:
|
|
47
|
+
- coder: The Coder instance
|
|
48
|
+
- source_file_path: Path to the file to extract lines from
|
|
49
|
+
- target_file_path: Path to the file to append extracted lines to (will be created if needed)
|
|
50
|
+
- start_pattern: Pattern marking the start of the block to extract
|
|
51
|
+
- end_pattern: Optional pattern marking the end of the block
|
|
52
|
+
- line_count: Optional number of lines to extract (alternative to end_pattern)
|
|
53
|
+
- near_context: Optional text nearby to help locate the correct instance of the start_pattern
|
|
54
|
+
- occurrence: Which occurrence of the start_pattern to use (1-based index, or -1 for last)
|
|
55
|
+
- dry_run: If True, simulate the change without modifying files
|
|
56
|
+
|
|
57
|
+
Returns a result message.
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
# --- Validate Source File ---
|
|
61
|
+
abs_source_path = coder.abs_root_path(source_file_path)
|
|
62
|
+
rel_source_path = coder.get_rel_fname(abs_source_path)
|
|
63
|
+
|
|
64
|
+
if not os.path.isfile(abs_source_path):
|
|
65
|
+
coder.io.tool_error(f"Source file '{source_file_path}' not found")
|
|
66
|
+
return "Error: Source file not found"
|
|
67
|
+
|
|
68
|
+
if abs_source_path not in coder.abs_fnames:
|
|
69
|
+
if abs_source_path in coder.abs_read_only_fnames:
|
|
70
|
+
coder.io.tool_error(
|
|
71
|
+
f"Source file '{source_file_path}' is read-only. Use MakeEditable first."
|
|
72
|
+
)
|
|
73
|
+
return "Error: Source file is read-only. Use MakeEditable first."
|
|
74
|
+
else:
|
|
75
|
+
coder.io.tool_error(f"Source file '{source_file_path}' not in context")
|
|
76
|
+
return "Error: Source file not in context"
|
|
77
|
+
|
|
78
|
+
# --- Validate Target File ---
|
|
79
|
+
abs_target_path = coder.abs_root_path(target_file_path)
|
|
80
|
+
rel_target_path = coder.get_rel_fname(abs_target_path)
|
|
81
|
+
target_exists = os.path.isfile(abs_target_path)
|
|
82
|
+
target_is_editable = abs_target_path in coder.abs_fnames
|
|
83
|
+
target_is_readonly = abs_target_path in coder.abs_read_only_fnames
|
|
84
|
+
|
|
85
|
+
if target_exists and not target_is_editable:
|
|
86
|
+
if target_is_readonly:
|
|
87
|
+
coder.io.tool_error(
|
|
88
|
+
f"Target file '{target_file_path}' exists but is read-only. Use MakeEditable"
|
|
89
|
+
" first."
|
|
90
|
+
)
|
|
91
|
+
return "Error: Target file exists but is read-only. Use MakeEditable first."
|
|
92
|
+
else:
|
|
93
|
+
# This case shouldn't happen if file exists, but handle defensively
|
|
94
|
+
coder.io.tool_error(
|
|
95
|
+
f"Target file '{target_file_path}' exists but is not in context. Add it first."
|
|
96
|
+
)
|
|
97
|
+
return "Error: Target file exists but is not in context."
|
|
98
|
+
|
|
99
|
+
# --- Read Source Content ---
|
|
100
|
+
source_content = coder.io.read_text(abs_source_path)
|
|
101
|
+
if source_content is None:
|
|
102
|
+
coder.io.tool_error(
|
|
103
|
+
f"Could not read source file '{source_file_path}' before ExtractLines operation."
|
|
104
|
+
)
|
|
105
|
+
return f"Error: Could not read source file '{source_file_path}'"
|
|
106
|
+
|
|
107
|
+
# --- Find Extraction Range ---
|
|
108
|
+
if end_pattern and line_count:
|
|
109
|
+
coder.io.tool_error("Cannot specify both end_pattern and line_count")
|
|
110
|
+
return "Error: Cannot specify both end_pattern and line_count"
|
|
111
|
+
|
|
112
|
+
source_lines = source_content.splitlines()
|
|
113
|
+
original_source_content = source_content
|
|
114
|
+
|
|
115
|
+
start_pattern_line_indices = []
|
|
116
|
+
for i, line in enumerate(source_lines):
|
|
117
|
+
if start_pattern in line:
|
|
118
|
+
if near_context:
|
|
119
|
+
context_window_start = max(0, i - 5)
|
|
120
|
+
context_window_end = min(len(source_lines), i + 6)
|
|
121
|
+
context_block = "\n".join(source_lines[context_window_start:context_window_end])
|
|
122
|
+
if near_context in context_block:
|
|
123
|
+
start_pattern_line_indices.append(i)
|
|
124
|
+
else:
|
|
125
|
+
start_pattern_line_indices.append(i)
|
|
126
|
+
|
|
127
|
+
if not start_pattern_line_indices:
|
|
128
|
+
err_msg = f"Start pattern '{start_pattern}' not found"
|
|
129
|
+
if near_context:
|
|
130
|
+
err_msg += f" near context '{near_context}'"
|
|
131
|
+
err_msg += f" in source file '{source_file_path}'."
|
|
132
|
+
coder.io.tool_error(err_msg)
|
|
133
|
+
return f"Error: {err_msg}"
|
|
134
|
+
|
|
135
|
+
num_occurrences = len(start_pattern_line_indices)
|
|
136
|
+
try:
|
|
137
|
+
occurrence = int(occurrence)
|
|
138
|
+
if occurrence == -1:
|
|
139
|
+
target_idx = num_occurrences - 1
|
|
140
|
+
elif occurrence > 0 and occurrence <= num_occurrences:
|
|
141
|
+
target_idx = occurrence - 1
|
|
142
|
+
else:
|
|
143
|
+
err_msg = (
|
|
144
|
+
f"Occurrence number {occurrence} is out of range for start pattern"
|
|
145
|
+
f" '{start_pattern}'. Found {num_occurrences} occurrences"
|
|
146
|
+
)
|
|
147
|
+
if near_context:
|
|
148
|
+
err_msg += f" near '{near_context}'"
|
|
149
|
+
err_msg += f" in '{source_file_path}'."
|
|
150
|
+
coder.io.tool_error(err_msg)
|
|
151
|
+
return f"Error: {err_msg}"
|
|
152
|
+
except ValueError:
|
|
153
|
+
coder.io.tool_error(f"Invalid occurrence value: '{occurrence}'. Must be an integer.")
|
|
154
|
+
return f"Error: Invalid occurrence value '{occurrence}'"
|
|
155
|
+
|
|
156
|
+
start_line = start_pattern_line_indices[target_idx]
|
|
157
|
+
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
|
158
|
+
|
|
159
|
+
end_line = -1
|
|
160
|
+
if end_pattern:
|
|
161
|
+
for i in range(start_line, len(source_lines)):
|
|
162
|
+
if end_pattern in source_lines[i]:
|
|
163
|
+
end_line = i
|
|
164
|
+
break
|
|
165
|
+
if end_line == -1:
|
|
166
|
+
err_msg = (
|
|
167
|
+
f"End pattern '{end_pattern}' not found after {occurrence_str}start pattern"
|
|
168
|
+
f" '{start_pattern}' (line {start_line + 1}) in '{source_file_path}'."
|
|
169
|
+
)
|
|
170
|
+
coder.io.tool_error(err_msg)
|
|
171
|
+
return f"Error: {err_msg}"
|
|
172
|
+
elif line_count:
|
|
173
|
+
try:
|
|
174
|
+
line_count = int(line_count)
|
|
175
|
+
if line_count <= 0:
|
|
176
|
+
raise ValueError("Line count must be positive")
|
|
177
|
+
end_line = min(start_line + line_count - 1, len(source_lines) - 1)
|
|
178
|
+
except ValueError:
|
|
179
|
+
coder.io.tool_error(
|
|
180
|
+
f"Invalid line_count value: '{line_count}'. Must be a positive integer."
|
|
181
|
+
)
|
|
182
|
+
return f"Error: Invalid line_count value '{line_count}'"
|
|
183
|
+
else:
|
|
184
|
+
end_line = start_line # Extract just the start line if no end specified
|
|
185
|
+
|
|
186
|
+
# --- Prepare Content Changes ---
|
|
187
|
+
extracted_lines = source_lines[start_line : end_line + 1]
|
|
188
|
+
new_source_lines = source_lines[:start_line] + source_lines[end_line + 1 :]
|
|
189
|
+
new_source_content = "\n".join(new_source_lines)
|
|
190
|
+
|
|
191
|
+
target_content = ""
|
|
192
|
+
if target_exists:
|
|
193
|
+
target_content = coder.io.read_text(abs_target_path)
|
|
194
|
+
if target_content is None:
|
|
195
|
+
coder.io.tool_error(f"Could not read existing target file '{target_file_path}'.")
|
|
196
|
+
return f"Error: Could not read target file '{target_file_path}'"
|
|
197
|
+
original_target_content = target_content # For tracking
|
|
198
|
+
|
|
199
|
+
# Append extracted lines to target content, ensuring a newline if target wasn't empty
|
|
200
|
+
extracted_block = "\n".join(extracted_lines)
|
|
201
|
+
if target_content and not target_content.endswith("\n"):
|
|
202
|
+
target_content += "\n" # Add newline before appending if needed
|
|
203
|
+
new_target_content = target_content + extracted_block
|
|
204
|
+
|
|
205
|
+
# --- Generate Diffs ---
|
|
206
|
+
source_diff_snippet = generate_unified_diff_snippet(
|
|
207
|
+
original_source_content, new_source_content, rel_source_path
|
|
208
|
+
)
|
|
209
|
+
target_insertion_line = len(target_content.splitlines()) if target_content else 0
|
|
210
|
+
target_diff_snippet = generate_unified_diff_snippet(
|
|
211
|
+
original_target_content, new_target_content, rel_target_path
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# --- Handle Dry Run ---
|
|
215
|
+
if dry_run:
|
|
216
|
+
num_extracted = end_line - start_line + 1
|
|
217
|
+
target_action = "append to" if target_exists else "create"
|
|
218
|
+
coder.io.tool_output(
|
|
219
|
+
f"Dry run: Would extract {num_extracted} lines (from {occurrence_str}start pattern"
|
|
220
|
+
f" '{start_pattern}') in {source_file_path} and {target_action} {target_file_path}"
|
|
221
|
+
)
|
|
222
|
+
# Provide more informative dry run response with diffs
|
|
223
|
+
return (
|
|
224
|
+
f"Dry run: Would extract {num_extracted} lines from {rel_source_path} and"
|
|
225
|
+
f" {target_action} {rel_target_path}.\nSource Diff"
|
|
226
|
+
f" (Deletion):\n{source_diff_snippet}\nTarget Diff"
|
|
227
|
+
f" (Insertion):\n{target_diff_snippet}"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# --- Apply Changes (Not Dry Run) ---
|
|
231
|
+
coder.io.write_text(abs_source_path, new_source_content)
|
|
232
|
+
coder.io.write_text(abs_target_path, new_target_content)
|
|
233
|
+
|
|
234
|
+
# --- Track Changes ---
|
|
235
|
+
source_change_id = "TRACKING_FAILED"
|
|
236
|
+
target_change_id = "TRACKING_FAILED"
|
|
237
|
+
try:
|
|
238
|
+
source_metadata = {
|
|
239
|
+
"start_line": start_line + 1,
|
|
240
|
+
"end_line": end_line + 1,
|
|
241
|
+
"start_pattern": start_pattern,
|
|
242
|
+
"end_pattern": end_pattern,
|
|
243
|
+
"line_count": line_count,
|
|
244
|
+
"near_context": near_context,
|
|
245
|
+
"occurrence": occurrence,
|
|
246
|
+
"extracted_content": extracted_block,
|
|
247
|
+
"target_file": rel_target_path,
|
|
248
|
+
}
|
|
249
|
+
source_change_id = coder.change_tracker.track_change(
|
|
250
|
+
file_path=rel_source_path,
|
|
251
|
+
change_type="extractlines_source",
|
|
252
|
+
original_content=original_source_content,
|
|
253
|
+
new_content=new_source_content,
|
|
254
|
+
metadata=source_metadata,
|
|
255
|
+
)
|
|
256
|
+
except Exception as track_e:
|
|
257
|
+
coder.io.tool_error(f"Error tracking source change for ExtractLines: {track_e}")
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
target_metadata = {
|
|
261
|
+
"insertion_line": target_insertion_line + 1,
|
|
262
|
+
"inserted_content": extracted_block,
|
|
263
|
+
"source_file": rel_source_path,
|
|
264
|
+
}
|
|
265
|
+
target_change_id = coder.change_tracker.track_change(
|
|
266
|
+
file_path=rel_target_path,
|
|
267
|
+
change_type="extractlines_target",
|
|
268
|
+
original_content=original_target_content,
|
|
269
|
+
new_content=new_target_content,
|
|
270
|
+
metadata=target_metadata,
|
|
271
|
+
)
|
|
272
|
+
except Exception as track_e:
|
|
273
|
+
coder.io.tool_error(f"Error tracking target change for ExtractLines: {track_e}")
|
|
274
|
+
|
|
275
|
+
# --- Update Context ---
|
|
276
|
+
coder.files_edited_by_tools.add(rel_source_path)
|
|
277
|
+
coder.files_edited_by_tools.add(rel_target_path)
|
|
278
|
+
|
|
279
|
+
if not target_exists:
|
|
280
|
+
# Add the newly created file to editable context
|
|
281
|
+
coder.abs_fnames.add(abs_target_path)
|
|
282
|
+
coder.io.tool_output(f"✨ Created and added '{target_file_path}' to editable context.")
|
|
283
|
+
|
|
284
|
+
# --- Return Result ---
|
|
285
|
+
num_extracted = end_line - start_line + 1
|
|
286
|
+
target_action = "appended to" if target_exists else "created"
|
|
287
|
+
coder.io.tool_output(
|
|
288
|
+
f"✅ Extracted {num_extracted} lines from {rel_source_path} (change_id:"
|
|
289
|
+
f" {source_change_id}) and {target_action} {rel_target_path} (change_id:"
|
|
290
|
+
f" {target_change_id})"
|
|
291
|
+
)
|
|
292
|
+
# Provide more informative success response with change IDs and diffs
|
|
293
|
+
return (
|
|
294
|
+
f"Successfully extracted {num_extracted} lines from {rel_source_path} and"
|
|
295
|
+
f" {target_action} {rel_target_path}.\nSource Change ID: {source_change_id}\nSource"
|
|
296
|
+
f" Diff (Deletion):\n{source_diff_snippet}\nTarget Change ID:"
|
|
297
|
+
f" {target_change_id}\nTarget Diff (Insertion):\n{target_diff_snippet}"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
except Exception as e:
|
|
301
|
+
coder.io.tool_error(f"Error in ExtractLines: {str(e)}\n{traceback.format_exc()}")
|
|
302
|
+
return f"Error: {str(e)}"
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def process_response(coder, params):
|
|
306
|
+
"""
|
|
307
|
+
Process the ExtractLines tool response.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
coder: The Coder instance
|
|
311
|
+
params: Dictionary of parameters
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
str: Result message
|
|
315
|
+
"""
|
|
316
|
+
source_file_path = params.get("source_file_path")
|
|
317
|
+
target_file_path = params.get("target_file_path")
|
|
318
|
+
start_pattern = params.get("start_pattern")
|
|
319
|
+
end_pattern = params.get("end_pattern")
|
|
320
|
+
line_count = params.get("line_count")
|
|
321
|
+
near_context = params.get("near_context")
|
|
322
|
+
occurrence = params.get("occurrence", 1)
|
|
323
|
+
dry_run = params.get("dry_run", False)
|
|
324
|
+
|
|
325
|
+
if source_file_path and target_file_path and start_pattern:
|
|
326
|
+
return _execute_extract_lines(
|
|
327
|
+
coder,
|
|
328
|
+
source_file_path,
|
|
329
|
+
target_file_path,
|
|
330
|
+
start_pattern,
|
|
331
|
+
end_pattern,
|
|
332
|
+
line_count,
|
|
333
|
+
near_context,
|
|
334
|
+
occurrence,
|
|
335
|
+
dry_run,
|
|
336
|
+
)
|
|
337
|
+
else:
|
|
338
|
+
return (
|
|
339
|
+
"Error: Missing required parameters for ExtractLines (source_file_path,"
|
|
340
|
+
" target_file_path, start_pattern)"
|
|
341
|
+
)
|
aider/tools/finished.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
schema = {
|
|
2
|
+
"type": "function",
|
|
3
|
+
"function": {
|
|
4
|
+
"name": "Finished",
|
|
5
|
+
"description": (
|
|
6
|
+
"Declare that we are done with every single sub goal and no further work is needed."
|
|
7
|
+
),
|
|
8
|
+
"parameters": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"required": [],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Normalized tool name for lookup
|
|
17
|
+
NORM_NAME = "finished"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _execute_finished(coder):
|
|
21
|
+
"""
|
|
22
|
+
Mark that the current generation task needs no further effort.
|
|
23
|
+
|
|
24
|
+
This gives the LLM explicit control over when it can stop looping
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
if coder:
|
|
28
|
+
coder.agent_finished = True
|
|
29
|
+
# coder.io.tool_output("Task Finished!")
|
|
30
|
+
return "Task Finished!"
|
|
31
|
+
|
|
32
|
+
# coder.io.tool_Error("Error: Could not mark agent task as finished")
|
|
33
|
+
return "Error: Could not mark agent task as finished"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def process_response(coder, params):
|
|
37
|
+
"""
|
|
38
|
+
Process the Finished tool response.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
coder: The Coder instance
|
|
42
|
+
params: Dictionary of parameters (should be empty for Finished)
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
str: Result message
|
|
46
|
+
"""
|
|
47
|
+
# Finished tool has no parameters to validate
|
|
48
|
+
return _execute_finished(coder)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
from aider.repo import ANY_GIT_ERROR
|
|
2
|
+
|
|
3
|
+
schema = {
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "GitBranch",
|
|
7
|
+
"description": (
|
|
8
|
+
"List branches in the repository with various filtering and formatting options."
|
|
9
|
+
),
|
|
10
|
+
"parameters": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"remotes": {
|
|
14
|
+
"type": "boolean",
|
|
15
|
+
"description": "List remote-tracking branches (-r/--remotes flag)",
|
|
16
|
+
},
|
|
17
|
+
"all": {
|
|
18
|
+
"type": "boolean",
|
|
19
|
+
"description": "List both local and remote branches (-a/--all flag)",
|
|
20
|
+
},
|
|
21
|
+
"verbose": {
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"description": (
|
|
24
|
+
"Show verbose information including commit hash and subject (-v flag)"
|
|
25
|
+
),
|
|
26
|
+
},
|
|
27
|
+
"very_verbose": {
|
|
28
|
+
"type": "boolean",
|
|
29
|
+
"description": (
|
|
30
|
+
"Show very verbose information including upstream branch (-vv flag)"
|
|
31
|
+
),
|
|
32
|
+
},
|
|
33
|
+
"merged": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"description": "Show branches merged into specified commit (--merged flag)",
|
|
36
|
+
},
|
|
37
|
+
"no_merged": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": (
|
|
40
|
+
"Show branches not merged into specified commit (--no-merged flag)"
|
|
41
|
+
),
|
|
42
|
+
},
|
|
43
|
+
"sort": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"description": (
|
|
46
|
+
"Sort branches by key (committerdate, authordate, refname, etc.) (--sort"
|
|
47
|
+
" flag)"
|
|
48
|
+
),
|
|
49
|
+
},
|
|
50
|
+
"format": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "Custom output format using placeholders (--format flag)",
|
|
53
|
+
},
|
|
54
|
+
"show_current": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"description": "Show only current branch name (--show-current flag)",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
"required": [],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Normalized tool name for lookup
|
|
65
|
+
NORM_NAME = "gitbranch"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _execute_git_branch(coder, params=None):
|
|
69
|
+
"""
|
|
70
|
+
List branches in the repository with various filtering and formatting options.
|
|
71
|
+
"""
|
|
72
|
+
if not coder.repo:
|
|
73
|
+
return "Not in a git repository."
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
# Build git command arguments
|
|
77
|
+
args = []
|
|
78
|
+
|
|
79
|
+
# Handle boolean flags
|
|
80
|
+
if params:
|
|
81
|
+
if params.get("remotes"):
|
|
82
|
+
args.append("--remotes")
|
|
83
|
+
if params.get("all"):
|
|
84
|
+
args.append("--all")
|
|
85
|
+
if params.get("verbose"):
|
|
86
|
+
args.append("--verbose")
|
|
87
|
+
if params.get("very_verbose"):
|
|
88
|
+
args.append("--verbose")
|
|
89
|
+
args.append("--verbose")
|
|
90
|
+
if params.get("show_current"):
|
|
91
|
+
args.append("--show-current")
|
|
92
|
+
|
|
93
|
+
# Handle string parameters
|
|
94
|
+
if params.get("merged"):
|
|
95
|
+
args.extend(["--merged", params["merged"]])
|
|
96
|
+
if params.get("no_merged"):
|
|
97
|
+
args.extend(["--no-merged", params["no_merged"]])
|
|
98
|
+
if params.get("sort"):
|
|
99
|
+
args.extend(["--sort", params["sort"]])
|
|
100
|
+
if params.get("format"):
|
|
101
|
+
args.extend(["--format", params["format"]])
|
|
102
|
+
|
|
103
|
+
# Execute git command
|
|
104
|
+
result = coder.repo.repo.git.branch(*args)
|
|
105
|
+
|
|
106
|
+
# If no result and show_current was used, get current branch directly
|
|
107
|
+
if not result and params and params.get("show_current"):
|
|
108
|
+
current_branch = coder.repo.repo.active_branch.name
|
|
109
|
+
return current_branch
|
|
110
|
+
|
|
111
|
+
return result if result else "No branches found matching the criteria."
|
|
112
|
+
|
|
113
|
+
except ANY_GIT_ERROR as e:
|
|
114
|
+
coder.io.tool_error(f"Error running git branch: {e}")
|
|
115
|
+
return f"Error running git branch: {e}"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def process_response(coder, params):
|
|
119
|
+
"""
|
|
120
|
+
Process the GitBranch tool response.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
coder: The Coder instance
|
|
124
|
+
params: Dictionary of parameters for GitBranch
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: Result message
|
|
128
|
+
"""
|
|
129
|
+
return _execute_git_branch(coder, params)
|
aider/tools/git_diff.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from aider.repo import ANY_GIT_ERROR
|
|
2
|
+
|
|
3
|
+
schema = {
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "GitDiff",
|
|
7
|
+
"description": (
|
|
8
|
+
"Show the diff between the current working directory and a git branch or commit."
|
|
9
|
+
),
|
|
10
|
+
"parameters": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"branch": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "The branch or commit hash to diff against. Defaults to HEAD.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
"required": [],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Normalized tool name for lookup
|
|
24
|
+
NORM_NAME = "gitdiff"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _execute_git_diff(coder, branch=None):
|
|
28
|
+
"""
|
|
29
|
+
Show the diff between the current working directory and a git branch or commit.
|
|
30
|
+
"""
|
|
31
|
+
if not coder.repo:
|
|
32
|
+
return "Not in a git repository."
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
if branch:
|
|
36
|
+
diff = coder.repo.diff_commits(False, branch, "HEAD")
|
|
37
|
+
else:
|
|
38
|
+
diff = coder.repo.diff_commits(False, "HEAD", None)
|
|
39
|
+
|
|
40
|
+
if not diff:
|
|
41
|
+
return "No differences found."
|
|
42
|
+
return diff
|
|
43
|
+
except ANY_GIT_ERROR as e:
|
|
44
|
+
coder.io.tool_error(f"Error running git diff: {e}")
|
|
45
|
+
return f"Error running git diff: {e}"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def process_response(coder, params):
|
|
49
|
+
"""
|
|
50
|
+
Process the GitDiff tool response.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
coder: The Coder instance
|
|
54
|
+
params: Dictionary of parameters
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str: Result message
|
|
58
|
+
"""
|
|
59
|
+
branch = params.get("branch")
|
|
60
|
+
return _execute_git_diff(coder, branch)
|
aider/tools/git_log.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from aider.repo import ANY_GIT_ERROR
|
|
2
|
+
|
|
3
|
+
schema = {
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "GitLog",
|
|
7
|
+
"description": "Show the git log.",
|
|
8
|
+
"parameters": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"limit": {
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"description": "The maximum number of commits to show. Defaults to 10.",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
"required": [],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Normalized tool name for lookup
|
|
22
|
+
NORM_NAME = "gitlog"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _execute_git_log(coder, limit=10):
|
|
26
|
+
"""
|
|
27
|
+
Show the git log.
|
|
28
|
+
"""
|
|
29
|
+
if not coder.repo:
|
|
30
|
+
return "Not in a git repository."
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
commits = list(coder.repo.repo.iter_commits(max_count=limit))
|
|
34
|
+
log_output = []
|
|
35
|
+
for commit in commits:
|
|
36
|
+
short_hash = commit.hexsha[:8]
|
|
37
|
+
message = commit.message.strip().split("\n")[0]
|
|
38
|
+
log_output.append(f"{short_hash} {message}")
|
|
39
|
+
return "\n".join(log_output)
|
|
40
|
+
except ANY_GIT_ERROR as e:
|
|
41
|
+
coder.io.tool_error(f"Error running git log: {e}")
|
|
42
|
+
return f"Error running git log: {e}"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def process_response(coder, params):
|
|
46
|
+
"""
|
|
47
|
+
Process the GitLog tool response.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
coder: The Coder instance
|
|
51
|
+
params: Dictionary of parameters
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
str: Result message
|
|
55
|
+
"""
|
|
56
|
+
limit = params.get("limit", 10)
|
|
57
|
+
return _execute_git_log(coder, limit)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from aider.repo import ANY_GIT_ERROR
|
|
2
|
+
|
|
3
|
+
schema = {
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "GitRemote",
|
|
7
|
+
"description": "List remote repositories.",
|
|
8
|
+
"parameters": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {},
|
|
11
|
+
"required": [],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Normalized tool name for lookup
|
|
17
|
+
NORM_NAME = "gitremote"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _execute_git_remote(coder):
|
|
21
|
+
"""
|
|
22
|
+
List remote repositories.
|
|
23
|
+
"""
|
|
24
|
+
if not coder.repo:
|
|
25
|
+
return "Not in a git repository."
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
remotes = coder.repo.repo.remotes
|
|
29
|
+
if not remotes:
|
|
30
|
+
return "No remotes configured."
|
|
31
|
+
|
|
32
|
+
result = []
|
|
33
|
+
for remote in remotes:
|
|
34
|
+
result.append(f"{remote.name}\t{remote.url}")
|
|
35
|
+
return "\n".join(result)
|
|
36
|
+
except ANY_GIT_ERROR as e:
|
|
37
|
+
coder.io.tool_error(f"Error running git remote: {e}")
|
|
38
|
+
return f"Error running git remote: {e}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def process_response(coder, params):
|
|
42
|
+
"""
|
|
43
|
+
Process the GitRemote tool response.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
coder: The Coder instance
|
|
47
|
+
params: Dictionary of parameters (should be empty for GitRemote)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
str: Result message
|
|
51
|
+
"""
|
|
52
|
+
# GitRemote tool has no parameters to validate
|
|
53
|
+
return _execute_git_remote(coder)
|