auto-coder 0.1.264__py3-none-any.whl → 0.1.266__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.

Files changed (53) hide show
  1. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/METADATA +2 -2
  2. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/RECORD +53 -51
  3. autocoder/agent/planner.py +4 -4
  4. autocoder/auto_coder.py +26 -21
  5. autocoder/auto_coder_server.py +7 -7
  6. autocoder/chat_auto_coder.py +150 -49
  7. autocoder/commands/auto_command.py +83 -5
  8. autocoder/commands/tools.py +48 -50
  9. autocoder/common/__init__.py +0 -1
  10. autocoder/common/auto_coder_lang.py +43 -3
  11. autocoder/common/code_auto_generate.py +3 -3
  12. autocoder/common/code_auto_generate_diff.py +3 -6
  13. autocoder/common/code_auto_generate_editblock.py +3 -3
  14. autocoder/common/code_auto_generate_strict_diff.py +3 -3
  15. autocoder/common/code_auto_merge_diff.py +37 -3
  16. autocoder/common/code_auto_merge_editblock.py +43 -1
  17. autocoder/common/code_auto_merge_strict_diff.py +39 -4
  18. autocoder/common/command_completer.py +3 -0
  19. autocoder/common/command_generator.py +24 -8
  20. autocoder/common/command_templates.py +2 -2
  21. autocoder/common/conf_import_export.py +105 -0
  22. autocoder/common/conf_validator.py +1 -1
  23. autocoder/common/files.py +41 -2
  24. autocoder/common/image_to_page.py +11 -11
  25. autocoder/common/index_import_export.py +38 -18
  26. autocoder/common/mcp_hub.py +3 -3
  27. autocoder/common/mcp_server.py +2 -2
  28. autocoder/common/shells.py +254 -13
  29. autocoder/common/stats_panel.py +126 -0
  30. autocoder/dispacher/actions/action.py +6 -18
  31. autocoder/dispacher/actions/copilot.py +2 -2
  32. autocoder/dispacher/actions/plugins/action_regex_project.py +1 -3
  33. autocoder/dispacher/actions/plugins/action_translate.py +1 -1
  34. autocoder/index/entry.py +2 -2
  35. autocoder/index/filter/normal_filter.py +1 -1
  36. autocoder/index/filter/quick_filter.py +1 -1
  37. autocoder/index/index.py +5 -5
  38. autocoder/models.py +2 -2
  39. autocoder/pyproject/__init__.py +5 -5
  40. autocoder/rag/cache/byzer_storage_cache.py +4 -4
  41. autocoder/rag/cache/file_monitor_cache.py +2 -2
  42. autocoder/rag/cache/simple_cache.py +4 -4
  43. autocoder/rag/long_context_rag.py +2 -2
  44. autocoder/regexproject/__init__.py +3 -2
  45. autocoder/suffixproject/__init__.py +3 -2
  46. autocoder/tsproject/__init__.py +3 -2
  47. autocoder/utils/conversation_store.py +1 -1
  48. autocoder/utils/operate_config_api.py +3 -3
  49. autocoder/version.py +1 -1
  50. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/LICENSE +0 -0
  51. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/WHEEL +0 -0
  52. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/entry_points.txt +0 -0
  53. {auto_coder-0.1.264.dist-info → auto_coder-0.1.266.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,105 @@
1
+ import os
2
+ import json
3
+ import shutil
4
+ from loguru import logger
5
+ from autocoder.common.printer import Printer
6
+ from autocoder.common.result_manager import ResultManager
7
+
8
+ result_manager = ResultManager()
9
+
10
+ def export_conf(project_root: str, export_path: str) -> bool:
11
+ printer = Printer()
12
+ """
13
+ Export conf from memory.json to a specified directory
14
+
15
+ Args:
16
+ project_root: Project root directory
17
+ export_path: Path to export the conf file
18
+
19
+ Returns:
20
+ bool: True if successful, False otherwise
21
+ """
22
+ project_root = os.path.abspath(project_root) or os.getcwd()
23
+ try:
24
+ memory_path = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder", "memory.json")
25
+ if not os.path.exists(memory_path):
26
+ printer.print_in_terminal("conf_not_found", path=memory_path)
27
+ return False
28
+
29
+ # Read and extract conf
30
+ with open(memory_path, "r",encoding="utf-8") as f:
31
+ memory_data = json.load(f)
32
+
33
+ conf_data = memory_data.get("conf", {})
34
+
35
+ # Write to export location
36
+ export_file = os.path.join(export_path, "conf.json")
37
+ os.makedirs(export_path, exist_ok=True)
38
+ with open(export_file, "w",encoding="utf-8") as f:
39
+ json.dump(conf_data, f, indent=2)
40
+ printer.print_in_terminal("conf_export_success", path=export_file)
41
+ result_manager.add_result(content=printer.get_message_from_key_with_format("conf_export_success", path=export_file), meta={"action": "conf_export", "input": {
42
+ "path": export_file
43
+ }})
44
+ return True
45
+
46
+ except Exception as e:
47
+ result_manager.add_result(content=printer.get_message_from_key_with_format("conf_export_error", error=str(e)), meta={"action": "conf_export", "input": {
48
+ "path": export_file
49
+ }})
50
+ printer.print_in_terminal("conf_export_error", error=str(e))
51
+ return False
52
+
53
+
54
+ def import_conf(project_root: str, import_path: str) -> bool:
55
+ project_root = os.path.abspath(project_root) or os.getcwd()
56
+ printer = Printer()
57
+ """
58
+ Import conf from a specified directory into memory.json
59
+
60
+ Args:
61
+ project_root: Project root directory
62
+ import_path: Path containing the conf file to import
63
+
64
+ Returns:
65
+ bool: True if successful, False otherwise
66
+ """
67
+ try:
68
+ import_file = os.path.join(import_path, "conf.json")
69
+ if not os.path.exists(import_file):
70
+ printer.print_in_terminal("conf_not_found", path=import_file)
71
+ return False
72
+
73
+ # Read conf file
74
+ with open(import_file, "r",encoding="utf-8") as f:
75
+ conf_data = json.load(f)
76
+
77
+ # Backup existing memory
78
+ memory_path = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder", "memory.json")
79
+ if os.path.exists(memory_path):
80
+ backup_path = memory_path + ".bak"
81
+ shutil.copy2(memory_path, backup_path)
82
+ printer.print_in_terminal("conf_backup_success", path=backup_path)
83
+
84
+ # Update conf in memory
85
+ with open(memory_path, "r",encoding="utf-8") as f:
86
+ memory_data = json.load(f)
87
+
88
+ memory_data["conf"] = conf_data
89
+
90
+ # Write updated memory
91
+ with open(memory_path, "w",encoding="utf-8") as f:
92
+ json.dump(memory_data, f, indent=2)
93
+
94
+ printer.print_in_terminal("conf_import_success", path=memory_path)
95
+ result_manager.add_result(content=printer.get_message_from_key_with_format("conf_import_success", path=memory_path), meta={"action": "conf_import", "input": {
96
+ "path": memory_path
97
+ }})
98
+ return True
99
+
100
+ except Exception as e:
101
+ result_manager.add_result(content=printer.get_message_from_key_with_format("conf_import_error", error=str(e)), meta={"action": "conf_import", "input": {
102
+ "path": memory_path
103
+ }})
104
+ printer.print_in_terminal("conf_import_error", error=str(e))
105
+ return False
@@ -142,7 +142,7 @@ class ConfigValidator:
142
142
  }
143
143
 
144
144
  @classmethod
145
- def validate(cls, key: str, value: Any, product_mode: str) -> Any:
145
+ def validate(cls, key: str, value: Any, product_mode: str) -> Any:
146
146
  # 获取配置规范
147
147
  spec = cls.CONFIG_SPEC.get(key)
148
148
  if not spec:
autocoder/common/files.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from autocoder.common.auto_coder_lang import get_message_with_format
2
- from typing import List, Dict, Union
2
+ from typing import List, Dict, Union, Generator, Tuple
3
3
 
4
4
  def read_file(file_path):
5
5
  """Read a file with automatic encoding detection.
@@ -30,6 +30,45 @@ def read_file(file_path):
30
30
  file_path=file_path,
31
31
  encodings=", ".join(encodings)))
32
32
 
33
+ def read_lines(file_path:str):
34
+ encodings = ['utf-8', 'gbk', 'utf-16', 'latin-1']
35
+ for encoding in encodings:
36
+ try:
37
+ with open(file_path, 'r', encoding=encoding) as f:
38
+ return f.readlines()
39
+ except UnicodeDecodeError:
40
+ continue
41
+ raise ValueError(get_message_with_format("file_decode_error",
42
+ file_path=file_path,
43
+ encodings=", ".join(encodings)))
44
+
45
+
46
+
47
+ def read_file_with_line_numbers(file_path: str,line_number_start:int=0) -> Generator[Tuple[int, str], None, None]:
48
+ """Read a file and return its content with line numbers.
49
+
50
+ Args:
51
+ file_path (str): Path to the file to read
52
+
53
+ Returns:
54
+ List[str]: A list of strings where each string is in the format "line_number:line_content"
55
+
56
+ Raises:
57
+ ValueError: If the file cannot be decoded with any of the tried encodings
58
+ """
59
+ encodings = ['utf-8', 'gbk', 'utf-16', 'latin-1']
60
+
61
+ for encoding in encodings:
62
+ try:
63
+ with open(file_path, 'r', encoding=encoding) as file:
64
+ for line_number, line in enumerate(file, start=line_number_start):
65
+ yield (line_number, line)
66
+ except UnicodeDecodeError:
67
+ continue
68
+
69
+ raise ValueError(get_message_with_format("file_decode_error",
70
+ file_path=file_path,
71
+ encodings=", ".join(encodings)))
33
72
 
34
73
 
35
74
  def save_file(file_path: str, content: Union[str, List[str]]) -> None:
@@ -55,4 +94,4 @@ def save_file(file_path: str, content: Union[str, List[str]]) -> None:
55
94
  except IOError as e:
56
95
  raise IOError(get_message_with_format("file_write_error",
57
96
  file_path=file_path,
58
- error=str(e)))
97
+ error=str(e)))
@@ -122,7 +122,7 @@ class ImageToPageDirectly:
122
122
 
123
123
  counter = 1
124
124
  target_html_path = os.path.join(html_dir,f"{html_file_name}-{counter}.html")
125
- with open(target_html_path, "w") as f:
125
+ with open(target_html_path, "w",encoding="utf-8") as f:
126
126
  f.write(html)
127
127
 
128
128
  while counter < max_iter:
@@ -137,11 +137,11 @@ class ImageToPageDirectly:
137
137
 
138
138
  target_html_path = os.path.join(html_dir,f"{html_file_name}-{counter}.html")
139
139
  logger.info(f"generate html: {target_html_path}")
140
- with open(target_html_path, "w") as f:
140
+ with open(target_html_path, "w",encoding="utf-8") as f:
141
141
  f.write(html)
142
142
 
143
143
  logger.info(f"finally generate html: {html_path}")
144
- with open(html_path, "w") as f:
144
+ with open(html_path, "w",encoding="utf-8") as f:
145
145
  f.write(html)
146
146
 
147
147
 
@@ -248,7 +248,7 @@ class ImageToPage:
248
248
  file_path = block.path
249
249
  os.makedirs(os.path.dirname(file_path), exist_ok=True)
250
250
 
251
- with open(file_path, "w") as f:
251
+ with open(file_path, "w",encoding="utf-8") as f:
252
252
  logger.info(f"Upsert path: {file_path}")
253
253
  f.write(block.content)
254
254
  file_modified_num += 1
@@ -268,7 +268,7 @@ class ImageToPage:
268
268
  ## generate html by image description
269
269
  content_contains_html_prompt = self.generate_html.prompt(desc,html_path)
270
270
 
271
- with open(self.args.target_file, "w") as f:
271
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
272
272
  f.write(content_contains_html_prompt)
273
273
 
274
274
  t = self.llm.chat_oai(conversations=[{
@@ -278,7 +278,7 @@ class ImageToPage:
278
278
 
279
279
  content_contains_html = t[0].output
280
280
 
281
- with open(self.args.target_file, "w") as f:
281
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
282
282
  f.write(content_contains_html)
283
283
 
284
284
 
@@ -296,7 +296,7 @@ class ImageToPage:
296
296
 
297
297
  for i in range(max_iter):
298
298
  logger.info(f"iterate {i}")
299
- with open(html_path,"r") as f:
299
+ with open(html_path,"r",encoding="utf-8") as f:
300
300
  prev_html = f.read()
301
301
 
302
302
  gen_screenshots(url=html_path,image_dir=new_image_dir)
@@ -309,7 +309,7 @@ class ImageToPage:
309
309
  ## get new description prompt by comparing old and new image
310
310
  new_desc_prompt = self.get_optimize(self.score(origin_image,new_image))
311
311
 
312
- with open(self.args.target_file, "w") as f:
312
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
313
313
  f.write(new_desc_prompt)
314
314
 
315
315
  t = self.llm.chat_oai(conversations=[{
@@ -319,7 +319,7 @@ class ImageToPage:
319
319
 
320
320
  new_desc = t[0].output
321
321
 
322
- with open(self.args.target_file, "w") as f:
322
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
323
323
  f.write(new_desc)
324
324
 
325
325
  logger.info(f"score old/new image: {new_desc}")
@@ -327,7 +327,7 @@ class ImageToPage:
327
327
  ## generate new html by new description
328
328
  optimze_html_prompt = self.optimize_html.prompt(desc=new_desc,html=prev_html,html_path=html_path)
329
329
 
330
- with open(self.args.target_file, "w") as f:
330
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
331
331
  f.write(optimze_html_prompt)
332
332
 
333
333
  t = self.llm.chat_oai(conversations=[{
@@ -336,7 +336,7 @@ class ImageToPage:
336
336
  }],llm_config={**extra_llm_config})
337
337
  new_code = t[0].output
338
338
 
339
- with open(self.args.target_file, "w") as f:
339
+ with open(self.args.target_file, "w",encoding="utf-8") as f:
340
340
  f.write(new_code)
341
341
 
342
342
  self.write_code(new_code,html_path)
@@ -3,6 +3,9 @@ import json
3
3
  import shutil
4
4
  from loguru import logger
5
5
  from autocoder.common.printer import Printer
6
+ from autocoder.common.result_manager import ResultManager
7
+
8
+ result_manager = ResultManager()
6
9
 
7
10
 
8
11
  def export_index(project_root: str, export_path: str) -> bool:
@@ -22,11 +25,11 @@ def export_index(project_root: str, export_path: str) -> bool:
22
25
  if not os.path.exists(index_path):
23
26
  printer.print_in_terminal("index_not_found", path=index_path)
24
27
  return False
25
-
28
+
26
29
  # Read and convert paths
27
- with open(index_path, "r") as f:
30
+ with open(index_path, "r",encoding="utf-8") as f:
28
31
  index_data = json.load(f)
29
-
32
+
30
33
  # Convert absolute paths to relative
31
34
  converted_data = {}
32
35
  for abs_path, data in index_data.items():
@@ -35,21 +38,29 @@ def export_index(project_root: str, export_path: str) -> bool:
35
38
  data["module_name"] = rel_path
36
39
  converted_data[rel_path] = data
37
40
  except ValueError:
38
- printer.print_in_terminal("index_convert_path_fail", path=abs_path)
41
+ printer.print_in_terminal(
42
+ "index_convert_path_fail", path=abs_path)
39
43
  converted_data[abs_path] = data
40
-
44
+
41
45
  # Write to export location
42
46
  export_file = os.path.join(export_path, "index.json")
43
47
  os.makedirs(export_path, exist_ok=True)
44
- with open(export_file, "w") as f:
48
+ with open(export_file, "w",encoding="utf-8") as f:
45
49
  json.dump(converted_data, f, indent=2)
46
-
50
+ printer.print_in_terminal("index_export_success", path=export_file)
51
+ result_manager.add_result(content=printer.get_message_from_key_with_format("index_export_success", path=export_file), meta={"action": "index_export", "input": {
52
+ "path": export_file
53
+ }})
47
54
  return True
48
-
55
+
49
56
  except Exception as e:
50
57
  printer.print_in_terminal("index_error", error=str(e))
58
+ result_manager.add_result(content=printer.get_message_from_key_with_format("index_error", error=str(e)), meta={"action": "index_export", "input": {
59
+ "path": export_file
60
+ }})
51
61
  return False
52
62
 
63
+
53
64
  def import_index(project_root: str, import_path: str) -> bool:
54
65
  printer = Printer()
55
66
  """
@@ -67,11 +78,11 @@ def import_index(project_root: str, import_path: str) -> bool:
67
78
  if not os.path.exists(import_file):
68
79
  printer.print_in_terminal("index_not_found", path=import_file)
69
80
  return False
70
-
81
+
71
82
  # Read and convert paths
72
- with open(import_file, "r") as f:
83
+ with open(import_file, "r",encoding="utf-8") as f:
73
84
  index_data = json.load(f)
74
-
85
+
75
86
  # Convert relative paths to absolute
76
87
  converted_data = {}
77
88
  for rel_path, data in index_data.items():
@@ -80,22 +91,31 @@ def import_index(project_root: str, import_path: str) -> bool:
80
91
  data["module_name"] = abs_path
81
92
  converted_data[abs_path] = data
82
93
  except Exception:
83
- printer.print_in_terminal("index_convert_path_fail", path=rel_path)
94
+ printer.print_in_terminal(
95
+ "index_convert_path_fail", path=rel_path)
84
96
  converted_data[rel_path] = data
85
-
97
+
86
98
  # Backup existing index
87
99
  index_path = os.path.join(project_root, ".auto-coder", "index.json")
88
100
  if os.path.exists(index_path):
89
101
  backup_path = index_path + ".bak"
90
102
  shutil.copy2(index_path, backup_path)
91
103
  printer.print_in_terminal("index_backup_success", path=backup_path)
92
-
104
+
93
105
  # Write new index
94
- with open(index_path, "w") as f:
106
+ with open(index_path, "w",encoding="utf-8") as f:
95
107
  json.dump(converted_data, f, indent=2)
96
-
97
- return True
98
108
 
109
+ printer.print_in_terminal("index_import_success", path=index_path)
110
+ result_manager.add_result(content=printer.get_message_from_key_with_format("index_import_success", path=index_path), meta={"action": "index_import", "input": {
111
+ "path": index_path
112
+ }})
113
+
114
+ return True
115
+
99
116
  except Exception as e:
100
117
  printer.print_in_terminal("index_error", error=str(e))
101
- return False
118
+ result_manager.add_result(content=printer.get_message_from_key_with_format("index_error", error=str(e)), meta={"action": "index_import", "input": {
119
+ "path": index_path
120
+ }})
121
+ return False
@@ -116,7 +116,7 @@ class McpHub:
116
116
  def _write_default_settings(self):
117
117
  """Write default MCP settings file"""
118
118
  default_settings = {"mcpServers": {}}
119
- with open(self.settings_path, "w") as f:
119
+ with open(self.settings_path, "w",encoding="utf-8") as f:
120
120
  json.dump(default_settings, f, indent=2)
121
121
 
122
122
  async def add_server_config(self, name: str, config:Dict[str,Any]) -> None:
@@ -129,7 +129,7 @@ class McpHub:
129
129
  try:
130
130
  settings = self._read_settings()
131
131
  settings["mcpServers"][name] = config
132
- with open(self.settings_path, "w") as f:
132
+ with open(self.settings_path, "w",encoding="utf-8") as f:
133
133
  json.dump(settings, f, indent=2, ensure_ascii=False)
134
134
  await self.initialize()
135
135
  logger.info(f"Added/updated MCP server config: {name}")
@@ -148,7 +148,7 @@ class McpHub:
148
148
  settings = self._read_settings()
149
149
  if name in settings["mcpServers"]:
150
150
  del settings["mcpServers"][name]
151
- with open(self.settings_path, "w") as f:
151
+ with open(self.settings_path, "w",encoding="utf-8") as f:
152
152
  json.dump(settings, f, indent=2, ensure_ascii=False)
153
153
  logger.info(f"Removed MCP server config: {name}")
154
154
  await self.initialize()
@@ -80,7 +80,7 @@ def get_mcp_external_servers() -> List[McpExternalServer]:
80
80
  if os.path.exists(cache_file):
81
81
  cache_time = os.path.getmtime(cache_file)
82
82
  if time.time() - cache_time < 3600: # 1 hour cache
83
- with open(cache_file, "r") as f:
83
+ with open(cache_file, "r",encoding="utf-8") as f:
84
84
  raw_data = json.load(f)
85
85
  return [McpExternalServer(**item) for item in raw_data]
86
86
 
@@ -91,7 +91,7 @@ def get_mcp_external_servers() -> List[McpExternalServer]:
91
91
  response = requests.get(url)
92
92
  if response.status_code == 200:
93
93
  raw_data = response.json()
94
- with open(cache_file, "w") as f:
94
+ with open(cache_file, "w",encoding="utf-8") as f:
95
95
  json.dump(raw_data, f)
96
96
  return [McpExternalServer(**item) for item in raw_data]
97
97
  return []