aider-ce 0.88.3__py3-none-any.whl → 0.88.6.dev7__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/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
@@ -968,7 +991,7 @@ class InputOutput:
968
991
  else:
969
992
  style = dict()
970
993
 
971
- self.console.print(Text(inp), **style)
994
+ self.stream_print(Text(inp), **style)
972
995
 
973
996
  def user_input(self, inp, log_only=True):
974
997
  if not log_only:
@@ -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,20 +1243,25 @@ 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
+ if self.pretty:
1249
+ if color:
1250
+ style["color"] = ensure_hash_prefix(color)
1251
+
1252
+ style = RichStyle(**style)
1246
1253
 
1247
1254
  try:
1248
- self.stream_print(message, **style)
1255
+ self.stream_print(message, style=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=style)
1255
1262
 
1256
- if self.prompt_session and self.prompt_session.app:
1257
- self.prompt_session.app.invalidate()
1263
+ def tool_success(self, message="", strip=True):
1264
+ self._tool_message(message, strip, self.user_input_color)
1258
1265
 
1259
1266
  def tool_error(self, message="", strip=True):
1260
1267
  self.num_error_outputs += 1
@@ -1302,7 +1309,7 @@ class InputOutput:
1302
1309
  else:
1303
1310
  show_resp = Text(message or "(empty response)")
1304
1311
 
1305
- self.console.print(show_resp)
1312
+ self.stream_print(show_resp)
1306
1313
 
1307
1314
  def render_markdown(self, text):
1308
1315
  output = StringIO()
@@ -1345,12 +1352,18 @@ class InputOutput:
1345
1352
 
1346
1353
  if not final:
1347
1354
  if len(lines) > 1:
1348
- self.console.print(output)
1355
+ self.console.print(
1356
+ Text.from_ansi(output) if self.has_ansi_codes(output) else output
1357
+ )
1349
1358
  else:
1350
1359
  # Ensure any remaining buffered content is printed using the full response
1351
- self.console.print(output)
1360
+ self.console.print(Text.from_ansi(output) if self.has_ansi_codes(output) else output)
1352
1361
  self.reset_streaming_response()
1353
1362
 
1363
+ def has_ansi_codes(self, s: str) -> bool:
1364
+ """Check if a string contains the ANSI escape character."""
1365
+ return "\x1b" in s
1366
+
1354
1367
  def reset_streaming_response(self):
1355
1368
  self._stream_buffer = ""
1356
1369
  self._stream_line_count = 0
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/repo.py CHANGED
@@ -310,7 +310,7 @@ class GitRepo:
310
310
  # Perform the commit
311
311
  self.repo.git.commit(cmd)
312
312
  commit_hash = self.get_head_commit_sha(short=True)
313
- self.io.tool_output(f"Commit {commit_hash} {commit_message}", bold=True)
313
+ self.io.tool_success(f"Commit {commit_hash} {commit_message}")
314
314
  return commit_hash, commit_message
315
315
 
316
316
  except ANY_GIT_ERROR as err:
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
 
@@ -0,0 +1,182 @@
1
+ # Session Management
2
+
3
+ Aider provides session management commands that allow you to save, load, and manage your chat sessions. This is particularly useful for:
4
+
5
+ - Continuing work on complex projects across multiple sessions
6
+ - Recreating specific development environments
7
+ - Archiving important conversations and file configurations
8
+
9
+ ## Session Commands
10
+
11
+ ### `/save-session <name>`
12
+ Save the current chat session to a named file in `.aider/sessions/`.
13
+
14
+ **Usage:**
15
+ ```
16
+ /save-session my-project-session
17
+ ```
18
+
19
+ **What gets saved:**
20
+ - Chat history (both done and current messages)
21
+ - All files in the chat (editable, read-only, and read-only stubs)
22
+ - Current model and edit format settings
23
+ - Auto-commit, auto-lint, and auto-test settings
24
+ - Session metadata (timestamp, version)
25
+
26
+ ### `/load-session <name>`
27
+ Load a previously saved session by name or file path.
28
+
29
+ **Usage:**
30
+ ```
31
+ /load-session my-project-session
32
+ ```
33
+
34
+ **What gets loaded:**
35
+ - Restores chat history and file configurations
36
+ - Recreates the exact session state
37
+ - Preserves all settings and model configurations
38
+
39
+ ### `/list-sessions`
40
+ List all available saved sessions in `.aider/sessions/`.
41
+
42
+ **Usage:**
43
+ ```
44
+ /list-sessions
45
+ ```
46
+
47
+ **Shows:**
48
+ - Session names
49
+ - Model used
50
+ - Edit format
51
+ - Creation timestamp
52
+
53
+ ## How Sessions Work
54
+
55
+ ### Session Storage
56
+ Sessions are stored as JSON files in the `.aider/sessions/` directory within your project. Each session file contains:
57
+
58
+ ```json
59
+ {
60
+ "version": "1.0",
61
+ "timestamp": 1700000000,
62
+ "session_name": "my-session",
63
+ "model": "gpt-4",
64
+ "edit_format": "diff",
65
+ "chat_history": {
66
+ "done_messages": [...],
67
+ "cur_messages": [...]
68
+ },
69
+ "files": {
70
+ "editable": ["file1.py", "file2.js"],
71
+ "read_only": ["docs/README.md"],
72
+ "read_only_stubs": []
73
+ },
74
+ "settings": {
75
+ "root": "/path/to/project",
76
+ "auto_commits": true,
77
+ "auto_lint": false,
78
+ "auto_test": false
79
+ }
80
+ }
81
+ ```
82
+
83
+ ### Session File Location
84
+ - **Relative paths**: Files within your project are stored with relative paths
85
+ - **Absolute paths**: External files are stored with absolute paths
86
+
87
+ ## Use Cases
88
+
89
+ ### Project Continuation
90
+ ```
91
+ # Start working on a project
92
+ /add src/main.py src/utils.py
93
+ # ... have a conversation ...
94
+ /save-session my-project
95
+
96
+ # Later, continue where you left off
97
+ /load-session my-project
98
+ ```
99
+
100
+ ### Multiple Contexts
101
+ ```
102
+ # Work on frontend
103
+ /add src/components/*.jsx src/styles/*.css
104
+ /save-session frontend-work
105
+
106
+ # Switch to backend
107
+ /reset
108
+ /add server/*.py database/*.sql
109
+ /save-session backend-work
110
+
111
+ # Easily switch between contexts
112
+ /load-session frontend-work
113
+ ```
114
+
115
+ ## Best Practices
116
+
117
+ ### Naming Conventions
118
+ - Use descriptive names: `feature-auth-session`, `bugfix-issue-123`
119
+ - Include dates if needed: `2024-01-project-setup`
120
+
121
+ ### File Management
122
+ - Session files include all file paths, so they work best when project structure is stable
123
+ - External files (outside the project root) are stored with absolute paths
124
+ - Missing files are skipped with warnings during loading
125
+
126
+ ### Version Control
127
+ - Consider adding `.aider/sessions/` to your `.gitignore` if sessions contain sensitive information
128
+
129
+ ## Troubleshooting
130
+
131
+ ### Session Not Found
132
+ If `/load-session` reports "Session not found":
133
+ - Check that the session file exists in `.aider/sessions/`
134
+ - Verify the session name matches exactly
135
+ - Use `/list-sessions` to see available sessions
136
+
137
+ ### Missing Files
138
+ If files are reported as missing during loading:
139
+ - The files may have been moved or deleted
140
+ - Session files store relative paths, so directory structure changes can affect this
141
+ - External files must exist at their original locations
142
+
143
+ ### Corrupted Sessions
144
+ If a session fails to load:
145
+ - Check the session file is valid JSON
146
+ - Verify the session version is compatible
147
+ - Try creating a new session and compare file structures
148
+
149
+ ## Related Commands
150
+ - `/reset` - Clear chat history and drop files (useful before loading a session)
151
+
152
+ ## Examples
153
+
154
+ ### Complete Workflow
155
+ ```
156
+ # Start a new project session
157
+ /add package.json src/main.js src/components/
158
+ # ... work on the project ...
159
+ /save-session react-project
160
+
161
+ # Later, continue working
162
+ /load-session react-project
163
+ # All files and chat history are restored
164
+ ```
165
+
166
+ ### Session with External Files
167
+ ```
168
+ # Include documentation from outside the project
169
+ /read-only ~/docs/api-reference.md
170
+ /save-session project-with-docs
171
+ ```
172
+
173
+ ### Multiple Model Sessions
174
+ ```
175
+ # Save session with specific model
176
+ /model gpt-4
177
+ /save-session gpt4-session
178
+
179
+ # Try different model
180
+ /model claude-3
181
+ /save-session claude-session
182
+ ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aider-ce
3
- Version: 0.88.3
3
+ Version: 0.88.6.dev7
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
@@ -146,6 +146,8 @@ This project aims to be compatible with upstream Aider, but with priority commit
146
146
 
147
147
  ### Other Notes
148
148
  * [MCP Configuration](https://github.com/dwash96/aider-ce/blob/main/aider/website/docs/config/mcp.md)
149
+ * [Session Management](https://github.com/dwash96/aider-ce/blob/main/aider/website/docs/sessions.md)
150
+
149
151
 
150
152
  ### Installation Instructions
151
153
  This project can be installed using several methods: