auto-coder 0.1.235__py3-none-any.whl → 0.1.238__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 auto-coder might be problematic. Click here for more details.

@@ -1,70 +1,79 @@
1
1
  import byzerllm
2
- from typing import List,Union
2
+ from typing import List, Union
3
3
  from autocoder.common import AutoCoderArgs
4
4
  from autocoder.common.types import CodeGenerateResult
5
5
  from pydantic import BaseModel
6
- from loguru import logger
6
+ from autocoder.common.printer import Printer
7
7
  from concurrent.futures import ThreadPoolExecutor, as_completed
8
8
  import traceback
9
-
9
+ from autocoder.common.utils_code_auto_generate import chat_with_continue
10
+ from byzerllm.utils.str2model import to_model
10
11
  class RankResult(BaseModel):
11
- rank_result:List[int]
12
+ rank_result: List[int]
13
+
12
14
 
13
15
  class CodeModificationRanker:
14
16
  def __init__(self, llm: byzerllm.ByzerLLM, args: AutoCoderArgs):
15
17
  self.llm = llm
16
- self.args = args
17
- self.llms = self.llm.get_sub_client("generate_rerank_model") or [self.llm]
18
+ self.args = args
19
+ self.llms = self.llm.get_sub_client(
20
+ "generate_rerank_model") or [self.llm]
18
21
  if not isinstance(self.llms, list):
19
22
  self.llms = [self.llms]
20
-
23
+ self.printer = Printer()
24
+
21
25
  @byzerllm.prompt()
22
- def _rank_modifications(self, s:CodeGenerateResult) -> str:
26
+ def _rank_modifications(self, s: CodeGenerateResult) -> str:
23
27
  '''
24
28
  对一组代码修改进行质量评估并排序。
25
29
 
26
30
  下面是修改需求:
27
-
31
+
28
32
  <edit_requirement>
29
33
  {{ s.conversations[0][-2]["content"] }}
30
34
  </edit_requirement>
31
-
35
+
32
36
  下面是相应的代码修改:
33
37
  {% for content in s.contents %}
34
38
  <edit_block id="{{ loop.index0 }}">
35
39
  {{content}}
36
40
  </edit_block>
37
41
  {% endfor %}
38
-
42
+
39
43
  请输出如下格式的评估结果,只包含 JSON 数据:
40
44
 
41
45
  ```json
42
46
  {
43
- "rank_result": [id1, id2, id3] // id 为 edit_block 的 id,按质量从高到低排序
47
+ "rank_result": [id1, id2, id3]
44
48
  }
45
49
  ```
46
50
 
47
- 注意:
48
- 1. 只输出前面要求的 Json 格式就好,不要输出其他内容,Json 需要使用 ```json ```包裹
51
+ 注意:
52
+ 1. id edit_block id,按质量从高到低排序,并且 id 必须是数字
53
+ 2. 只输出前面要求的 Json 格式就好,不要输出其他内容,Json 需要使用 ```json ```包裹
49
54
  '''
50
-
51
55
 
52
56
  def rank_modifications(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
53
57
  import time
54
58
  from collections import defaultdict
55
59
 
56
60
  start_time = time.time()
57
-
61
+
58
62
  # 如果只有一个候选,直接返回
59
63
  if len(generate_result.contents) == 1:
60
- logger.info("Only 1 candidate, skip ranking")
64
+ self.printer.print_in_terminal("ranking_skip", style="blue")
61
65
  return generate_result
62
-
63
- logger.info(f"Start ranking {len(generate_result.contents)} candidates")
66
+
67
+ self.printer.print_in_terminal(
68
+ "ranking_start", style="blue", count=len(generate_result.contents))
64
69
  generate_times = self.args.generate_times_same_model
65
70
  total_tasks = len(self.llms) * generate_times
71
+
72
+ query = self._rank_modifications.prompt(generate_result)
73
+ input_tokens_count = 0
74
+ generated_tokens_count = 0
66
75
  try:
67
- # Create a thread pool with (number of models * generate_times) workers
76
+ # Create a thread pool with (number of models * generate_times) workers
68
77
  with ThreadPoolExecutor(max_workers=total_tasks) as executor:
69
78
  # Submit tasks for each model and generate_times
70
79
  futures = []
@@ -72,49 +81,70 @@ class CodeModificationRanker:
72
81
  for _ in range(generate_times):
73
82
  futures.append(
74
83
  executor.submit(
75
- self._rank_modifications.with_llm(llm).with_return_type(RankResult).run,
76
- generate_result
84
+ chat_with_continue,
85
+ llm,
86
+ [{"role": "user", "content": query}],
87
+ {}
77
88
  )
78
89
  )
79
-
90
+
80
91
  # Collect all results
81
92
  results = []
82
93
  for future in as_completed(futures):
83
94
  try:
84
- v = future.result()
95
+ result = future.result()
96
+ input_tokens_count += result.input_tokens_count
97
+ generated_tokens_count += result.generated_tokens_count
98
+ v = to_model(result.content,RankResult)
85
99
  results.append(v.rank_result)
86
100
  except Exception as e:
87
- logger.warning(f"Ranking request failed: {str(e)}")
88
- logger.debug(traceback.format_exc())
101
+ self.printer.print_in_terminal(
102
+ "ranking_failed_request", style="yellow", error=str(e))
103
+ if self.args.debug:
104
+ print(traceback.format_exc())
89
105
  continue
90
-
106
+
91
107
  if not results:
92
- raise Exception("All ranking requests failed")
93
-
108
+ raise Exception(
109
+ self.printer.get_message_from_key("ranking_all_failed"))
110
+
94
111
  # Calculate scores for each candidate
95
112
  candidate_scores = defaultdict(float)
96
113
  for rank_result in results:
97
114
  for idx, candidate_id in enumerate(rank_result):
98
115
  # Score is 1/(position + 1) since position starts from 0
99
116
  candidate_scores[candidate_id] += 1.0 / (idx + 1)
100
-
117
+
101
118
  # Sort candidates by score in descending order
102
- sorted_candidates = sorted(candidate_scores.keys(),
103
- key=lambda x: candidate_scores[x],
104
- reverse=True)
105
-
119
+ sorted_candidates = sorted(candidate_scores.keys(),
120
+ key=lambda x: candidate_scores[x],
121
+ reverse=True)
122
+
106
123
  elapsed = time.time() - start_time
107
124
  # Format scores for logging
108
- score_details = ", ".join([f"candidate {i}: {candidate_scores[i]:.2f}" for i in sorted_candidates])
109
- logger.info(f"Ranking completed in {elapsed:.2f}s, total voters: {total_tasks}, best candidate index: {sorted_candidates[0]}, scores: {score_details}")
110
-
111
- rerank_contents = [generate_result.contents[i] for i in sorted_candidates]
112
- rerank_conversations = [generate_result.conversations[i] for i in sorted_candidates]
113
- return CodeGenerateResult(contents=rerank_contents,conversations=rerank_conversations)
114
-
125
+ score_details = ", ".join(
126
+ [f"candidate {i}: {candidate_scores[i]:.2f}" for i in sorted_candidates])
127
+ self.printer.print_in_terminal(
128
+ "ranking_complete",
129
+ style="green",
130
+ elapsed=f"{elapsed:.2f}",
131
+ total_tasks=total_tasks,
132
+ best_candidate=sorted_candidates[0],
133
+ scores=score_details,
134
+ input_tokens=input_tokens_count,
135
+ output_tokens=generated_tokens_count
136
+ )
137
+
138
+ rerank_contents = [generate_result.contents[i]
139
+ for i in sorted_candidates]
140
+ rerank_conversations = [
141
+ generate_result.conversations[i] for i in sorted_candidates]
142
+ return CodeGenerateResult(contents=rerank_contents, conversations=rerank_conversations)
143
+
115
144
  except Exception as e:
116
- logger.error(f"Ranking process failed: {str(e)}")
117
- logger.debug(traceback.format_exc())
145
+ self.printer.print_in_terminal(
146
+ "ranking_process_failed", style="red", error=str(e))
118
147
  elapsed = time.time() - start_time
119
- logger.warning(f"Ranking failed in {elapsed:.2f}s, using original order")
148
+ self.printer.print_in_terminal(
149
+ "ranking_failed", style="yellow", elapsed=f"{elapsed:.2f}")
120
150
  return generate_result
@@ -1,5 +1,7 @@
1
1
  from rich.console import Console
2
- from typing import Optional
2
+ from rich.panel import Panel
3
+ from rich.text import Text
4
+ from typing import Optional,Dict,Any
3
5
  from byzerllm.utils import format_str_jinja2
4
6
  from autocoder.common.auto_coder_lang import get_message
5
7
  from autocoder.chat_auto_coder_lang import get_message as get_chat_message
@@ -10,20 +12,26 @@ class Printer:
10
12
  else:
11
13
  self.console = console
12
14
 
13
- def get_message_from_key(self, key: str):
15
+ def get_message_from_key(self, msg_key: str):
14
16
  try:
15
- return get_message(key)
17
+ return get_message(msg_key)
16
18
  except Exception as e:
17
- return get_chat_message(key)
19
+ return get_chat_message(msg_key)
18
20
 
19
- def print_in_terminal(self, key: str, style: str = None,**kwargs):
21
+ def get_message_from_key_with_format(self, msg_key: str, **kwargs):
22
+ try:
23
+ return format_str_jinja2(self.get_message_from_key(msg_key), **kwargs)
24
+ except Exception as e:
25
+ return format_str_jinja2(self.get_chat_message_from_key(msg_key), **kwargs)
26
+
27
+ def print_in_terminal(self, msg_key: str, style: str = None,**kwargs):
20
28
  try:
21
29
  if style:
22
- self.console.print(format_str_jinja2(self.get_message_from_key(key),**kwargs), style=style)
30
+ self.console.print(format_str_jinja2(self.get_message_from_key(msg_key),**kwargs), style=style)
23
31
  else:
24
- self.console.print(format_str_jinja2(self.get_message_from_key(key),**kwargs))
32
+ self.console.print(format_str_jinja2(self.get_message_from_key(msg_key),**kwargs))
25
33
  except Exception as e:
26
- print(self.get_message_from_key(key))
34
+ print(self.get_message_from_key(msg_key))
27
35
 
28
36
 
29
37
  def print_str_in_terminal(self, content: str, style: str = None):
@@ -33,4 +41,9 @@ class Printer:
33
41
  else:
34
42
  self.console.print(content)
35
43
  except Exception as e:
36
- print(content)
44
+ print(content)
45
+
46
+ def print_panel(self, content: str, text_options:Dict[str,Any], panel_options:Dict[str,Any]):
47
+ panel = Panel(Text(content, **text_options), **panel_options)
48
+ self.console.print(panel)
49
+
@@ -25,9 +25,10 @@ from autocoder.common.image_to_page import ImageToPage, ImageToPageDirectly
25
25
  from autocoder.utils.conversation_store import store_code_model_conversation
26
26
  from loguru import logger
27
27
  import time
28
+ from autocoder.common.printer import Printer
28
29
 
29
30
 
30
- class BaseAction:
31
+ class BaseAction:
31
32
  def _get_content_length(self, content: str) -> int:
32
33
  try:
33
34
  tokenizer = BuildinTokenizer()
@@ -43,6 +44,7 @@ class ActionTSProject(BaseAction):
43
44
  self.args = args
44
45
  self.llm = llm
45
46
  self.pp = None
47
+ self.printer = Printer()
46
48
 
47
49
  def run(self):
48
50
  args = self.args
@@ -96,8 +98,8 @@ class ActionTSProject(BaseAction):
96
98
  f"Content(send to model) is {content_length} tokens, which is larger than the maximum input length {self.args.model_max_input_length}"
97
99
  )
98
100
 
99
- if args.execute:
100
- logger.info("Auto generate the code...")
101
+ if args.execute:
102
+ self.printer.print_in_terminal("code_generation_start")
101
103
  start_time = time.time()
102
104
  if args.auto_merge == "diff":
103
105
  generate = CodeAutoGenerateDiff(
@@ -121,10 +123,15 @@ class ActionTSProject(BaseAction):
121
123
  generate_result = generate.single_round_run(
122
124
  query=args.query, source_content=content
123
125
  )
124
- logger.info(f"Code generation completed in {time.time() - start_time:.2f} seconds, input_tokens_count: {generate_result.metadata.get('input_tokens_count', 0)}, generated_tokens_count: {generate_result.metadata.get('generated_tokens_count', 0)}")
126
+ self.printer.print_in_terminal(
127
+ "code_generation_complete",
128
+ duration=time.time() - start_time,
129
+ input_tokens=generate_result.metadata.get('input_tokens_count', 0),
130
+ output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
131
+ )
125
132
  merge_result = None
126
133
  if args.execute and args.auto_merge:
127
- logger.info("Auto merge the code...")
134
+ self.printer.print_in_terminal("code_merge_start")
128
135
  if args.auto_merge == "diff":
129
136
  code_merge = CodeAutoMergeDiff(llm=self.llm, args=self.args)
130
137
  merge_result = code_merge.merge_code(generate_result=generate_result)
@@ -165,6 +172,7 @@ class ActionPyScriptProject(BaseAction):
165
172
  ) -> None:
166
173
  self.args = args
167
174
  self.llm = llm
175
+ self.printer = Printer()
168
176
 
169
177
  def run(self) -> bool:
170
178
  args = self.args
@@ -180,7 +188,7 @@ class ActionPyScriptProject(BaseAction):
180
188
  def process_content(self, content: str):
181
189
  args = self.args
182
190
  if args.execute:
183
- logger.info("Auto generate the code...")
191
+ self.printer.print_in_terminal("code_generation_start")
184
192
  start_time = time.time()
185
193
  if args.auto_merge == "diff":
186
194
  generate = CodeAutoGenerateDiff(
@@ -205,10 +213,15 @@ class ActionPyScriptProject(BaseAction):
205
213
  query=args.query, source_content=content
206
214
  )
207
215
 
208
- logger.info(f"Code generation completed in {time.time() - start_time:.2f} seconds, input_tokens_count: {generate_result.metadata.get('input_tokens_count', 0)}, generated_tokens_count: {generate_result.metadata.get('generated_tokens_count', 0)}")
216
+ self.printer.print_in_terminal(
217
+ "code_generation_complete",
218
+ duration=time.time() - start_time,
219
+ input_tokens=generate_result.metadata.get('input_tokens_count', 0),
220
+ output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
221
+ )
209
222
  merge_result = None
210
223
  if args.execute and args.auto_merge:
211
- logger.info("Auto merge the code...")
224
+ self.printer.print_in_terminal("code_merge_start")
212
225
  if args.auto_merge == "diff":
213
226
  code_merge = CodeAutoMergeDiff(llm=self.llm, args=self.args)
214
227
  merge_result = code_merge.merge_code(generate_result=generate_result)
@@ -241,7 +254,12 @@ class ActionPyScriptProject(BaseAction):
241
254
  )
242
255
 
243
256
  end_time = time.time()
244
- logger.info(f"Code generation completed in {end_time - start_time:.2f} seconds")
257
+ self.printer.print_in_terminal(
258
+ "code_generation_complete",
259
+ duration=end_time - start_time,
260
+ input_tokens=generate_result.metadata.get('input_tokens_count', 0),
261
+ output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
262
+ )
245
263
  with open(self.args.target_file, "w") as file:
246
264
  file.write(content)
247
265
 
@@ -253,6 +271,7 @@ class ActionPyProject(BaseAction):
253
271
  self.args = args
254
272
  self.llm = llm
255
273
  self.pp = None
274
+ self.printer = Printer()
256
275
 
257
276
  def run(self):
258
277
  args = self.args
@@ -282,12 +301,15 @@ class ActionPyProject(BaseAction):
282
301
  if args.execute and self.llm and not args.human_as_model:
283
302
  content_length = self._get_content_length(content)
284
303
  if content_length > self.args.model_max_input_length:
285
- logger.warning(
286
- f'''Content(send to model) is {content_length} tokens (you may collect too much files), which is larger than the maximum input length {self.args.model_max_input_length}'''
287
- )
304
+ self.printer.print_in_terminal(
305
+ "code_execution_warning",
306
+ style="yellow",
307
+ content_length=content_length,
308
+ max_length=self.args.model_max_input_length
309
+ )
288
310
 
289
311
  if args.execute:
290
- logger.info("Auto generate the code...")
312
+ self.printer.print_in_terminal("code_generation_start")
291
313
  start_time = time.time()
292
314
  if args.auto_merge == "diff":
293
315
  generate = CodeAutoGenerateDiff(
@@ -313,10 +335,15 @@ class ActionPyProject(BaseAction):
313
335
  generate_result = generate.single_round_run(
314
336
  query=args.query, source_content=content
315
337
  )
316
- logger.info(f"Code generation completed in {time.time() - start_time:.2f} seconds, input_tokens_count: {generate_result.metadata.get('input_tokens_count', 0)}, generated_tokens_count: {generate_result.metadata.get('generated_tokens_count', 0)}")
338
+ self.printer.print_in_terminal(
339
+ "code_generation_complete",
340
+ duration=time.time() - start_time,
341
+ input_tokens=generate_result.metadata.get('input_tokens_count', 0),
342
+ output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
343
+ )
317
344
  merge_result = None
318
345
  if args.execute and args.auto_merge:
319
- logger.info("Auto merge the code...")
346
+ self.printer.print_in_terminal("code_merge_start")
320
347
  if args.auto_merge == "diff":
321
348
  code_merge = CodeAutoMergeDiff(llm=self.llm, args=self.args)
322
349
  merge_result = code_merge.merge_code(generate_result=generate_result)
@@ -358,6 +385,7 @@ class ActionSuffixProject(BaseAction):
358
385
  self.args = args
359
386
  self.llm = llm
360
387
  self.pp = None
388
+ self.printer = Printer()
361
389
 
362
390
  def run(self):
363
391
  args = self.args
@@ -387,7 +415,7 @@ class ActionSuffixProject(BaseAction):
387
415
  )
388
416
 
389
417
  if args.execute:
390
- logger.info("Auto generate the code...")
418
+ self.printer.print_in_terminal("code_generation_start")
391
419
  start_time = time.time()
392
420
  if args.auto_merge == "diff":
393
421
  generate = CodeAutoGenerateDiff(
@@ -412,10 +440,15 @@ class ActionSuffixProject(BaseAction):
412
440
  query=args.query, source_content=content
413
441
  )
414
442
 
415
- logger.info(f"Code generation completed in {time.time() - start_time:.2f} seconds, input_tokens_count: {generate_result.metadata.get('input_tokens_count', 0)}, generated_tokens_count: {generate_result.metadata.get('generated_tokens_count', 0)}")
443
+ self.printer.print_in_terminal(
444
+ "code_generation_complete",
445
+ duration=time.time() - start_time,
446
+ input_tokens=generate_result.metadata.get('input_tokens_count', 0),
447
+ output_tokens=generate_result.metadata.get('generated_tokens_count', 0)
448
+ )
416
449
  merge_result = None
417
450
  if args.execute and args.auto_merge:
418
- logger.info("Auto merge the code...")
451
+ self.printer.print_in_terminal("code_merge_start")
419
452
  if args.auto_merge == "diff":
420
453
  code_merge = CodeAutoMergeDiff(llm=self.llm, args=self.args)
421
454
  merge_result = code_merge.merge_code(generate_result=generate_result)
autocoder/index/entry.py CHANGED
@@ -22,6 +22,7 @@ from autocoder.index.types import (
22
22
  from autocoder.index.filter.quick_filter import QuickFilter
23
23
  from autocoder.index.filter.normal_filter import NormalFilter
24
24
  from autocoder.index.index import IndexManager
25
+ from loguru import logger
25
26
 
26
27
  def build_index_and_filter_files(
27
28
  llm, args: AutoCoderArgs, sources: List[SourceCode]
@@ -99,11 +100,14 @@ def build_index_and_filter_files(
99
100
  })
100
101
  )
101
102
  )
102
-
103
- quick_filter = QuickFilter(index_manager,stats,sources)
103
+
104
+ #MARK
105
+ printer.print_in_terminal("quick_filter_start", style="blue")
106
+ quick_filter = QuickFilter(index_manager,stats,sources)
104
107
  final_files = quick_filter.filter(index_manager.read_index(),args.query)
105
108
 
106
109
  if not final_files:
110
+ printer.print_in_terminal("normal_filter_start", style="blue")
107
111
  normal_filter = NormalFilter(index_manager,stats,sources)
108
112
  final_files = normal_filter.filter(index_manager.read_index(),args.query)
109
113
 
@@ -279,7 +283,7 @@ def build_index_and_filter_files(
279
283
 
280
284
  # Print final statistics in a more structured way
281
285
  summary = f"""
282
- === Indexing and Filtering Summary ===
286
+ === File Stat ===
283
287
  • Total files scanned: {stats['total_files']}
284
288
  • Files indexed: {stats['indexed_files']}
285
289
  • Files filtered:
@@ -288,7 +292,7 @@ def build_index_and_filter_files(
288
292
  - Relevance verified: {stats.get('verified_files', 0)}
289
293
  • Final files selected: {stats['final_files']}
290
294
 
291
- === Time Breakdown ===
295
+ === Time Stat ===
292
296
  • Index build: {stats['timings'].get('build_index', 0):.2f}s
293
297
  • Quick filter: {stats['timings'].get('quick_filter', 0):.2f}s
294
298
  • Normal filter:
@@ -297,9 +301,18 @@ def build_index_and_filter_files(
297
301
  - Relevance check: {stats['timings']["normal_filter"].get('relevance_verification', 0):.2f}s
298
302
  • File selection: {stats['timings'].get('file_selection', 0):.2f}s
299
303
  • Total time: {total_time:.2f}s
300
- ====================================
304
+
301
305
  """
302
- printer.print_str_in_terminal(summary)
306
+ printer.print_panel(
307
+ summary,
308
+ text_options={"justify": "left", "style": "bold white"},
309
+ panel_options={
310
+ "title": "Indexing and Filtering Summary",
311
+ "border_style": "bold blue",
312
+ "padding": (1, 2),
313
+ "expand": False
314
+ }
315
+ )
303
316
 
304
317
  if args.request_id and not args.skip_events:
305
318
  queue_communicate.send_event(
@@ -58,7 +58,7 @@ class QuickFilter():
58
58
  特别注意
59
59
  1. 如果用户的query里 @文件 或者 @@符号,那么被@的文件或者@@的符号必须要返回,并且查看他们依赖的文件是否相关。
60
60
  2. 如果 query 里是一段历史对话,那么对话里的内容提及的文件路径必须要返回。
61
- 3. json格式数据不允许有注释
61
+ 3. json格式数据不允许有注释
62
62
  '''
63
63
  file_meta_str = "\n".join([f"##[{index}]{item.module_name}\n{item.symbols}" for index,item in enumerate(file_meta_list)])
64
64
  context = {
autocoder/index/index.py CHANGED
@@ -263,22 +263,21 @@ class IndexManager:
263
263
  else:
264
264
  index_data = {}
265
265
 
266
- @byzerllm.prompt()
267
- def error_message(source_dir: str, file_path: str):
268
- """
269
- The source_dir is different from the path in index file (e.g. file_path:{{ file_path }} source_dir:{{ source_dir }}).
270
- You may need to replace the prefix with the source_dir in the index file or Just delete the index file to rebuild it.
271
- """
272
-
273
- for item in index_data.keys():
274
- if not item.startswith(self.source_dir):
266
+ # 清理已不存在的文件索引
267
+ keys_to_remove = []
268
+ for file_path in index_data:
269
+ if not os.path.exists(file_path):
270
+ keys_to_remove.append(file_path)
271
+
272
+ # 删除无效条目并记录日志
273
+ for key in set(keys_to_remove):
274
+ if key in index_data:
275
+ del index_data[key]
275
276
  self.printer.print_in_terminal(
276
- "index_source_dir_mismatch",
277
+ "index_file_removed",
277
278
  style="yellow",
278
- source_dir=self.source_dir,
279
- file_path=item
279
+ file_path=key
280
280
  )
281
- break
282
281
 
283
282
  updated_sources = []
284
283
 
@@ -336,9 +335,16 @@ class IndexManager:
336
335
  index_data[module_name] = result
337
336
  updated_sources.append(module_name)
338
337
 
339
- if updated_sources:
338
+ # 如果 updated_sources 或 keys_to_remove 有值,则保存索引文件
339
+ if updated_sources or keys_to_remove:
340
340
  with open(self.index_file, "w") as file:
341
341
  json.dump(index_data, file, ensure_ascii=False, indent=2)
342
+ self.printer.print_in_terminal(
343
+ "index_file_saved",
344
+ style="green",
345
+ updated_files=len(updated_sources),
346
+ removed_files=len(keys_to_remove)
347
+ )
342
348
 
343
349
  return index_data
344
350
 
File without changes
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.235"
1
+ __version__ = "0.1.238"