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/__init__.py +1 -1
- aider/_version.py +2 -2
- aider/args.py +14 -2
- aider/coders/base_coder.py +162 -50
- aider/commands.py +248 -47
- aider/exceptions.py +3 -0
- aider/io.py +107 -94
- aider/main.py +4 -0
- aider/queries/tree-sitter-languages/haskell-tags.scm +3 -0
- aider/queries/tree-sitter-languages/zig-tags.scm +3 -0
- aider/repo.py +1 -1
- aider/urls.py +1 -1
- aider/versioncheck.py +1 -1
- aider/website/docs/sessions.md +182 -0
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/METADATA +3 -1
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/RECORD +20 -17
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/WHEEL +0 -0
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/entry_points.txt +0 -0
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/licenses/LICENSE.txt +0 -0
- {aider_ce-0.88.3.dist-info → aider_ce-0.88.6.dev7.dist-info}/top_level.txt +0 -0
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
|
-
|
|
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
|
-
|
|
661
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
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
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1186
|
-
confirmation_future.set_result(False)
|
|
1187
|
-
raise
|
|
1191
|
+
return False
|
|
1188
1192
|
finally:
|
|
1189
|
-
|
|
1190
|
-
|
|
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
|
-
|
|
1245
|
-
style = 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,
|
|
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,
|
|
1261
|
+
self.stream_print(message, style=style)
|
|
1255
1262
|
|
|
1256
|
-
|
|
1257
|
-
|
|
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.
|
|
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(
|
|
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))
|
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.
|
|
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/
|
|
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
|
@@ -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
|
+
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:
|