aider-ce 0.88.3__py3-none-any.whl → 0.88.5__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.

Potentially problematic release.


This version of aider-ce might be problematic. Click here for more details.

aider/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from packaging import version
2
2
 
3
- __version__ = "0.88.3.dev"
3
+ __version__ = "0.88.5.dev"
4
4
  safe_version = __version__
5
5
 
6
6
  try:
aider/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.88.3'
32
- __version_tuple__ = version_tuple = (0, 88, 3)
31
+ __version__ = version = '0.88.5'
32
+ __version_tuple__ = version_tuple = (0, 88, 5)
33
33
 
34
34
  __commit_id__ = commit_id = None
aider/args.py CHANGED
@@ -315,7 +315,12 @@ def get_parser(default_config_files, git_root):
315
315
  " (default: current directory)"
316
316
  ),
317
317
  )
318
-
318
+ group.add_argument(
319
+ "--map-memory-cache",
320
+ action="store_true",
321
+ help="Store repo map in memory (default: False)",
322
+ default=False,
323
+ )
319
324
  ##########
320
325
  group = parser.add_argument_group("History Files")
321
326
  default_input_history_file = (
@@ -745,7 +750,14 @@ def get_parser(default_config_files, git_root):
745
750
  help="Print the system prompts and exit (debug)",
746
751
  default=False,
747
752
  )
748
-
753
+ group.add_argument(
754
+ "--linear-output",
755
+ action="store_true",
756
+ help=(
757
+ "Run input and output sequentially instead of us simultaneous streams (default: False)"
758
+ ),
759
+ default=False,
760
+ )
749
761
  ##########
750
762
  group = parser.add_argument_group("Voice settings")
751
763
  group.add_argument(
@@ -42,7 +42,7 @@ from rich.console import Console
42
42
 
43
43
  from aider import __version__, models, prompts, urls, utils
44
44
  from aider.analytics import Analytics
45
- from aider.commands import Commands
45
+ from aider.commands import Commands, SwitchCoder
46
46
  from aider.exceptions import LiteLLMExceptions
47
47
  from aider.history import ChatSummary
48
48
  from aider.io import ConfirmGroup, InputOutput
@@ -381,6 +381,7 @@ class Coder:
381
381
  map_cache_dir=".",
382
382
  repomap_in_memory=False,
383
383
  preserve_todo_list=False,
384
+ linear_output=False,
384
385
  ):
385
386
  # initialize from args.map_cache_dir
386
387
  self.map_cache_dir = map_cache_dir
@@ -469,6 +470,7 @@ class Coder:
469
470
 
470
471
  self.dry_run = dry_run
471
472
  self.pretty = self.io.pretty
473
+ self.linear_output = linear_output
472
474
 
473
475
  self.main_model = main_model
474
476
 
@@ -585,8 +587,6 @@ class Coder:
585
587
  self.summarizer_thread = None
586
588
  self.summarized_done_messages = []
587
589
  self.summarizing_messages = None
588
- self.input_task = None
589
- self.confirmation_in_progress = False
590
590
 
591
591
  self.files_edited_by_tools = set()
592
592
 
@@ -1057,18 +1057,71 @@ class Coder:
1057
1057
  self.commit_before_message.append(self.repo.get_head_commit_sha())
1058
1058
 
1059
1059
  async def run(self, with_message=None, preproc=True):
1060
- while self.confirmation_in_progress:
1060
+ while self.io.confirmation_in_progress:
1061
1061
  await asyncio.sleep(0.1) # Yield control and wait briefly
1062
1062
 
1063
+ if self.linear_output:
1064
+ return await self._run_linear(with_message, preproc)
1065
+
1063
1066
  if self.io.prompt_session:
1064
1067
  with patch_stdout(raw=True):
1065
1068
  return await self._run_patched(with_message, preproc)
1066
1069
  else:
1067
1070
  return await self._run_patched(with_message, preproc)
1068
1071
 
1072
+ async def _run_linear(self, with_message=None, preproc=True):
1073
+ try:
1074
+ if with_message:
1075
+ self.io.user_input(with_message)
1076
+ await self.run_one(with_message, preproc)
1077
+ return self.partial_response_content
1078
+
1079
+ user_message = None
1080
+ await self.io.cancel_input_task()
1081
+ await self.io.cancel_processing_task()
1082
+
1083
+ while True:
1084
+ try:
1085
+ if self.commands.cmd_running:
1086
+ await asyncio.sleep(0.1)
1087
+ continue
1088
+
1089
+ if not self.suppress_announcements_for_next_prompt:
1090
+ self.show_announcements()
1091
+ self.suppress_announcements_for_next_prompt = True
1092
+
1093
+ self.io.input_task = asyncio.create_task(self.get_input())
1094
+ await asyncio.sleep(0)
1095
+ await self.io.input_task
1096
+ user_message = self.io.input_task.result()
1097
+
1098
+ self.io.processing_task = asyncio.create_task(
1099
+ self._processing_logic(user_message, preproc)
1100
+ )
1101
+
1102
+ await self.io.processing_task
1103
+
1104
+ self.io.ring_bell()
1105
+ user_message = None
1106
+ except KeyboardInterrupt:
1107
+ if self.io.input_task:
1108
+ self.io.set_placeholder("")
1109
+ await self.io.cancel_input_task()
1110
+
1111
+ if self.io.processing_task:
1112
+ await self.io.cancel_processing_task()
1113
+ self.io.stop_spinner()
1114
+
1115
+ self.keyboard_interrupt()
1116
+ except (asyncio.CancelledError, IndexError):
1117
+ pass
1118
+ except EOFError:
1119
+ return
1120
+ finally:
1121
+ await self.io.cancel_input_task()
1122
+ await self.io.cancel_processing_task()
1123
+
1069
1124
  async def _run_patched(self, with_message=None, preproc=True):
1070
- input_task = None
1071
- processing_task = None
1072
1125
  try:
1073
1126
  if with_message:
1074
1127
  self.io.user_input(with_message)
@@ -1076,91 +1129,142 @@ class Coder:
1076
1129
  return self.partial_response_content
1077
1130
 
1078
1131
  user_message = None
1132
+ await self.io.cancel_input_task()
1133
+ await self.io.cancel_processing_task()
1079
1134
 
1080
1135
  while True:
1081
1136
  try:
1137
+ if self.commands.cmd_running:
1138
+ await asyncio.sleep(0.1)
1139
+ continue
1140
+
1082
1141
  if (
1083
- not self.confirmation_in_progress
1084
- and not input_task
1142
+ not self.io.confirmation_in_progress
1085
1143
  and not user_message
1086
- and (not processing_task or not self.io.placeholder)
1144
+ and (
1145
+ not self.io.input_task
1146
+ or self.io.input_task.done()
1147
+ or self.io.input_task.cancelled()
1148
+ )
1149
+ and (not self.io.processing_task or not self.io.placeholder)
1087
1150
  ):
1088
1151
  if not self.suppress_announcements_for_next_prompt:
1089
1152
  self.show_announcements()
1090
- self.suppress_announcements_for_next_prompt = False
1153
+ self.suppress_announcements_for_next_prompt = True
1091
1154
 
1092
1155
  # Stop spinner before showing announcements or getting input
1093
1156
  self.io.stop_spinner()
1094
-
1095
1157
  self.copy_context()
1096
- self.input_task = asyncio.create_task(self.get_input())
1097
- input_task = self.input_task
1158
+ self.io.input_task = asyncio.create_task(self.get_input())
1159
+
1160
+ # Yield Control so input can actually get properly set up
1161
+ await asyncio.sleep(0)
1098
1162
 
1099
1163
  tasks = set()
1100
- if processing_task:
1101
- tasks.add(processing_task)
1102
- if input_task:
1103
- tasks.add(input_task)
1164
+
1165
+ if self.io.processing_task:
1166
+ if self.io.processing_task.done():
1167
+ exception = self.io.processing_task.exception()
1168
+ if exception:
1169
+ if isinstance(exception, SwitchCoder):
1170
+ await self.io.processing_task
1171
+ elif (
1172
+ not self.io.processing_task.done()
1173
+ and not self.io.processing_task.cancelled()
1174
+ ):
1175
+ tasks.add(self.io.processing_task)
1176
+
1177
+ if (
1178
+ self.io.input_task
1179
+ and not self.io.input_task.done()
1180
+ and not self.io.input_task.cancelled()
1181
+ ):
1182
+ tasks.add(self.io.input_task)
1104
1183
 
1105
1184
  if tasks:
1106
1185
  done, pending = await asyncio.wait(
1107
1186
  tasks, return_when=asyncio.FIRST_COMPLETED
1108
1187
  )
1109
1188
 
1110
- if input_task and input_task in done:
1111
- if processing_task:
1112
- if not self.confirmation_in_progress:
1113
- processing_task.cancel()
1114
- try:
1115
- await processing_task
1116
- except asyncio.CancelledError:
1117
- pass
1189
+ if self.io.input_task and self.io.input_task in done:
1190
+ if self.io.processing_task:
1191
+ if not self.io.confirmation_in_progress:
1192
+ await self.io.cancel_processing_task()
1118
1193
  self.io.stop_spinner()
1119
- processing_task = None
1120
1194
 
1121
1195
  try:
1122
- user_message = input_task.result()
1196
+ user_message = self.io.input_task.result()
1197
+ await self.io.cancel_input_task()
1198
+
1199
+ if self.commands.is_run_command(user_message):
1200
+ self.commands.cmd_running = True
1201
+
1123
1202
  except (asyncio.CancelledError, KeyboardInterrupt):
1124
1203
  user_message = None
1125
- input_task = None
1126
- self.input_task = None
1127
- if user_message is None:
1204
+
1205
+ if not user_message:
1206
+ await self.io.cancel_input_task()
1128
1207
  continue
1129
1208
 
1130
- if processing_task and processing_task in done:
1209
+ if self.io.processing_task and self.io.processing_task in pending:
1131
1210
  try:
1132
- await processing_task
1211
+ tasks = set()
1212
+ tasks.add(self.io.processing_task)
1213
+
1214
+ # We just did a confirmation so add a new input task
1215
+ if (
1216
+ not self.io.input_task
1217
+ and self.io.get_confirmation_acknowledgement()
1218
+ ):
1219
+ self.io.input_task = asyncio.create_task(self.get_input())
1220
+ tasks.add(self.io.input_task)
1221
+
1222
+ done, pending = await asyncio.wait(
1223
+ tasks, return_when=asyncio.FIRST_COMPLETED
1224
+ )
1225
+
1226
+ if self.io.input_task and self.io.input_task in done:
1227
+ await self.io.cancel_processing_task()
1228
+ self.io.stop_spinner()
1229
+ self.io.acknowledge_confirmation()
1230
+
1231
+ try:
1232
+ user_message = self.io.input_task.result()
1233
+ await self.io.cancel_input_task()
1234
+ except (asyncio.CancelledError, KeyboardInterrupt):
1235
+ user_message = None
1236
+
1133
1237
  except (asyncio.CancelledError, KeyboardInterrupt):
1134
1238
  pass
1135
- processing_task = None
1239
+
1136
1240
  # Stop spinner when processing task completes
1137
1241
  self.io.stop_spinner()
1138
1242
 
1139
- if user_message and self.run_one_completed and self.compact_context_completed:
1140
- processing_task = asyncio.create_task(
1243
+ if user_message and not self.io.acknowledge_confirmation():
1244
+ self.io.processing_task = asyncio.create_task(
1141
1245
  self._processing_logic(user_message, preproc)
1142
1246
  )
1247
+
1143
1248
  # Start spinner for processing task
1144
1249
  self.io.start_spinner("Processing...")
1145
- user_message = None # Clear message after starting task
1250
+
1251
+ self.io.ring_bell()
1252
+ user_message = None
1146
1253
  except KeyboardInterrupt:
1147
- if processing_task:
1148
- processing_task.cancel()
1149
- processing_task = None
1150
- # Stop spinner when processing task is cancelled
1151
- self.io.stop_spinner()
1152
- if input_task:
1254
+ if self.io.input_task:
1153
1255
  self.io.set_placeholder("")
1154
- input_task.cancel()
1155
- input_task = None
1256
+ await self.io.cancel_input_task()
1257
+
1258
+ if self.io.processing_task:
1259
+ await self.io.cancel_processing_task()
1260
+ self.io.stop_spinner()
1261
+
1156
1262
  self.keyboard_interrupt()
1157
1263
  except EOFError:
1158
1264
  return
1159
1265
  finally:
1160
- if input_task:
1161
- input_task.cancel()
1162
- if processing_task:
1163
- processing_task.cancel()
1266
+ await self.io.cancel_input_task()
1267
+ await self.io.cancel_processing_task()
1164
1268
 
1165
1269
  async def _processing_logic(self, user_message, preproc):
1166
1270
  try:
@@ -1188,6 +1292,7 @@ class Coder:
1188
1292
  all_read_only_files = [self.get_rel_fname(fname) for fname in all_read_only_fnames]
1189
1293
  all_files = sorted(set(inchat_files + all_read_only_files))
1190
1294
  edit_format = "" if self.edit_format == self.main_model.edit_format else self.edit_format
1295
+
1191
1296
  return await self.io.get_input(
1192
1297
  self.root,
1193
1298
  all_files,
@@ -1203,6 +1308,12 @@ class Coder:
1203
1308
  return
1204
1309
 
1205
1310
  if self.commands.is_command(inp):
1311
+ if inp[0] in "!":
1312
+ inp = f"/run {inp[1:]}"
1313
+
1314
+ if self.commands.is_run_command(inp):
1315
+ self.commands.cmd_running = True
1316
+
1206
1317
  return await self.commands.run(inp)
1207
1318
 
1208
1319
  await self.check_for_file_mentions(inp)
@@ -2704,7 +2815,7 @@ class Coder:
2704
2815
 
2705
2816
  async for chunk in completion:
2706
2817
  # Check if confirmation is in progress and wait if needed
2707
- while self.confirmation_in_progress:
2818
+ while self.io.confirmation_in_progress:
2708
2819
  await asyncio.sleep(0.1) # Yield control and wait briefly
2709
2820
 
2710
2821
  if isinstance(chunk, str):
aider/commands.py CHANGED
@@ -84,6 +84,7 @@ class Commands:
84
84
 
85
85
  # Store the original read-only filenames provided via args.read
86
86
  self.original_read_only_fnames = set(original_read_only_fnames or [])
87
+ self.cmd_running = False
87
88
 
88
89
  def cmd_model(self, args):
89
90
  "Switch the Main Model to a new LLM"
@@ -256,6 +257,9 @@ class Commands:
256
257
  def is_command(self, inp):
257
258
  return inp[0] in "/!"
258
259
 
260
+ def is_run_command(self, inp):
261
+ return inp and (inp[0] in "!" or inp[:5] == "/test" or inp[:4] == "/run")
262
+
259
263
  def get_raw_completions(self, cmd):
260
264
  assert cmd.startswith("/")
261
265
  cmd = cmd[1:]
@@ -1151,51 +1155,61 @@ class Commands:
1151
1155
 
1152
1156
  async def cmd_run(self, args, add_on_nonzero_exit=False):
1153
1157
  "Run a shell command and optionally add the output to the chat (alias: !)"
1154
- exit_status, combined_output = await asyncio.to_thread(
1155
- run_cmd,
1156
- args,
1157
- verbose=self.verbose,
1158
- error_print=self.io.tool_error,
1159
- cwd=self.coder.root,
1160
- )
1158
+ try:
1159
+ self.cmd_running = True
1160
+ exit_status, combined_output = await asyncio.to_thread(
1161
+ run_cmd,
1162
+ args,
1163
+ verbose=self.verbose,
1164
+ error_print=self.io.tool_error,
1165
+ cwd=self.coder.root,
1166
+ )
1167
+ self.cmd_running = False
1161
1168
 
1162
- if combined_output is None:
1163
- return
1169
+ # This print statement, for whatever reason,
1170
+ # allows the thread to properly yield control of the terminal
1171
+ # to the main program
1172
+ print("")
1164
1173
 
1165
- # Calculate token count of output
1166
- token_count = self.coder.main_model.token_count(combined_output)
1167
- k_tokens = token_count / 1000
1174
+ if combined_output is None:
1175
+ return
1168
1176
 
1169
- if add_on_nonzero_exit:
1170
- add = exit_status != 0
1171
- else:
1172
- add = await self.io.confirm_ask(
1173
- f"Add {k_tokens:.1f}k tokens of command output to the chat?"
1174
- )
1177
+ # Calculate token count of output
1178
+ token_count = self.coder.main_model.token_count(combined_output)
1179
+ k_tokens = token_count / 1000
1175
1180
 
1176
- if add:
1177
- num_lines = len(combined_output.strip().splitlines())
1178
- line_plural = "line" if num_lines == 1 else "lines"
1179
- self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
1181
+ if add_on_nonzero_exit:
1182
+ add = exit_status != 0
1183
+ else:
1184
+ add = await self.io.confirm_ask(
1185
+ f"Add {k_tokens:.1f}k tokens of command output to the chat?"
1186
+ )
1180
1187
 
1181
- msg = prompts.run_output.format(
1182
- command=args,
1183
- output=combined_output,
1184
- )
1188
+ if add:
1189
+ num_lines = len(combined_output.strip().splitlines())
1190
+ line_plural = "line" if num_lines == 1 else "lines"
1191
+ self.io.tool_output(f"Added {num_lines} {line_plural} of output to the chat.")
1185
1192
 
1186
- self.coder.cur_messages += [
1187
- dict(role="user", content=msg),
1188
- dict(role="assistant", content="Ok."),
1189
- ]
1193
+ msg = prompts.run_output.format(
1194
+ command=args,
1195
+ output=combined_output,
1196
+ )
1197
+
1198
+ self.coder.cur_messages += [
1199
+ dict(role="user", content=msg),
1200
+ dict(role="assistant", content="Ok."),
1201
+ ]
1190
1202
 
1191
- if add_on_nonzero_exit and exit_status != 0:
1192
- # Return the formatted output message for test failures
1193
- return msg
1194
- elif add and exit_status != 0:
1195
- self.io.placeholder = "What's wrong? Fix"
1203
+ if add_on_nonzero_exit and exit_status != 0:
1204
+ # Return the formatted output message for test failures
1205
+ return msg
1206
+ elif add and exit_status != 0:
1207
+ self.io.placeholder = "What's wrong? Fix"
1196
1208
 
1197
- # Return None if output wasn't added or command succeeded
1198
- return None
1209
+ # Return None if output wasn't added or command succeeded
1210
+ return None
1211
+ finally:
1212
+ self.cmd_running = False
1199
1213
 
1200
1214
  def cmd_exit(self, args):
1201
1215
  "Exit the application"
aider/io.py CHANGED
@@ -320,6 +320,7 @@ class InputOutput:
320
320
  root=".",
321
321
  notifications=False,
322
322
  notifications_command=None,
323
+ verbose=False,
323
324
  ):
324
325
  self.console = Console()
325
326
  self.pretty = pretty
@@ -337,6 +338,8 @@ class InputOutput:
337
338
  self.multiline_mode = multiline_mode
338
339
  self.bell_on_next_input = False
339
340
  self.notifications = notifications
341
+ self.verbose = verbose
342
+
340
343
  if notifications and notifications_command is None:
341
344
  self.notifications_command = self.get_default_notification_command()
342
345
  else:
@@ -363,7 +366,7 @@ class InputOutput:
363
366
  )
364
367
 
365
368
  self.fzf_available = shutil.which("fzf")
366
- if not self.fzf_available:
369
+ if not self.fzf_available and self.verbose:
367
370
  self.tool_warning(
368
371
  "fzf not found, fuzzy finder features will be disabled. Install it for enhanced"
369
372
  " file/history search."
@@ -459,8 +462,17 @@ class InputOutput:
459
462
 
460
463
  self.file_watcher = file_watcher
461
464
  self.root = root
462
- self.outstanding_confirmations = []
465
+
466
+ # Variables used to interface with base_coder
463
467
  self.coder = None
468
+ self.input_task = None
469
+ self.processing_task = None
470
+ self.confirmation_in_progress = False
471
+ self.confirmation_acknowledgement = False
472
+
473
+ # State tracking for confirmation input
474
+ self.confirmation_input_active = False
475
+ self.saved_input_text = ""
464
476
 
465
477
  # Validate color settings after console is initialized
466
478
  self._validate_color_settings()
@@ -657,16 +669,8 @@ class InputOutput:
657
669
  print()
658
670
 
659
671
  def interrupt_input(self):
660
- coder = self.coder() if self.coder else None
661
- # interrupted_for_confirmation = False
662
-
663
- if (
664
- coder
665
- and hasattr(coder, "input_task")
666
- and coder.input_task
667
- and not coder.input_task.done()
668
- ):
669
- coder.input_task.cancel()
672
+ if self.input_task and not self.input_task.done():
673
+ self.input_task.cancel()
670
674
 
671
675
  if self.prompt_session and self.prompt_session.app:
672
676
  # Store any partial input before interrupting
@@ -680,10 +684,8 @@ class InputOutput:
680
684
 
681
685
  def reject_outstanding_confirmations(self):
682
686
  """Reject all outstanding confirmation dialogs."""
683
- for future in self.outstanding_confirmations:
684
- if not future.done():
685
- future.set_result(False)
686
- self.outstanding_confirmations = []
687
+ # This method is now a no-op since we removed the confirmation_future logic
688
+ pass
687
689
 
688
690
  async def get_input(
689
691
  self,
@@ -695,12 +697,8 @@ class InputOutput:
695
697
  abs_read_only_stubs_fnames=None,
696
698
  edit_format=None,
697
699
  ):
698
- self.reject_outstanding_confirmations()
699
700
  self.rule()
700
701
 
701
- # Ring the bell if needed
702
- self.ring_bell()
703
-
704
702
  rel_fnames = list(rel_fnames)
705
703
  show = ""
706
704
  if rel_fnames:
@@ -879,6 +877,11 @@ class InputOutput:
879
877
  self.tool_error(str(err))
880
878
  return ""
881
879
  except Exception as err:
880
+ try:
881
+ self.prompt_session.app.exit()
882
+ except Exception:
883
+ pass
884
+
882
885
  import traceback
883
886
 
884
887
  self.tool_error(str(err))
@@ -931,6 +934,26 @@ class InputOutput:
931
934
  self.user_input(inp)
932
935
  return inp
933
936
 
937
+ async def cancel_input_task(self):
938
+ if self.input_task:
939
+ input_task = self.input_task
940
+ self.input_task = None
941
+ try:
942
+ input_task.cancel()
943
+ await input_task
944
+ except (asyncio.CancelledError, IndexError):
945
+ pass
946
+
947
+ async def cancel_processing_task(self):
948
+ if self.processing_task:
949
+ processing_task = self.processing_task
950
+ self.processing_task = None
951
+ try:
952
+ processing_task.cancel()
953
+ await processing_task
954
+ except (asyncio.CancelledError, IndexError):
955
+ pass
956
+
934
957
  def add_to_input_history(self, inp):
935
958
  if not self.input_history_file:
936
959
  return
@@ -1001,32 +1024,33 @@ class InputOutput:
1001
1024
  return True
1002
1025
  return False
1003
1026
 
1027
+ def set_confirmation_acknowledgement(self):
1028
+ self.confirmation_acknowledgement = True
1029
+
1030
+ def get_confirmation_acknowledgement(self):
1031
+ return self.confirmation_acknowledgement
1032
+
1033
+ def acknowledge_confirmation(self):
1034
+ outstanding_confirmation = self.confirmation_acknowledgement
1035
+ self.confirmation_acknowledgement = False
1036
+ return outstanding_confirmation
1037
+
1004
1038
  @restore_multiline_async
1005
1039
  async def confirm_ask(
1006
1040
  self,
1007
1041
  *args,
1008
1042
  **kwargs,
1009
1043
  ):
1010
- coder = self.coder() if self.coder else None
1011
- interrupted_for_confirmation = False
1012
- if (
1013
- coder
1014
- and hasattr(coder, "input_task")
1015
- and coder.input_task
1016
- and not coder.input_task.done()
1017
- ):
1018
- coder.confirmation_in_progress = True
1019
- interrupted_for_confirmation = True
1020
- # self.interrupt_input()
1044
+ self.confirmation_in_progress = True
1021
1045
 
1022
1046
  try:
1047
+ self.set_confirmation_acknowledgement()
1023
1048
  return await asyncio.create_task(self._confirm_ask(*args, **kwargs))
1024
1049
  except KeyboardInterrupt:
1025
1050
  # Re-raise KeyboardInterrupt to allow it to propagate
1026
1051
  raise
1027
1052
  finally:
1028
- if interrupted_for_confirmation:
1029
- coder.confirmation_in_progress = False
1053
+ self.confirmation_in_progress = False
1030
1054
 
1031
1055
  async def _confirm_ask(
1032
1056
  self,
@@ -1039,19 +1063,11 @@ class InputOutput:
1039
1063
  ):
1040
1064
  self.num_user_asks += 1
1041
1065
 
1042
- # Ring the bell if needed
1043
- self.ring_bell()
1044
-
1045
1066
  question_id = (question, subject)
1046
1067
 
1047
- confirmation_future = asyncio.get_running_loop().create_future()
1048
- self.outstanding_confirmations.append(confirmation_future)
1049
-
1050
1068
  try:
1051
1069
  if question_id in self.never_prompts:
1052
- if not confirmation_future.done():
1053
- confirmation_future.set_result(False)
1054
- return await confirmation_future
1070
+ return False
1055
1071
 
1056
1072
  if group and not group.show_group:
1057
1073
  group = None
@@ -1086,47 +1102,45 @@ class InputOutput:
1086
1102
  else:
1087
1103
  self.tool_output(subject, bold=True)
1088
1104
 
1089
- style = self._get_style()
1090
-
1091
1105
  if self.yes is True:
1092
1106
  res = "n" if explicit_yes_required else "y"
1107
+ self.acknowledge_confirmation()
1093
1108
  elif self.yes is False:
1094
1109
  res = "n"
1110
+ self.acknowledge_confirmation()
1095
1111
  elif group and group.preference:
1096
1112
  res = group.preference
1097
1113
  self.user_input(f"{question}{res}", log_only=False)
1114
+ self.acknowledge_confirmation()
1098
1115
  else:
1116
+ # Ring the bell if needed
1117
+ self.ring_bell()
1118
+
1099
1119
  while True:
1100
1120
  try:
1101
1121
  if self.prompt_session:
1102
- coder = self.coder() if self.coder else None
1103
1122
  if (
1104
- coder
1105
- and hasattr(coder, "input_task")
1106
- and coder.input_task
1107
- and not coder.input_task.done()
1123
+ not self.input_task
1124
+ or self.input_task.done()
1125
+ or self.input_task.cancelled()
1126
+ ):
1127
+ coder = self.coder() if self.coder else None
1128
+
1129
+ if coder:
1130
+ self.input_task = asyncio.create_task(coder.get_input())
1131
+ await asyncio.sleep(0)
1132
+
1133
+ if (
1134
+ self.input_task
1135
+ and not self.input_task.done()
1136
+ and not self.input_task.cancelled()
1108
1137
  ):
1109
1138
  self.prompt_session.message = question
1110
1139
  self.prompt_session.app.invalidate()
1111
- res = await coder.input_task
1112
1140
  else:
1113
- prompt_task = asyncio.create_task(
1114
- self.prompt_session.prompt_async(
1115
- question,
1116
- style=style,
1117
- complete_while_typing=False,
1118
- )
1119
- )
1120
- done, pending = await asyncio.wait(
1121
- {prompt_task, confirmation_future},
1122
- return_when=asyncio.FIRST_COMPLETED,
1123
- )
1124
-
1125
- if confirmation_future in done:
1126
- prompt_task.cancel()
1127
- return await confirmation_future
1128
-
1129
- res = await prompt_task
1141
+ continue
1142
+
1143
+ res = await self.input_task
1130
1144
  else:
1131
1145
  res = await asyncio.get_event_loop().run_in_executor(
1132
1146
  None, input, question
@@ -1136,9 +1150,7 @@ class InputOutput:
1136
1150
  res = default
1137
1151
  break
1138
1152
  except asyncio.CancelledError:
1139
- if not confirmation_future.done():
1140
- confirmation_future.set_result(False)
1141
- raise
1153
+ return False
1142
1154
 
1143
1155
  if not res:
1144
1156
  res = default
@@ -1157,9 +1169,7 @@ class InputOutput:
1157
1169
  self.never_prompts.add(question_id)
1158
1170
  hist = f"{question.strip()} {res}"
1159
1171
  self.append_chat_history(hist, linebreak=True, blockquote=True)
1160
- if not confirmation_future.done():
1161
- confirmation_future.set_result(False)
1162
- return await confirmation_future
1172
+ return False
1163
1173
 
1164
1174
  if explicit_yes_required:
1165
1175
  is_yes = res == "y"
@@ -1177,19 +1187,11 @@ class InputOutput:
1177
1187
 
1178
1188
  hist = f"{question.strip()} {res}"
1179
1189
  self.append_chat_history(hist, linebreak=True, blockquote=True)
1180
-
1181
- if not confirmation_future.done():
1182
- confirmation_future.set_result(is_yes)
1183
-
1184
1190
  except asyncio.CancelledError:
1185
- if not confirmation_future.done():
1186
- confirmation_future.set_result(False)
1187
- raise
1191
+ return False
1188
1192
  finally:
1189
- if confirmation_future in self.outstanding_confirmations:
1190
- self.outstanding_confirmations.remove(confirmation_future)
1191
-
1192
- return await confirmation_future
1193
+ pass
1194
+ return is_yes
1193
1195
 
1194
1196
  @restore_multiline
1195
1197
  def prompt_ask(self, question, default="", subject=None):
@@ -1241,17 +1243,22 @@ class InputOutput:
1241
1243
 
1242
1244
  if not isinstance(message, Text):
1243
1245
  message = Text(message)
1244
- color = ensure_hash_prefix(color) if color else None
1245
- style = dict(style=color) if self.pretty and color else dict()
1246
+
1247
+ style = dict()
1248
+
1249
+ if self.pretty:
1250
+ color = ensure_hash_prefix(color) if color else None
1251
+ if color:
1252
+ style["color"] = color
1246
1253
 
1247
1254
  try:
1248
- self.stream_print(message, **style)
1255
+ self.stream_print(message, style=RichStyle(**style))
1249
1256
  except UnicodeEncodeError:
1250
1257
  # Fallback to ASCII-safe output
1251
1258
  if isinstance(message, Text):
1252
1259
  message = message.plain
1253
1260
  message = str(message).encode("ascii", errors="replace").decode("ascii")
1254
- self.stream_print(message, **style)
1261
+ self.stream_print(message, style=RichStyle(**style))
1255
1262
 
1256
1263
  if self.prompt_session and self.prompt_session.app:
1257
1264
  self.prompt_session.app.invalidate()
aider/main.py CHANGED
@@ -601,6 +601,7 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
601
601
  multiline_mode=args.multiline,
602
602
  notifications=args.notifications,
603
603
  notifications_command=args.notifications_command,
604
+ verbose=args.verbose,
604
605
  )
605
606
 
606
607
  io = get_io(args.pretty)
@@ -1056,6 +1057,9 @@ async def main_async(argv=None, input=None, output=None, force_git_root=None, re
1056
1057
  context_compaction_max_tokens=args.context_compaction_max_tokens,
1057
1058
  context_compaction_summary_tokens=args.context_compaction_summary_tokens,
1058
1059
  map_cache_dir=args.map_cache_dir,
1060
+ repomap_in_memory=args.map_memory_cache,
1061
+ preserve_todo_list=args.preserve_todo_list,
1062
+ linear_output=args.linear_output,
1059
1063
  )
1060
1064
  except UnknownEditFormat as err:
1061
1065
  io.tool_error(str(err))
@@ -0,0 +1,3 @@
1
+ (function (variable) @name.definition.function)
2
+ (bind (variable) @name.definition.function)
3
+ (signature (variable) @name.definition.type)
@@ -0,0 +1,3 @@
1
+ (FnProto) @name.definition.function
2
+ (VarDecl "const" @name.definition.constant)
3
+ (VarDecl "var" @name.definition.variable)
aider/urls.py CHANGED
@@ -8,7 +8,7 @@ model_warnings = "https://aider.chat/docs/llms/warnings.html"
8
8
  token_limits = "https://aider.chat/docs/troubleshooting/token-limits.html"
9
9
  llms = "https://aider.chat/docs/llms.html"
10
10
  large_repos = "https://aider.chat/docs/faq.html#can-i-use-aider-in-a-large-mono-repo"
11
- github_issues = "https://github.com/Aider-AI/aider/issues/new"
11
+ github_issues = "https://github.com/dwash96/aider-ce/issues/new"
12
12
  git_index_version = "https://github.com/Aider-AI/aider/issues/211"
13
13
  install_properly = "https://aider.chat/docs/troubleshooting/imports.html"
14
14
  analytics = "https://aider.chat/docs/more/analytics.html"
aider/versioncheck.py CHANGED
@@ -21,7 +21,7 @@ def install_from_main_branch(io):
21
21
  io,
22
22
  None,
23
23
  "Install the development version of aider from the main branch?",
24
- ["git+https://github.com/Aider-AI/aider.git"],
24
+ ["git+https://github.com/dwash96/aider-ce.git"],
25
25
  self_update=True,
26
26
  )
27
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aider-ce
3
- Version: 0.88.3
3
+ Version: 0.88.5
4
4
  Summary: Aider is AI pair programming in your terminal
5
5
  Project-URL: Homepage, https://github.com/dwash96/aider-ce
6
6
  Classifier: Development Status :: 4 - Beta
@@ -1,11 +1,11 @@
1
- aider/__init__.py,sha256=wrKtj8dqyfjwH3Rlw7e1W9GVgUnjsG9nsUMYHBwb3Vo,496
1
+ aider/__init__.py,sha256=1DZ03r447CFeqM5FT2f7BbovXi_RlzOLcnP79PsACpU,496
2
2
  aider/__main__.py,sha256=Vdhw8YA1K3wPMlbJQYL5WqvRzAKVeZ16mZQFO9VRmCo,62
3
- aider/_version.py,sha256=enEulHZ1Bg_kUgfLWzNgkcmguOKMpRSnje8Z-0F49F4,706
3
+ aider/_version.py,sha256=zZmH68H1r9949DHpJ12DEFhFY-78SXQLc-K3CKqklcc,706
4
4
  aider/analytics.py,sha256=c5ujaCcMc3yG-9rz_0oSsqBwmVQRxJnui6iE_yDyY_M,7507
5
- aider/args.py,sha256=lC64t3gp-SJ1Sv51LDHpTAsiU2ZwiFWerYf3iu9mtWY,32742
5
+ aider/args.py,sha256=r9xdhB44K4LF2ru-cbOdaoHYzvG6CyViwcw9QRewEKw,33145
6
6
  aider/args_formatter.py,sha256=CBRnzHyZk-fFCK0ekAzb6C4PPJOU-VTpWIIsJe3qUhk,6369
7
7
  aider/change_tracker.py,sha256=djUlUuewhwRAlC0x6jIUZNpn6_PK1YyiNTMYvlvDeTE,4884
8
- aider/commands.py,sha256=TFQPjSy7y_BgU2WUB5cTQM2eCHFbd2UO86KGyNhLUVI,80529
8
+ aider/commands.py,sha256=dbS-pqao-TSg35P9BDPiY5fRhLGwY5ZJyyIE-dAqlQw,81156
9
9
  aider/copypaste.py,sha256=J99QrXILUED_GPdEqxt7WjGZ5if8sfy0VQTzsV2jBrE,2095
10
10
  aider/deprecated.py,sha256=SNeAWR7ih87F5AyFpC4pxRoJAaw8measBW583w0EUT8,4277
11
11
  aider/diffs.py,sha256=y6_rxIKe3FPCIsVy_RRkHdofguYOhYBr2Oytr5AqjHI,3028
@@ -17,10 +17,10 @@ aider/gui.py,sha256=JnHvli1JTCGHAgsOZ8HkAWOKAFxmngbyviZIJeYvjsw,17573
17
17
  aider/help.py,sha256=wExA1E9vuJccKBH1VvKmH-zJqFi-vhNc0n3CD3Y-8fI,4432
18
18
  aider/help_pats.py,sha256=syn7pSVJdcf8uMKTxnZUZBQu-r8JMAi-rrC-k2er1Fk,376
19
19
  aider/history.py,sha256=083Gm7KxNo1PXMFHYiChigxCbRzmLkfNlesODdCC-eY,6067
20
- aider/io.py,sha256=flltMLvPUnG7sDpfQC_XWICjXxhIy2EJGtdygSr0cvA,56836
20
+ aider/io.py,sha256=6CKaWP5zWngaMjzS2lpy_pT84a_mGWgDcyFsazHKlTU,56543
21
21
  aider/linter.py,sha256=t5jwWZ1dvIzRtig1kTSjzl6u1LRfw0e19qwNIen2jAg,7998
22
22
  aider/llm.py,sha256=dtT0mavXP1SyR0Zu_ysZXKdbs3y53q2PevvDKBUrs6s,1505
23
- aider/main.py,sha256=2Pk5nJhUf-aoa2cbs6VPQA0lfneRYgw-dCbkFO8r8WY,46331
23
+ aider/main.py,sha256=3IE18moiAP2nXs-NY_PJKk8PXS_pdzMvbefoNfT9CnQ,46520
24
24
  aider/mdstream.py,sha256=fS9iQUQmIJPEMo7o1psPGE2yYj31MI3m3msdN-jEzUw,7594
25
25
  aider/models.py,sha256=yflYZ64oza4QH04vIPI2n7rcsdSw2Np4BRwRKlb3STQ,45455
26
26
  aider/onboarding.py,sha256=pMWl--NOH_hb4w1wVxLmv8W0akcrilo1Pxf9XUSqBXs,16135
@@ -34,9 +34,9 @@ aider/run_cmd.py,sha256=9-NpSL4hlqIndf_EN1jnmWfjX7vIPbDgKgGPGRAr2Rw,4223
34
34
  aider/scrape.py,sha256=1d5RTtHLJ8JersGoQWm0mDVk_rQfsY4Xm-0jTK8xEPw,8346
35
35
  aider/sendchat.py,sha256=fY9scUSGdcLUDrD3PWUEyp6njRZZ138l79oXz_bks8o,7700
36
36
  aider/special.py,sha256=OhsBWWM-DWwjWbi6kE7EqR4CiUfyJ6qJuCgcmywZSAc,4415
37
- aider/urls.py,sha256=W0OL4pahSIZAaSUHPvn9KPN1aIkXE5nAKcizMKy4EKg,1122
37
+ aider/urls.py,sha256=LoSe3P1wGC5hEohJ5lRuIXT2R0YzLNbJrC67c8KoQZ4,1124
38
38
  aider/utils.py,sha256=wkT43yJx59Q0OfIlzNX2n9rPyEEo7WLKXdXoxNJzdz4,12231
39
- aider/versioncheck.py,sha256=R9R1gUJYgOtmUycpJ4YqxCkCOylQBSiZ_p_BAnHJ8H4,2977
39
+ aider/versioncheck.py,sha256=e2rD1Kdz_mcuzcgyrRsveYd-BxfgS4pzkFbIE2gz6xs,2979
40
40
  aider/voice.py,sha256=hNQCMCWhljcROJhzsvnkwgzzgQQbFORkpROhKeqICig,6797
41
41
  aider/waiting.py,sha256=QbDnh1U6oJPqkUrRM3DC8iA5-djbKRW5iJh6Q3VOnrI,944
42
42
  aider/watch.py,sha256=znCZhHCBlcMm-4SRJP-B0mWfsl5q26DAd-zlk2zykQ8,10641
@@ -46,7 +46,7 @@ aider/coders/architect_coder.py,sha256=O5KIf__Ka0bgtCUhYWUmAb08aCS6Nq-CdVWWa-VNK
46
46
  aider/coders/architect_prompts.py,sha256=R0_KxZjo-km_yNaeDAquDP9qfp3IdWgrdMirCWe0RIE,1658
47
47
  aider/coders/ask_coder.py,sha256=Omk4Ih8-prefkMZ_jnRS3faoW5CQUakHOvZ-s7piM3U,210
48
48
  aider/coders/ask_prompts.py,sha256=W6HwDUfzfOLt9q8sl6rw7fN7b5ND90FkxCZrtrWl5vY,1171
49
- aider/coders/base_coder.py,sha256=I2IwjL2mzcBJhnaMHhAZn0tQZ6DPi8sw-EsjRofJk9c,128223
49
+ aider/coders/base_coder.py,sha256=5R6AGbofXg1PeW-TF3pD0o5vWl1-Tn9lND2GhQlRRvI,132707
50
50
  aider/coders/base_prompts.py,sha256=O3bBjhf0hgvtKbQ9QyOMnRy8LrmfLyT9dVAcXxHS_3k,3659
51
51
  aider/coders/chat_chunks.py,sha256=8HPet6cmQdgWvaA_tGpinO4ASMst53uTcSEtNVTYDXE,1981
52
52
  aider/coders/context_coder.py,sha256=_RSzu6ptHo2lkTN7-e9TpcZKzqbQF2eNX5MkyswGm3s,1577
@@ -125,6 +125,7 @@ aider/queries/tree-sitter-languages/elixir-tags.scm,sha256=eO20nPIwI7_vq4Fob6U5R
125
125
  aider/queries/tree-sitter-languages/elm-tags.scm,sha256=4qTEWJCAd7_BOfwyky0q_NYzAMtGdiq7qwo1GIhXmag,951
126
126
  aider/queries/tree-sitter-languages/fortran-tags.scm,sha256=BD6M5CVhMpINlLR7U9bL6STRwGLYBrMmvmldOHe1-9U,419
127
127
  aider/queries/tree-sitter-languages/go-tags.scm,sha256=mHtS5NEuxWJGfVz1rq4YlJRMYVDAl5tf7iYnm6RikVE,848
128
+ aider/queries/tree-sitter-languages/haskell-tags.scm,sha256=mopkZ2Py3_Vl3xvpmaryzUVwYWAzl6GaYgmMb9qKD3Q,143
128
129
  aider/queries/tree-sitter-languages/hcl-tags.scm,sha256=yOVCBeF4C3ZrFG-gg0adWg2QkxylPcI2dbVeEgD7EPE,2137
129
130
  aider/queries/tree-sitter-languages/java-tags.scm,sha256=7WKb-djGv0Ief6XEWQPYpfLpgJHtMPPukIUi55PegvE,627
130
131
  aider/queries/tree-sitter-languages/javascript-tags.scm,sha256=svVct6pxbcYP_-xEBwzGy6t1SlN7ajkEUCivUkBZn_Q,2251
@@ -140,6 +141,7 @@ aider/queries/tree-sitter-languages/ruby-tags.scm,sha256=vIidsCeE2A0vdFN18yXKqUW
140
141
  aider/queries/tree-sitter-languages/rust-tags.scm,sha256=9ljM1nzhfPs_ZTRw7cr2P9ToOyhGcKkCoN4_HPXSWi4,1451
141
142
  aider/queries/tree-sitter-languages/scala-tags.scm,sha256=UxQjz80JIrrJ7Pm56uUnQyThfmQNvwk7aQzPNypB-Ao,1761
142
143
  aider/queries/tree-sitter-languages/typescript-tags.scm,sha256=OMdCeedPiA24ky82DpgTMKXK_l2ySTuF2zrQ2fJAi9E,1253
144
+ aider/queries/tree-sitter-languages/zig-tags.scm,sha256=BPgov_nD_LqpL37sbdwsMYbFmHwjBOuRm76geKo29ds,124
143
145
  aider/resources/__init__.py,sha256=09npmZFptj6XR6ZeEuekpcK2stecKEjI59zR0Vz2JU8,142
144
146
  aider/resources/model-metadata.json,sha256=fFBW3iBFAZlhEPXyM-5_8qYEEOCx6tFqMu2Yh-5oBLI,28667
145
147
  aider/resources/model-settings.yml,sha256=bqpgKJRNZUcSlXyuZgTKFybf61kW5NRuoIVyOMZztwc,58325
@@ -261,9 +263,9 @@ aider/website/docs/usage/tutorials.md,sha256=ZKBztbUtucHOiv9h8gvWiWTP6MTSsFyz4mA
261
263
  aider/website/docs/usage/voice.md,sha256=BtX7pHRgHRWUmrNbS4JssC-SO8RrJ_OetBCtIYpO0pU,3452
262
264
  aider/website/docs/usage/watch.md,sha256=OVF14lGtv1vhSXRE8PpxQ3YW-uXSifarUbmLBjmLRyA,7940
263
265
  aider/website/share/index.md,sha256=P51aDw9AT8AVbsU7v6g1tWuMjly7y_plM_ZI1ScaT8Y,3172
264
- aider_ce-0.88.3.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
265
- aider_ce-0.88.3.dist-info/METADATA,sha256=3XMMyoRjhPiiC-TNNFw4oVg3yUtLttJRCfvX03w5zBE,20820
266
- aider_ce-0.88.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
267
- aider_ce-0.88.3.dist-info/entry_points.txt,sha256=qUBEUd84DYNEHFSgZbgsjgsrAABxqwOj-Dwut9pHZx0,45
268
- aider_ce-0.88.3.dist-info/top_level.txt,sha256=uwOA6ycgSiRLrBsaRBcIeN_eBKAX78U01_KDEHR8mBk,6
269
- aider_ce-0.88.3.dist-info/RECORD,,
266
+ aider_ce-0.88.5.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
267
+ aider_ce-0.88.5.dist-info/METADATA,sha256=uCUDJn4PseoYw1J-KczE4HLbg3JfANIPcjiKYkH48Zg,20820
268
+ aider_ce-0.88.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
269
+ aider_ce-0.88.5.dist-info/entry_points.txt,sha256=qUBEUd84DYNEHFSgZbgsjgsrAABxqwOj-Dwut9pHZx0,45
270
+ aider_ce-0.88.5.dist-info/top_level.txt,sha256=uwOA6ycgSiRLrBsaRBcIeN_eBKAX78U01_KDEHR8mBk,6
271
+ aider_ce-0.88.5.dist-info/RECORD,,