auto-coder 0.1.202__py3-none-any.whl → 0.1.203__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.
@@ -1,3 +1,6 @@
1
+ from prompt_toolkit.formatted_text import HTML
2
+ from prompt_toolkit.shortcuts import radiolist_dialog
3
+ from prompt_toolkit import prompt
1
4
  import os
2
5
  import yaml
3
6
  import json
@@ -6,6 +9,7 @@ import io
6
9
  import uuid
7
10
  import glob
8
11
  import time
12
+ import hashlib
9
13
  from contextlib import contextmanager
10
14
  from typing import List, Dict, Any, Optional
11
15
  from prompt_toolkit import PromptSession
@@ -41,6 +45,7 @@ from rich.live import Live
41
45
  from byzerllm.utils.nontext import Image
42
46
  import re
43
47
  import git
48
+ from autocoder.common import git_utils
44
49
  from autocoder.utils.request_queue import (
45
50
  request_queue,
46
51
  RequestValue,
@@ -65,7 +70,8 @@ def parse_arguments():
65
70
  import argparse
66
71
 
67
72
  parser = argparse.ArgumentParser(description="Chat Auto Coder")
68
- parser.add_argument("--debug", action="store_true", help="Enable debug mode")
73
+ parser.add_argument("--debug", action="store_true",
74
+ help="Enable debug mode")
69
75
  parser.add_argument(
70
76
  "--quick",
71
77
  action="store_true",
@@ -81,9 +87,6 @@ if platform.system() == "Windows":
81
87
 
82
88
  init()
83
89
 
84
- from prompt_toolkit import prompt
85
- from prompt_toolkit.shortcuts import radiolist_dialog
86
- from prompt_toolkit.formatted_text import HTML
87
90
 
88
91
  memory = {
89
92
  "conversation": [],
@@ -107,6 +110,7 @@ commands = [
107
110
  "/coding",
108
111
  "/chat",
109
112
  "/ask",
113
+ "/commit",
110
114
  "/revert",
111
115
  "/index/query",
112
116
  "/index/build",
@@ -149,7 +153,10 @@ def show_help():
149
153
  print(
150
154
  f" \033[94m/summon\033[0m \033[93m<query>\033[0m - \033[92m{get_message('summon_desc')}\033[0m"
151
155
  )
152
- print(f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
156
+ print(
157
+ f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
158
+ print(
159
+ f" \033[94m/commit\033[0m - \033[92m{get_message('commit_desc')}\033[0m")
153
160
  print(
154
161
  f" \033[94m/conf\033[0m \033[93m<key>:<value>\033[0m - \033[92m{get_message('conf_desc')}\033[0m"
155
162
  )
@@ -162,7 +169,8 @@ def show_help():
162
169
  print(
163
170
  f" \033[94m/list_files\033[0m - \033[92m{get_message('list_files_desc')}\033[0m"
164
171
  )
165
- print(f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
172
+ print(
173
+ f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
166
174
  print(
167
175
  f" \033[94m/exclude_dirs\033[0m \033[93m<dir1>,<dir2> ...\033[0m - \033[92m{get_message('exclude_dirs_desc')}\033[0m"
168
176
  )
@@ -172,9 +180,11 @@ def show_help():
172
180
  print(
173
181
  f" \033[94m/voice_input\033[0m - \033[92m{get_message('voice_input_desc')}\033[0m"
174
182
  )
175
- print(f" \033[94m/mode\033[0m - \033[92m{get_message('mode_desc')}\033[0m")
183
+ print(
184
+ f" \033[94m/mode\033[0m - \033[92m{get_message('mode_desc')}\033[0m")
176
185
  print(f" \033[94m/lib\033[0m - \033[92m{get_message('lib_desc')}\033[0m")
177
- print(f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
186
+ print(
187
+ f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
178
188
  print()
179
189
 
180
190
 
@@ -199,10 +209,12 @@ def configure_project_type():
199
209
  print_formatted_text(HTML(f"<info>{escape(text)}</info>"), style=style)
200
210
 
201
211
  def print_warning(text):
202
- print_formatted_text(HTML(f"<warning>{escape(text)}</warning>"), style=style)
212
+ print_formatted_text(
213
+ HTML(f"<warning>{escape(text)}</warning>"), style=style)
203
214
 
204
215
  def print_header(text):
205
- print_formatted_text(HTML(f"<header>{escape(text)}</header>"), style=style)
216
+ print_formatted_text(
217
+ HTML(f"<header>{escape(text)}</header>"), style=style)
206
218
 
207
219
  print_header(f"\n=== {get_message('project_type_config')} ===\n")
208
220
  print_info(get_message("project_type_supports"))
@@ -248,7 +260,8 @@ def initialize_system():
248
260
  if not os.path.exists(".auto-coder"):
249
261
  first_time = True
250
262
  print_status(get_message("not_initialized"), "warning")
251
- init_choice = input(f" {get_message('init_prompt')}").strip().lower()
263
+ init_choice = input(
264
+ f" {get_message('init_prompt')}").strip().lower()
252
265
  if init_choice == "y":
253
266
  try:
254
267
  subprocess.run(
@@ -265,7 +278,8 @@ def initialize_system():
265
278
 
266
279
  if not os.path.exists(base_persist_dir):
267
280
  os.makedirs(base_persist_dir, exist_ok=True)
268
- print_status(get_message("created_dir").format(base_persist_dir), "success")
281
+ print_status(get_message("created_dir").format(
282
+ base_persist_dir), "success")
269
283
 
270
284
  if first_time:
271
285
  configure_project_type()
@@ -275,7 +289,8 @@ def initialize_system():
275
289
  init_project()
276
290
  # Check if Ray is running
277
291
  print_status(get_message("checking_ray"), "")
278
- ray_status = subprocess.run(["ray", "status"], capture_output=True, text=True)
292
+ ray_status = subprocess.run(
293
+ ["ray", "status"], capture_output=True, text=True)
279
294
  if ray_status.returncode != 0:
280
295
  print_status(get_message("ray_not_running"), "warning")
281
296
  try:
@@ -395,7 +410,7 @@ def get_all_file_names_in_project() -> List[str]:
395
410
 
396
411
  file_names = []
397
412
  final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
398
- for root, dirs, files in os.walk(project_root,followlinks=True):
413
+ for root, dirs, files in os.walk(project_root, followlinks=True):
399
414
  dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
400
415
  file_names.extend(files)
401
416
  return file_names
@@ -405,7 +420,7 @@ def get_all_file_in_project() -> List[str]:
405
420
 
406
421
  file_names = []
407
422
  final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
408
- for root, dirs, files in os.walk(project_root,followlinks=True):
423
+ for root, dirs, files in os.walk(project_root, followlinks=True):
409
424
  dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
410
425
  for file in files:
411
426
  file_names.append(os.path.join(root, file))
@@ -415,17 +430,18 @@ def get_all_file_in_project() -> List[str]:
415
430
  def get_all_file_in_project_with_dot() -> List[str]:
416
431
  file_names = []
417
432
  final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
418
- for root, dirs, files in os.walk(project_root,followlinks=True):
433
+ for root, dirs, files in os.walk(project_root, followlinks=True):
419
434
  dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
420
435
  for file in files:
421
- file_names.append(os.path.join(root, file).replace(project_root, "."))
436
+ file_names.append(os.path.join(
437
+ root, file).replace(project_root, "."))
422
438
  return file_names
423
439
 
424
440
 
425
441
  def get_all_dir_names_in_project() -> List[str]:
426
442
  dir_names = []
427
443
  final_exclude_dirs = defaut_exclude_dirs + memory.get("exclude_dirs", [])
428
- for root, dirs, files in os.walk(project_root,followlinks=True):
444
+ for root, dirs, files in os.walk(project_root, followlinks=True):
429
445
  dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
430
446
  for dir in dirs:
431
447
  dir_names.append(dir)
@@ -448,8 +464,8 @@ def find_files_in_project(patterns: List[str]) -> List[str]:
448
464
  matched_files.append(abs_path)
449
465
  else:
450
466
  is_added = False
451
- ## add files belongs to project
452
- for root, dirs, files in os.walk(project_root,followlinks=True):
467
+ # add files belongs to project
468
+ for root, dirs, files in os.walk(project_root, followlinks=True):
453
469
  dirs[:] = [d for d in dirs if d not in final_exclude_dirs]
454
470
  if pattern in files:
455
471
  matched_files.append(os.path.join(root, pattern))
@@ -460,7 +476,7 @@ def find_files_in_project(patterns: List[str]) -> List[str]:
460
476
  if _pattern in os.path.join(root, file):
461
477
  matched_files.append(os.path.join(root, file))
462
478
  is_added = True
463
- ## add files not belongs to project
479
+ # add files not belongs to project
464
480
  if not is_added:
465
481
  matched_files.append(pattern)
466
482
 
@@ -546,7 +562,10 @@ def show_help():
546
562
  print(
547
563
  f" \033[94m/summon\033[0m \033[93m<query>\033[0m - \033[92m{get_message('summon_desc')}\033[0m"
548
564
  )
549
- print(f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
565
+ print(
566
+ f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
567
+ print(
568
+ f" \033[94m/commit\033[0m - \033[92m{get_message('commit_desc')}\033[0m")
550
569
  print(
551
570
  f" \033[94m/conf\033[0m \033[93m<key>:<value>\033[0m - \033[92m{get_message('conf_desc')}\033[0m"
552
571
  )
@@ -559,7 +578,8 @@ def show_help():
559
578
  print(
560
579
  f" \033[94m/list_files\033[0m - \033[92m{get_message('list_files_desc')}\033[0m"
561
580
  )
562
- print(f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
581
+ print(
582
+ f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
563
583
  print(
564
584
  f" \033[94m/exclude_dirs\033[0m \033[93m<dir1>,<dir2> ...\033[0m - \033[92m{get_message('exclude_dirs_desc')}\033[0m"
565
585
  )
@@ -569,9 +589,11 @@ def show_help():
569
589
  print(
570
590
  f" \033[94m/voice_input\033[0m - \033[92m{get_message('voice_input_desc')}\033[0m"
571
591
  )
572
- print(f" \033[94m/mode\033[0m - \033[92m{get_message('mode_desc')}\033[0m")
592
+ print(
593
+ f" \033[94m/mode\033[0m - \033[92m{get_message('mode_desc')}\033[0m")
573
594
  print(f" \033[94m/lib\033[0m - \033[92m{get_message('lib_desc')}\033[0m")
574
- print(f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
595
+ print(
596
+ f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
575
597
  print()
576
598
 
577
599
 
@@ -635,13 +657,13 @@ class CommandCompleter(Completer):
635
657
 
636
658
  if len(words) > 0:
637
659
  if words[0] == "/mode":
638
- left_word = text[len("/mode") :]
660
+ left_word = text[len("/mode"):]
639
661
  for mode in ["normal", "auto_detect", "voice_input"]:
640
662
  if mode.startswith(left_word.strip()):
641
663
  yield Completion(mode, start_position=-len(left_word.strip()))
642
664
 
643
665
  if words[0] == "/add_files":
644
- new_text = text[len("/add_files") :]
666
+ new_text = text[len("/add_files"):]
645
667
  parser = CommandTextParser(new_text, words[0])
646
668
  parser.add_files()
647
669
  current_word = parser.current_word()
@@ -672,18 +694,21 @@ class CommandCompleter(Completer):
672
694
  for file_name in self.all_files_with_dot:
673
695
  if file_name.startswith(current_word):
674
696
  yield Completion(
675
- file_name, start_position=-len(current_word)
697
+ file_name, start_position=-
698
+ len(current_word)
676
699
  )
677
700
  else:
678
701
  for file_name in self.all_file_names:
679
702
  if file_name.startswith(current_word):
680
703
  yield Completion(
681
- file_name, start_position=-len(current_word)
704
+ file_name, start_position=-
705
+ len(current_word)
682
706
  )
683
707
  for file_name in self.all_files:
684
708
  if current_word and current_word in file_name:
685
709
  yield Completion(
686
- file_name, start_position=-len(current_word)
710
+ file_name, start_position=-
711
+ len(current_word)
687
712
  )
688
713
  elif words[0] in ["/chat", "/coding"]:
689
714
  image_extensions = (
@@ -713,7 +738,7 @@ class CommandCompleter(Completer):
713
738
  ".psd",
714
739
  ".xcf",
715
740
  )
716
- new_text = text[len(words[0]) :]
741
+ new_text = text[len(words[0]):]
717
742
  parser = CommandTextParser(new_text, words[0])
718
743
 
719
744
  parser.coding()
@@ -740,7 +765,8 @@ class CommandCompleter(Completer):
740
765
  if len(path_parts) > 3
741
766
  else file_name
742
767
  )
743
- relative_path = os.path.relpath(file_name, project_root)
768
+ relative_path = os.path.relpath(
769
+ file_name, project_root)
744
770
  yield Completion(
745
771
  relative_path,
746
772
  start_position=-len(name),
@@ -757,7 +783,8 @@ class CommandCompleter(Completer):
757
783
  if len(path_parts) > 3
758
784
  else file_name
759
785
  )
760
- relative_path = os.path.relpath(file_name, project_root)
786
+ relative_path = os.path.relpath(
787
+ file_name, project_root)
761
788
 
762
789
  yield Completion(
763
790
  relative_path,
@@ -773,7 +800,8 @@ class CommandCompleter(Completer):
773
800
  if len(path_parts) > 3
774
801
  else file_name
775
802
  )
776
- relative_path = os.path.relpath(file_name, project_root)
803
+ relative_path = os.path.relpath(
804
+ file_name, project_root)
777
805
  yield Completion(
778
806
  relative_path,
779
807
  start_position=-len(name),
@@ -791,7 +819,8 @@ class CommandCompleter(Completer):
791
819
  if len(path_parts) > 3
792
820
  else symbol.symbol_name
793
821
  )
794
- relative_path = os.path.relpath(file_name, project_root)
822
+ relative_path = os.path.relpath(
823
+ file_name, project_root)
795
824
  yield Completion(
796
825
  f"{symbol.symbol_name}(location: {relative_path})",
797
826
  start_position=-len(name),
@@ -826,7 +855,8 @@ class CommandCompleter(Completer):
826
855
  for dir in dirs:
827
856
  full_path = os.path.join(root, dir)
828
857
  if full_path.startswith(file_name):
829
- relative_path = os.path.relpath(full_path, search_dir)
858
+ relative_path = os.path.relpath(
859
+ full_path, search_dir)
830
860
  yield Completion(
831
861
  relative_path,
832
862
  start_position=-len(file_basename),
@@ -838,7 +868,8 @@ class CommandCompleter(Completer):
838
868
  image_extensions
839
869
  ) and file.startswith(file_basename):
840
870
  full_path = os.path.join(root, file)
841
- relative_path = os.path.relpath(full_path, search_dir)
871
+ relative_path = os.path.relpath(
872
+ full_path, search_dir)
842
873
  yield Completion(
843
874
  relative_path,
844
875
  start_position=-len(file_basename),
@@ -848,7 +879,7 @@ class CommandCompleter(Completer):
848
879
  break
849
880
 
850
881
  elif words[0] == "/remove_files":
851
- new_words = text[len("/remove_files") :].strip().split(",")
882
+ new_words = text[len("/remove_files"):].strip().split(",")
852
883
 
853
884
  is_at_space = text[-1] == " "
854
885
  last_word = new_words[-2] if len(new_words) > 1 else ""
@@ -875,7 +906,7 @@ class CommandCompleter(Completer):
875
906
  file_name, start_position=-len(current_word)
876
907
  )
877
908
  elif words[0] == "/exclude_dirs":
878
- new_words = text[len("/exclude_dirs") :].strip().split(",")
909
+ new_words = text[len("/exclude_dirs"):].strip().split(",")
879
910
  current_word = new_words[-1]
880
911
 
881
912
  for file_name in self.all_dir_names:
@@ -883,7 +914,7 @@ class CommandCompleter(Completer):
883
914
  yield Completion(file_name, start_position=-len(current_word))
884
915
 
885
916
  elif words[0] == "/lib":
886
- new_text = text[len("/lib") :]
917
+ new_text = text[len("/lib"):]
887
918
  parser = CommandTextParser(new_text, words[0])
888
919
  parser.lib()
889
920
  current_word = parser.current_word()
@@ -900,7 +931,7 @@ class CommandCompleter(Completer):
900
931
  )
901
932
 
902
933
  elif words[0] == "/conf":
903
- new_words = text[len("/conf") :].strip().split()
934
+ new_words = text[len("/conf"):].strip().split()
904
935
  is_at_space = text[-1] == " "
905
936
  last_word = new_words[-2] if len(new_words) > 1 else ""
906
937
  current_word = new_words[-1] if new_words else ""
@@ -919,7 +950,8 @@ class CommandCompleter(Completer):
919
950
  ]
920
951
  # /conf [curosr]
921
952
  elif not last_word and not current_word:
922
- completions = ["/drop"] if "/drop".startswith(current_word) else []
953
+ completions = [
954
+ "/drop"] if "/drop".startswith(current_word) else []
923
955
  completions += [
924
956
  field_name + ":"
925
957
  for field_name in AutoCoderArgs.model_fields.keys()
@@ -927,7 +959,8 @@ class CommandCompleter(Completer):
927
959
  ]
928
960
  # /conf p[cursor]
929
961
  elif not last_word and current_word:
930
- completions = ["/drop"] if "/drop".startswith(current_word) else []
962
+ completions = [
963
+ "/drop"] if "/drop".startswith(current_word) else []
931
964
  completions += [
932
965
  field_name + ":"
933
966
  for field_name in AutoCoderArgs.model_fields.keys()
@@ -955,7 +988,7 @@ class CommandCompleter(Completer):
955
988
  self.all_files = get_all_file_in_project()
956
989
  self.all_dir_names = get_all_dir_names_in_project()
957
990
  self.all_files_with_dot = get_all_file_in_project_with_dot()
958
- self.symbol_list = get_symbol_list()
991
+ self.symbol_list = get_symbol_list()
959
992
 
960
993
 
961
994
  completer = CommandCompleter(commands)
@@ -1021,7 +1054,8 @@ def add_files(args: List[str]):
1021
1054
  completer.refresh_files()
1022
1055
  load_memory()
1023
1056
  console.print(
1024
- Panel("Refreshed file list.", title="Files Refreshed", border_style="green")
1057
+ Panel("Refreshed file list.",
1058
+ title="Files Refreshed", border_style="green")
1025
1059
  )
1026
1060
  return
1027
1061
 
@@ -1029,7 +1063,8 @@ def add_files(args: List[str]):
1029
1063
  if len(args) == 1 or (len(args) == 2 and args[1] == "list"):
1030
1064
  if not groups:
1031
1065
  console.print(
1032
- Panel("No groups defined.", title="Groups", border_style="yellow")
1066
+ Panel("No groups defined.", title="Groups",
1067
+ border_style="yellow")
1033
1068
  )
1034
1069
  else:
1035
1070
  table = Table(
@@ -1054,7 +1089,8 @@ def add_files(args: List[str]):
1054
1089
  )
1055
1090
  table.add_row(
1056
1091
  group_name,
1057
- "\n".join([os.path.relpath(f, project_root) for f in files]),
1092
+ "\n".join([os.path.relpath(f, project_root)
1093
+ for f in files]),
1058
1094
  query_prefix,
1059
1095
  is_active,
1060
1096
  end_section=(i == len(groups) - 1),
@@ -1086,7 +1122,8 @@ def add_files(args: List[str]):
1086
1122
  if group_name in groups_info:
1087
1123
  del memory["current_files"]["groups_info"][group_name]
1088
1124
  if group_name in memory["current_files"]["current_groups"]:
1089
- memory["current_files"]["current_groups"].remove(group_name)
1125
+ memory["current_files"]["current_groups"].remove(
1126
+ group_name)
1090
1127
  console.print(
1091
1128
  Panel(
1092
1129
  f"Dropped group '{group_name}'.",
@@ -1259,7 +1296,8 @@ def remove_files(file_names: List[str]):
1259
1296
  memory["current_files"]["files"] = []
1260
1297
  memory["current_files"]["current_groups"] = []
1261
1298
  console.print(
1262
- Panel("Removed all files.", title="Files Removed", border_style="green")
1299
+ Panel("Removed all files.",
1300
+ title="Files Removed", border_style="green")
1263
1301
  )
1264
1302
  else:
1265
1303
  removed_files = []
@@ -1373,6 +1411,76 @@ def get_llm_friendly_package_docs(
1373
1411
  return docs
1374
1412
 
1375
1413
 
1414
+ def convert_yaml_to_config(yaml_file: str):
1415
+ from autocoder.auto_coder import AutoCoderArgs, load_include_files, Template
1416
+ args = AutoCoderArgs()
1417
+ with open(yaml_file, "r") as f:
1418
+ config = yaml.safe_load(f)
1419
+ config = load_include_files(config, yaml_file)
1420
+ for key, value in config.items():
1421
+ if key != "file": # 排除 --file 参数本身
1422
+ # key: ENV {{VARIABLE_NAME}}
1423
+ if isinstance(value, str) and value.startswith("ENV"):
1424
+ template = Template(value.removeprefix("ENV").strip())
1425
+ value = template.render(os.environ)
1426
+ setattr(args, key, value)
1427
+ return args
1428
+
1429
+ def commit():
1430
+ def prepare_commit_yaml():
1431
+ auto_coder_main(["next", "chat_action"])
1432
+
1433
+ prepare_commit_yaml()
1434
+
1435
+ latest_yaml_file = get_last_yaml_file("actions")
1436
+
1437
+ conf = memory.get("conf", {})
1438
+ current_files = memory["current_files"]["files"]
1439
+ execute_file = None
1440
+
1441
+ if latest_yaml_file:
1442
+ try:
1443
+ execute_file = os.path.join("actions", latest_yaml_file)
1444
+ yaml_config = {
1445
+ "include_file": ["./base/base.yml"],
1446
+ "auto_merge": conf.get("auto_merge", "editblock"),
1447
+ "human_as_model": conf.get("human_as_model", "false") == "true",
1448
+ "skip_build_index": conf.get("skip_build_index", "true") == "true",
1449
+ "skip_confirm": conf.get("skip_confirm", "true") == "true",
1450
+ "silence": conf.get("silence", "true") == "true",
1451
+ "include_project_structure": conf.get("include_project_structure", "true")
1452
+ == "true",
1453
+ }
1454
+ for key, value in conf.items():
1455
+ converted_value = convert_config_value(key, value)
1456
+ if converted_value is not None:
1457
+ yaml_config[key] = converted_value
1458
+
1459
+ yaml_config["urls"] = current_files + get_llm_friendly_package_docs(
1460
+ return_paths=True
1461
+ )
1462
+ args = convert_yaml_to_config(execute_file)
1463
+ llm = byzerllm.ByzerLLM.from_default_model(args.code_model or args.model)
1464
+ uncommitted_changes = git_utils.get_uncommitted_changes(".")
1465
+ commit_message = git_utils.generate_commit_message.with_llm(
1466
+ llm).run(uncommitted_changes)
1467
+ memory["conversation"].append({"role": "user", "content": commit_message})
1468
+ yaml_config["query"] = commit_message
1469
+ yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
1470
+ with open(os.path.join(execute_file), "w") as f:
1471
+ f.write(yaml_content)
1472
+
1473
+ file_content = open(execute_file).read()
1474
+ md5 = hashlib.md5(file_content.encode('utf-8')).hexdigest()
1475
+ file_name = os.path.basename(execute_file)
1476
+ commit_result = git_utils.commit_changes(".", f"auto_coder_{file_name}_{md5}")
1477
+ git_utils.print_commit_info(commit_result=commit_result)
1478
+ except Exception as e:
1479
+ print(f"Failed to commit: {e}")
1480
+ if execute_file:
1481
+ os.remove(execute_file)
1482
+
1483
+
1376
1484
  def coding(query: str):
1377
1485
  console = Console()
1378
1486
  is_apply = query.strip().startswith("/apply")
@@ -1415,7 +1523,7 @@ def coding(query: str):
1415
1523
  return_paths=True
1416
1524
  )
1417
1525
 
1418
- ## handle image
1526
+ # handle image
1419
1527
  v = Image.convert_image_paths_from(query)
1420
1528
  yaml_config["query"] = v
1421
1529
 
@@ -1424,7 +1532,8 @@ def coding(query: str):
1424
1532
  active_groups_context = "下面是对上面文件按分组给到的一些描述,当用户的需求正好匹配描述的时候,参考描述来做修改:\n"
1425
1533
  for group in current_groups:
1426
1534
  group_files = groups.get(group, [])
1427
- query_prefix = groups_info.get(group, {}).get("query_prefix", "")
1535
+ query_prefix = groups_info.get(
1536
+ group, {}).get("query_prefix", "")
1428
1537
  active_groups_context += f"组名: {group}\n"
1429
1538
  active_groups_context += f"文件列表:\n"
1430
1539
  for file in group_files:
@@ -1508,10 +1617,10 @@ def code_review(query: str) -> str:
1508
1617
 
1509
1618
  def chat(query: str):
1510
1619
  conf = memory.get("conf", {})
1511
-
1620
+
1512
1621
  yaml_config = {
1513
1622
  "include_file": ["./base/base.yml"],
1514
- "include_project_structure": conf.get("include_project_structure", "true") in ["true","True"],
1623
+ "include_project_structure": conf.get("include_project_structure", "true") in ["true", "True"],
1515
1624
  "human_as_model": conf.get("human_as_model", "false") == "true",
1516
1625
  "skip_build_index": conf.get("skip_build_index", "true") == "true",
1517
1626
  "skip_confirm": conf.get("skip_confirm", "true") == "true",
@@ -1868,7 +1977,8 @@ def execute_shell_command(command: str):
1868
1977
  f"[bold red]Command failed with return code {process.returncode}[/bold red]"
1869
1978
  )
1870
1979
  else:
1871
- console.print("[bold green]Command completed successfully[/bold green]")
1980
+ console.print(
1981
+ "[bold green]Command completed successfully[/bold green]")
1872
1982
 
1873
1983
  except FileNotFoundError:
1874
1984
  console.print(
@@ -1916,7 +2026,8 @@ def lib_command(args: List[str]):
1916
2026
  proxy_url,
1917
2027
  llm_friendly_packages_dir,
1918
2028
  )
1919
- console.print("Successfully cloned llm_friendly_packages repository")
2029
+ console.print(
2030
+ "Successfully cloned llm_friendly_packages repository")
1920
2031
  except git.exc.GitCommandError as e:
1921
2032
  console.print(f"Error cloning repository: {e}")
1922
2033
 
@@ -1977,7 +2088,8 @@ def lib_command(args: List[str]):
1977
2088
  console.print(f"Updated remote URL to: {new_url}")
1978
2089
 
1979
2090
  origin.pull()
1980
- console.print("Successfully updated llm_friendly_packages repository")
2091
+ console.print(
2092
+ "Successfully updated llm_friendly_packages repository")
1981
2093
 
1982
2094
  except git.exc.GitCommandError as e:
1983
2095
  console.print(f"Error updating repository: {e}")
@@ -1999,7 +2111,8 @@ def lib_command(args: List[str]):
1999
2111
  table.add_row(doc)
2000
2112
  console.print(table)
2001
2113
  else:
2002
- console.print(f"No markdown files found for package: {package_name}")
2114
+ console.print(
2115
+ f"No markdown files found for package: {package_name}")
2003
2116
 
2004
2117
  else:
2005
2118
  console.print(f"Unknown subcommand: {subcommand}")
@@ -2123,7 +2236,8 @@ def main():
2123
2236
  FormattedText(prompt_message), default=new_prompt, style=style
2124
2237
  )
2125
2238
  else:
2126
- user_input = session.prompt(FormattedText(prompt_message), style=style)
2239
+ user_input = session.prompt(
2240
+ FormattedText(prompt_message), style=style)
2127
2241
  new_prompt = ""
2128
2242
 
2129
2243
  if "mode" not in memory:
@@ -2148,13 +2262,14 @@ def main():
2148
2262
  new_prompt = "/coding " + text
2149
2263
 
2150
2264
  elif user_input.startswith("/add_files"):
2151
- args = user_input[len("/add_files") :].strip().split()
2265
+ args = user_input[len("/add_files"):].strip().split()
2152
2266
  add_files(args)
2153
2267
  elif user_input.startswith("/remove_files"):
2154
- file_names = user_input[len("/remove_files") :].strip().split(",")
2268
+ file_names = user_input[len(
2269
+ "/remove_files"):].strip().split(",")
2155
2270
  remove_files(file_names)
2156
2271
  elif user_input.startswith("/index/query"):
2157
- query = user_input[len("/index/query") :].strip()
2272
+ query = user_input[len("/index/query"):].strip()
2158
2273
  index_query(query)
2159
2274
 
2160
2275
  elif user_input.startswith("/index/build"):
@@ -2164,27 +2279,30 @@ def main():
2164
2279
  list_files()
2165
2280
 
2166
2281
  elif user_input.startswith("/mode"):
2167
- conf = user_input[len("/mode") :].strip()
2282
+ conf = user_input[len("/mode"):].strip()
2168
2283
  if not conf:
2169
2284
  print(memory["mode"])
2170
2285
  else:
2171
2286
  memory["mode"] = conf
2172
2287
 
2173
2288
  elif user_input.startswith("/conf"):
2174
- conf = user_input[len("/conf") :].strip()
2289
+ conf = user_input[len("/conf"):].strip()
2175
2290
  if not conf:
2176
2291
  print(memory["conf"])
2177
2292
  else:
2178
2293
  configure(conf)
2179
2294
  elif user_input.startswith("/revert"):
2180
2295
  revert()
2296
+ elif user_input.startswith("/commit"):
2297
+ commit()
2181
2298
  elif user_input.startswith("/help"):
2182
2299
  show_help()
2183
2300
  elif user_input.startswith("/exclude_dirs"):
2184
- dir_names = user_input[len("/exclude_dirs") :].strip().split(",")
2301
+ dir_names = user_input[len(
2302
+ "/exclude_dirs"):].strip().split(",")
2185
2303
  exclude_dirs(dir_names)
2186
2304
  elif user_input.startswith("/ask"):
2187
- query = user_input[len("/ask") :].strip()
2305
+ query = user_input[len("/ask"):].strip()
2188
2306
  if not query:
2189
2307
  print("Please enter your question.")
2190
2308
  else:
@@ -2194,38 +2312,38 @@ def main():
2194
2312
  raise EOFError()
2195
2313
 
2196
2314
  elif user_input.startswith("/coding"):
2197
- query = user_input[len("/coding") :].strip()
2315
+ query = user_input[len("/coding"):].strip()
2198
2316
  if not query:
2199
2317
  print("\033[91mPlease enter your request.\033[0m")
2200
2318
  continue
2201
2319
  coding(query)
2202
2320
  elif user_input.startswith("/chat"):
2203
- query = user_input[len("/chat") :].strip()
2321
+ query = user_input[len("/chat"):].strip()
2204
2322
  if not query:
2205
2323
  print("\033[91mPlease enter your request.\033[0m")
2206
2324
  else:
2207
2325
  chat(query)
2208
2326
 
2209
2327
  elif user_input.startswith("/design"):
2210
- query = user_input[len("/design") :].strip()
2328
+ query = user_input[len("/design"):].strip()
2211
2329
  if not query:
2212
2330
  print("\033[91mPlease enter your design request.\033[0m")
2213
2331
  else:
2214
2332
  design(query)
2215
2333
 
2216
2334
  elif user_input.startswith("/summon"):
2217
- query = user_input[len("/summon") :].strip()
2335
+ query = user_input[len("/summon"):].strip()
2218
2336
  if not query:
2219
2337
  print("\033[91mPlease enter your request.\033[0m")
2220
2338
  else:
2221
2339
  summon(query)
2222
2340
 
2223
2341
  elif user_input.startswith("/lib"):
2224
- args = user_input[len("/lib") :].strip().split()
2342
+ args = user_input[len("/lib"):].strip().split()
2225
2343
  lib_command(args)
2226
2344
 
2227
2345
  elif user_input.startswith("/debug"):
2228
- code = user_input[len("/debug") :].strip()
2346
+ code = user_input[len("/debug"):].strip()
2229
2347
  try:
2230
2348
  result = eval(code)
2231
2349
  print(f"Debug result: {result}")
@@ -2236,7 +2354,7 @@ def main():
2236
2354
  else:
2237
2355
  command = user_input
2238
2356
  if user_input.startswith("/shell"):
2239
- command = user_input[len("/shell") :].strip()
2357
+ command = user_input[len("/shell"):].strip()
2240
2358
  if not command:
2241
2359
  print("Please enter a shell command to execute.")
2242
2360
  else: