# Aider chat conversation:
USER: make `expand_subdir` use pathlib
ASSISTANT: To modify the `expand_subdir` function to use `pathlib`, we need to modify the `aider/commands.py` file. Here are the changes:
```python
aider/commands.py
<<<<<<< ORIGINAL
def expand_subdir(file_path):
for root, dirs, files in os.walk(file_path):
for fname in files:
yield fname
=======
from pathlib import Path
def expand_subdir(file_path):
for file in Path(file_path).rglob('*'):
if file.is_file():
yield str(file)
>>>>>>> UPDATED
```
This change replaces the `os.walk` function with the `Path.rglob` method from `pathlib`, which recursively finds all files in the given directory. The `is_file` method is used to ensure we only yield files, not directories. The `str` function is used to convert the `Path` object to a string.
# Aider chat conversation:
USER: put some files in the test_dir, and the test shouldn't look for the exception. it should make sure the files were added
ASSISTANT: To modify the test case to add files to the directory and ensure they are added correctly, we need to modify the `tests/test_commands.py` file.
Here is the proposed change:
```python
tests/test_commands.py
<<<<<<< ORIGINAL
def test_cmd_add_directory(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Create a directory
os.mkdir("test_dir")
# Call the cmd_add method with a directory
with self.assertRaises(IsADirectoryError):
commands.cmd_add("test_dir")
=======
def test_cmd_add_directory(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Create a directory and add files to it
os.mkdir("test_dir")
with open("test_dir/test_file1.txt", "w") as f:
f.write("Test file 1")
with open("test_dir/test_file2.txt", "w") as f:
f.write("Test file 2")
# Call the cmd_add method with a directory
commands.cmd_add("test_dir")
# Check if the files have been added to the chat session
self.assertIn(str(Path("test_dir/test_file1.txt").resolve()), coder.abs_fnames)
self.assertIn(str(Path("test_dir/test_file2.txt").resolve()), coder.abs_fnames)
>>>>>>> UPDATED
```
This new test case `test_cmd_add_directory` creates a directory named `test_dir`, adds two files to it, and attempts to add the directory using the `cmd_add` method. We then check if the files in the directory have been added to the chat session.
# Aider chat conversation:
USER: add a test case to reproduce this issue: Trying to add just a directory makes the program throw the following and exit:
> /add src/components
Traceback (most recent call last):
File "/home/palmerd/.local/bin/aider", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/main.py", line 369, in main
coder.run()
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/coders/base_coder.py", line 382, in run
new_user_message = self.run_loop()
^^^^^^^^^^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/coders/base_coder.py", line 446, in run_loop
return self.commands.run(inp)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 60, in run
return self.do_run(matching_commands[0][1:], rest_inp)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 45, in do_run
return cmd_method(args)
^^^^^^^^^^^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/commands.py", line 264, in cmd_add
content = self.io.read_text(abs_file_path)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/palmerd/.local/lib/python3.11/site-packages/aider/io.py", line 142, in read_text
with open(str(filename), "r", encoding=self.encoding) as f:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IsADirectoryError: [Errno 21] Is a directory: '/home/palmerd/vue-frontend/src/components'
ASSISTANT: To reproduce this issue, we need to create a test case that tries to add a directory using the `/add` command. However, the code you've provided is not designed to handle test cases.
Could you please provide the test suite or the file where the test cases are written so that I can add a new test case?
USER: I added these *read-write* files: tests/test_commands.py
ASSISTANT: Great, we can add a test case in the `tests/test_commands.py` file. This test case will attempt to add a directory and check if the appropriate error is handled.
Here is the proposed change:
```python
tests/test_commands.py
<<<<<<< ORIGINAL
def test_cmd_add_no_match(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Call the cmd_add method with a non-existent file pattern
commands.cmd_add("*.nonexistent")
# Check if no files have been added to the chat session
self.assertEqual(len(coder.abs_fnames), 0)
=======
def test_cmd_add_no_match(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Call the cmd_add method with a non-existent file pattern
commands.cmd_add("*.nonexistent")
# Check if no files have been added to the chat session
self.assertEqual(len(coder.abs_fnames), 0)
def test_cmd_add_directory(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Create a directory
os.mkdir("test_dir")
# Call the cmd_add method with a directory
with self.assertRaises(IsADirectoryError):
commands.cmd_add("test_dir")
>>>>>>> UPDATED
```
This new test case `test_cmd_add_directory` creates a directory named `test_dir` and attempts to add it using the `cmd_add` method. We expect an `IsADirectoryError` to be raised in this scenario.
# Aider chat conversation:
USER: nice. use Path not os `expanduser`
ASSISTANT: To replace `os.path.expanduser` with `Path`, we need to modify the `main` function in the `aider/main.py` file. Here is the change:
```python
aider/main.py
<<<<<<< ORIGINAL
global_git_config = git.GitConfigParser([os.path.expanduser("~/.gitconfig")], read_only=True)
=======
global_git_config = git.GitConfigParser([str(Path.home() / ".gitconfig")], read_only=True)
>>>>>>> UPDATED
```
This change will make the code use `Path.home()` to get the home directory instead of `os.path.expanduser("~")`. The `Path` object is then converted to a string before being passed to `git.GitConfigParser`.
# Aider chat conversation:
USER: i have a global git name and email, but the git create code here isn't noticing and is setting the example name/email when it makes a repo
ASSISTANT: To fix this, we need to modify the `main` function in the `aider/main.py` file. Specifically, we need to change the way it checks for the global git name and email. Instead of checking the local git configuration, we should check the global git configuration.
Here is the change:
```python
aider/main.py
<<<<<<< ORIGINAL
with repo.config_writer() as git_config:
if not git_config.has_option("user", "name"):
git_config.set_value("user", "name", "Your Name")
io.tool_error('Update git name with: git config --global user.name "Your Name"')
if not git_config.has_option("user", "email"):
git_config.set_value("user", "email", "you@example.com")
io.tool_error(
'Update git email with: git config --global user.email "you@example.com"'
)
=======
global_git_config = git.GitConfigParser([os.path.expanduser("~/.gitconfig")], read_only=True)
with repo.config_writer() as git_config:
if not global_git_config.has_option("user", "name"):
git_config.set_value("user", "name", "Your Name")
io.tool_error('Update git name with: git config --global user.name "Your Name"')
if not global_git_config.has_option("user", "email"):
git_config.set_value("user", "email", "you@example.com")
io.tool_error(
'Update git email with: git config --global user.email "you@example.com"'
)
>>>>>>> UPDATED
```
This change will make the code check the global git configuration (`~/.gitconfig`) for the user name and email. If they are not found, it will set the local git configuration with the example name and email and display a message to the user to update their global git configuration.
# Aider chat conversation:
USER: I ran this command:
pytest tests/test_coder.py -k test_run_with_invalid_request_error
And got this output:
============================= test session starts ==============================
platform darwin -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0
rootdir: /Users/gauthier/Projects/aider
configfile: pytest.ini
collected 14 items / 13 deselected / 1 selected
tests/test_coder.py F [100%]
=================================== FAILURES ===================================
________________ TestCoder.test_run_with_invalid_request_error _________________
self = <tests.test_coder.TestCoder testMethod=test_run_with_invalid_request_error>
mock_chat_completion_create = <MagicMock name='create' id='4934396624'>
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
def test_run_with_invalid_request_error(self, mock_chat_completion_create):
# Mock the IO object
mock_io = MagicMock()
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
# Set up the mock to raise InvalidRequestError
> mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")
E TypeError: InvalidRequestError.__init__() missing 1 required positional argument: 'param'
tests/test_coder.py:355: TypeError
=========================== short test summary info ============================
FAILED tests/test_coder.py::TestCoder::test_run_with_invalid_request_error - ...
======================= 1 failed, 13 deselected in 1.04s =======================
ASSISTANT: The `openai.error.InvalidRequestError` requires two positional arguments: `message` and `param`. The `param` argument is used to specify the parameter that caused the invalid request.
Let's modify the test to include a `param` when raising the `InvalidRequestError`.
Here is the change:
```python
tests/test_coder.py
<<<<<<< ORIGINAL
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
def test_run_with_invalid_request_error(self, mock_chat_completion_create):
# Mock the IO object
mock_io = MagicMock()
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
# Set up the mock to raise InvalidRequestError
mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")
# Call the run method and assert that InvalidRequestError is raised
with self.assertRaises(openai.error.InvalidRequestError):
coder.run(with_message="hi")
=======
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
def test_run_with_invalid_request_error(self, mock_chat_completion_create):
# Mock the IO object
mock_io = MagicMock()
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
# Set up the mock to raise InvalidRequestError
mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request", "param")
# Call the run method and assert that InvalidRequestError is raised
with self.assertRaises(openai.error.InvalidRequestError):
coder.run(with_message="hi")
>>>>>>> UPDATED
```
This change should fix the `TypeError` you're seeing in your test run.
# Aider chat conversation:
USER: add a test that mocks openai.ChatCompletion.create to throw an openai.error.InvalidRequestError and make sure it bubbles all the way up and out of the Coder class. use coder.run as the entrypoint for the test
ASSISTANT: To add this test, we need to modify the `tests/test_coder.py` file. We will add a new test method `test_run_with_invalid_request_error` that mocks `openai.ChatCompletion.create` to throw an `openai.error.InvalidRequestError`. We will then call `coder.run` and assert that the `InvalidRequestError` is raised.
Here is the change:
```python
tests/test_coder.py
<<<<<<< ORIGINAL
if __name__ == "__main__":
unittest.main()
=======
@patch("aider.coders.base_coder.openai.ChatCompletion.create")
def test_run_with_invalid_request_error(self, mock_chat_completion_create):
# Mock the IO object
mock_io = MagicMock()
# Initialize the Coder object with the mocked IO and mocked repo
coder = Coder.create(models.GPT4, None, mock_io, openai_api_key="fake_key")
# Set up the mock to raise InvalidRequestError
mock_chat_completion_create.side_effect = openai.error.InvalidRequestError("Invalid request")
# Call the run method and assert that InvalidRequestError is raised
with self.assertRaises(openai.error.InvalidRequestError):
coder.run(with_message="hi")
if __name__ == "__main__":
unittest.main()
>>>>>>> UPDATED
```
This test will ensure that if `openai.ChatCompletion.create` throws an `InvalidRequestError`, it will propagate up and out of the `Coder` class.
# Context:
USER: you forgot --apply ?
ASSISTANT: You're right, I apologize for missing that. The `--apply` argument should be grouped under 'Other Settings'. Here's the updated code:
```python
aider/main.py
<<<<<<< ORIGINAL
other_group = parser.add_argument_group('Other Settings')
other_group.add_argument(
"--dry-run",
action="store_true",
help="Perform a dry run without applying changes (default: False)",
default=False,
)
other_group.add_argument(
"--show-diffs",
action="store_true",
help="Show diffs when committing changes (default: False)",
default=False,
)
other_group.add_argument(
"--map-tokens",
type=int,
default=1024,
help="Max number of tokens to use for repo map, use 0 to disable (default: 1024)",
)
other_group.add_argument(
"--yes",
action="store_true",
help="Always say yes to every confirmation",
default=None,
)
other_group.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose output",
default=False,
)
other_group.add_argument(
"--message",
"--msg",
"-m",
metavar="COMMAND",
help="Specify a single message to send GPT, process reply then exit (disables chat mode)",
)
=======
other_group = parser.add_argument_group('Other Settings')
other_group.add_argument(
"--apply",
metavar="FILE",
help="Apply the changes from the given file instead of running the chat (debug)",
)
other_group.add_argument(
"--dry-run",
action="store_true",
help="Perform a dry run without applying changes (default: False)",
default=False,
)
other_group.add_argument(
"--show-diffs",
action="store_true",
help="Show diffs when committing changes (default: False)",
default=False,
)
other_group.add_argument(
"--map-tokens",
type=int,
default=1024,
help="Max number of tokens to use for repo map, use 0 to disable (default: 1024)",
)
other_group.add_argument(
"--yes",
action="store_true",
help="Always say yes to every confirmation",
default=None,
)
other_group.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose output",
default=False,
)
other_group.add_argument(
"--message",
"--msg",
"-m",
metavar="COMMAND",
help="Specify a single message to send GPT, process reply then exit (disables chat mode)",
)
>>>>>>> UPDATED
```
This will add the `--apply` argument to the 'Other Settings' group in the help message.
# Context:
USER: does `configargparse` have a way to group the args into sections so they display grouped in --help?
ASSISTANT: Yes, `configargparse` supports argument grouping. This is done using the `add_argument_group` method of the `ArgumentParser` object. This method creates a new group of arguments and any arguments added to this group will be displayed together in the help message.
Here's an example of how you can group arguments:
```python
group = parser.add_argument_group('group name')
group.add_argument('--arg1')
group.add_argument('--arg2')
```
In the help message, `arg1` and `arg2` will be displayed under the section 'group name'.
USER: can you update the code to group them into a few sensible groups?
ASSISTANT: Sure, I can group the arguments in the `main` function of the `aider/main.py` file into several groups. Here's how I would do it:
1. General arguments: version, config, files
2. History files: input-history-file, chat-history-file
3. Model settings: model, edit-format
4. Output settings: pretty, no-pretty, no-stream, user-input-color, tool-output-color, tool-error-color, assistant-output-color, code-theme
5. Git settings: no-git, auto-commits, no-auto-commits, dirty-commits, no-dirty-commits
6. OpenAI settings: openai-api-key, openai-api-base
7. Other settings: dry-run, show-diffs, map-tokens, yes, verbose, message
Here's the updated code:
```python
aider/main.py
<<<<<<< ORIGINAL
parser = configargparse.ArgumentParser(
description="aider is GPT powered coding in your terminal",
add_config_file_help=True,
default_config_files=default_config_files,
config_file_parser_class=configargparse.YAMLConfigFileParser,
auto_env_var_prefix="AIDER_",
)
parser.add_argument(
"--version",
action="version",
version=f"%(prog)s {__version__}",
help="Show the version number and exit",
)
parser.add_argument(
"-c",
"--config",
is_config_file=True,
metavar="CONFIG_FILE",
help=(
"Specify the config file (default: search for .aider.conf.yml in git root, cwd"
" or home directory)"
),
)
parser.add_argument(
"files",
metavar="FILE",
nargs="*",
help="a list of source code files (optional)",
)
default_input_history_file = (
os.path.join(git_root, ".aider.input.history") if git_root else ".aider.input.history"
)
default_chat_history_file = (
os.path.join(git_root, ".aider.chat.history.md") if git_root else ".aider.chat.history.md"
)
parser.add_argument(
"--input-history-file",
metavar="INPUT_HISTORY_FILE",
default=default_input_history_file,
help=f"Specify the chat input history file (default: {default_input_history_file})",
)
parser.add_argument(
"--chat-history-file",
metavar="CHAT_HISTORY_FILE",
default=default_chat_history_file,
help=f"Specify the chat history file (default: {default_chat_history_file})",
)
parser.add_argument(
"--model",
metavar="MODEL",
default=models.GPT4.name,
help=f"Specify the model to use for the main chat (default: {models.GPT4.name})",
)
parser.add_argument(
"-3",
action="store_const",
dest="model",
const=models.GPT35_16k.name,
help=f"Use {models.GPT35_16k.name} model for the main chat (gpt-4 is better)",
)
parser.add_argument(
"--edit-format",
metavar="EDIT_FORMAT",
default=None,
help="Specify what edit format GPT should use (default depends on model)",
)
parser.add_argument(
"--pretty",
action="store_true",
default=True,
help="Enable pretty, colorized output (default: True)",
)
parser.add_argument(
"--no-pretty",
action="store_false",
dest="pretty",
help="Disable pretty, colorized output",
)
parser.add_argument(
"--no-stream",
action="store_false",
dest="stream",
default=True,
help="Disable streaming responses",
)
parser.add_argument(
"--no-git",
action="store_false",
dest="git",
default=True,
help="Do not look for a git repo",
)
parser.add_argument(
"--user-input-color",
default="green",
help="Set the color for user input (default: green)",
)
parser.add_argument(
"--tool-output-color",
default=None,
help="Set the color for tool output (default: None)",
)
parser.add_argument(
"--tool-error-color",
default="red",
help="Set the color for tool error messages (default: red)",
)
parser.add_argument(
"--assistant-output-color",
default="blue",
help="Set the color for assistant output (default: blue)",
)
parser.add_argument(
"--code-theme",
default="default",
help=(
"Set the markdown code theme (default: default, other options include monokai,"
" solarized-dark, solarized-light)"
),
)
parser.add_argument(
"--apply",
metavar="FILE",
help="Apply the changes from the given file instead of running the chat (debug)",
)
parser.add_argument(
"--auto-commits",
action="store_true",
dest="auto_commits",
default=True,
help="Enable auto commit of GPT changes (default: True)",
)
parser.add_argument(
"--no-auto-commits",
action="store_false",
dest="auto_commits",
help="Disable auto commit of GPT changes (implies --no-dirty-commits)",
)
parser.add_argument(
"--dirty-commits",
action="store_true",
dest="dirty_commits",
help="Enable commits when repo is found dirty",
default=True,
)
parser.add_argument(
"--no-dirty-commits",
action="store_false",
dest="dirty_commits",
help="Disable commits when repo is found dirty",
)
parser.add_argument(
"--encoding",
default="utf-8",
help="Specify the encoding to use when reading files (default: utf-8)",
)
parser.add_argument(
"--openai-api-key",
metavar="OPENAI_API_KEY",
help="Specify the OpenAI API key",
env_var="OPENAI_API_KEY",
)
parser.add_argument(
"--openai-api-base",
metavar="OPENAI_API_BASE",
default="https://api.openai.com/v1",
help="Specify the OpenAI API base endpoint (default: https://api.openai.com/v1)",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Perform a dry run without applying changes (default: False)",
default=False,
)
parser.add_argument(
"--show-diffs",
action="store_true",
help="Show diffs when committing changes (default: False)",
default=False,
)
parser.add_argument(
"--map-tokens",
type=int,
default=1024,
help="Max number of tokens to use for repo map, use 0 to disable (default: 1024)",
)
parser.add_argument(
"--yes",
action="store_true",
help="Always say yes to every confirmation",
default=None,
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose output",
default=False,
)
parser.add_argument(
"--message",
"--msg",
"-m",
metavar="COMMAND",
help="Specify a single message to send GPT, process reply then exit (disables chat mode)",
)
=======
parser = configargparse.ArgumentParser(
description="aider is GPT powered coding in your terminal",
add_config_file_help=True,
default_config_files=default_config_files,
config_file_parser_class=configargparse.YAMLConfigFileParser,
auto_env_var_prefix="AIDER_",
)
general_group = parser.add_argument_group('General')
general_group.add_argument(
"--version",
action="version",
version=f"%(prog)s {__version__}",
help="Show the version number and exit",
)
general_group.add_argument(
"-c",
"--config",
is_config_file=True,
metavar="CONFIG_FILE",
help=(
"Specify the config file (default: search for .aider.conf.yml in git root, cwd"
" or home directory)"
),
)
general_group.add_argument(
"files",
metavar="FILE",
nargs="*",
help="a list of source code files (optional)",
)
history_group = parser.add_argument_group('History Files')
default_input_history_file = (
os.path.join(git_root, ".aider.input.history") if git_root else ".aider.input.history"
)
default_chat_history_file = (
os.path.join(git_root, ".aider.chat.history.md") if git_root else ".aider.chat.history.md"
)
history_group.add_argument(
"--input-history-file",
metavar="INPUT_HISTORY_FILE",
default=default_input_history_file,
help=f"Specify the chat input history file (default: {default_input_history_file})",
)
history_group.add_argument(
"--chat-history-file",
metavar="CHAT_HISTORY_FILE",
default=default_chat_history_file,
help=f"Specify the chat history file (default: {default_chat_history_file})",
)
model_group = parser.add_argument_group('Model Settings')
model_group.add_argument(
"--model",
metavar="MODEL",
default=models.GPT4.name,
help=f"Specify the model to use for the main chat (default: {models.GPT4.name})",
)
model_group.add_argument(
"-3",
action="store_const",
dest="model",
const=models.GPT35_16k.name,
help=f"Use {models.GPT35_16k.name} model for the main chat (gpt-4 is better)",
)
model_group.add_argument(
"--edit-format",
metavar="EDIT_FORMAT",
default=None,
help="Specify what edit format GPT should use (default depends on model)",
)
output_group = parser.add_argument_group('Output Settings')
output_group.add_argument(
"--pretty",
action="store_true",
default=True,
help="Enable pretty, colorized output (default: True)",
)
output_group.add_argument(
"--no-pretty",
action="store_false",
dest="pretty",
help="Disable pretty, colorized output",
)
output_group.add_argument(
"--no-stream",
action="store_false",
dest="stream",
default=True,
help="Disable streaming responses",
)
output_group.add_argument(
"--user-input-color",
default="green",
help="Set the color for user input (default: green)",
)
output_group.add_argument(
"--tool-output-color",
default=None,
help="Set the color for tool output (default: None)",
)
output_group.add_argument(
"--tool-error-color",
default="red",
help="Set the color for tool error messages (default: red)",
)
output_group.add_argument(
"--assistant-output-color",
default="blue",
help="Set the color for assistant output (default: blue)",
)
output_group.add_argument(
"--code-theme",
default="default",
help=(
"Set the markdown code theme (default: default, other options include monokai,"
" solarized-dark, solarized-light)"
),
)
git_group = parser.add_argument_group('Git Settings')
git_group.add_argument(
"--no-git",
action="store_false",
dest="git",
default=True,
help="Do not look for a git repo",
)
git_group.add_argument(
"--auto-commits",
action="store_true",
dest="auto_commits",
default=True,
help="Enable auto commit of GPT changes (default: True)",
)
git_group.add_argument(
"--no-auto-commits",
action="store_false",
dest="auto_commits",
help="Disable auto commit of GPT changes (implies --no-dirty-commits)",
)
git_group.add_argument(
"--dirty-commits",
action="store_true",
dest="dirty_commits",
help="Enable commits when repo is found dirty",
default=True,
)
git_group.add_argument(
"--no-dirty-commits",
action="store_false",
dest="dirty_commits",
help="Disable commits when repo is found dirty",
)
openai_group = parser.add_argument_group('OpenAI Settings')
openai_group.add_argument(
"--openai-api-key",
metavar="OPENAI_API_KEY",
help="Specify the OpenAI API key",
env_var="OPENAI_API_KEY",
)
openai_group.add_argument(
"--openai-api-base",
metavar="OPENAI_API_BASE",
default="https://api.openai.com/v1",
help="Specify the OpenAI API base endpoint (default: https://api.openai.com/v1)",
)
other_group = parser.add_argument_group('Other Settings')
other_group.add_argument(
"--dry-run",
action="store_true",
help="Perform a dry run without applying changes (default: False)",
default=False,
)
other_group.add_argument(
"--show-diffs",
action="store_true",
help="Show diffs when committing changes (default: False)",
default=False,
)
other_group.add_argument(
"--map-tokens",
type=int,
default=1024,
help="Max number of tokens to use for repo map, use 0 to disable (default: 1024)",
)
other_group.add_argument(
"--yes",
action="store_true",
help="Always say yes to every confirmation",
default=None,
)
other_group.add_argument(
"-v",
"--verbose",
action="store_true",
help="Enable verbose output",
default=False,
)
other_group.add_argument(
"--message",
"--msg",
"-m",
metavar="COMMAND",
help="Specify a single message to send GPT, process reply then exit (disables chat mode)",
)
>>>>>>> UPDATED
```
This will make the help message more organized and easier to read.