autocoder-nano 0.1.36__py3-none-any.whl → 0.1.38__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.
@@ -11,13 +11,13 @@ import uuid
11
11
  from autocoder_nano.agent.agentic_edit import AgenticEdit
12
12
  from autocoder_nano.agent.agentic_edit_types import AgenticEditRequest
13
13
  from autocoder_nano.chat import stream_chat_display
14
- from autocoder_nano.edit import Dispacher
14
+ from autocoder_nano.edit import coding
15
15
  from autocoder_nano.helper import show_help
16
- from autocoder_nano.index.entry import build_index_and_filter_files
17
- from autocoder_nano.index.index_manager import IndexManager
18
- from autocoder_nano.index.symbols_utils import extract_symbols
16
+ from autocoder_nano.project import project_source
17
+ from autocoder_nano.index import (index_export, index_import, index_build,
18
+ index_build_and_filter, extract_symbols)
19
+ from autocoder_nano.rules import rules_from_active_files, rules_from_commit_changes, get_rules_context
19
20
  from autocoder_nano.llm_client import AutoLLM
20
- from autocoder_nano.rules.rules_learn import AutoRulesLearn
21
21
  from autocoder_nano.utils.completer_utils import CommandCompleter
22
22
  from autocoder_nano.version import __version__
23
23
  from autocoder_nano.llm_types import *
@@ -26,7 +26,6 @@ from autocoder_nano.templates import create_actions
26
26
  from autocoder_nano.git_utils import (repo_init, commit_changes, revert_changes,
27
27
  get_uncommitted_changes, generate_commit_message)
28
28
  from autocoder_nano.sys_utils import default_exclude_dirs, detect_env
29
- from autocoder_nano.project import PyProject, SuffixProject
30
29
  from autocoder_nano.utils.printer_utils import Printer
31
30
 
32
31
  import yaml
@@ -49,11 +48,12 @@ from rich.text import Text
49
48
 
50
49
  printer = Printer()
51
50
  console = printer.get_console()
52
- # console = Console()
51
+
52
+
53
53
  project_root = os.getcwd()
54
54
  base_persist_dir = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder")
55
- # defaut_exclude_dirs = [".git", ".svn", "node_modules", "dist", "build", "__pycache__", ".auto-coder", "actions",
56
- # ".vscode", ".idea", ".hg"]
55
+
56
+
57
57
  commands = [
58
58
  "/add_files", "/remove_files", "/list_files", "/conf", "/coding", "/chat", "/revert", "/index/query",
59
59
  "/index/build", "/exclude_dirs", "/exclude_files", "/help", "/shell", "/exit", "/mode", "/models", "/commit",
@@ -65,8 +65,6 @@ memory = {
65
65
  "current_files": {"files": [], "groups": {}},
66
66
  "conf": {
67
67
  "auto_merge": "editblock",
68
- # "current_chat_model": "",
69
- # "current_code_model": "",
70
68
  "chat_model": "",
71
69
  "code_model": "",
72
70
  },
@@ -317,119 +315,13 @@ def exclude_files(query: str):
317
315
 
318
316
  def index_command(llm):
319
317
  args = get_final_config(query="", delete_execute_file=True)
320
-
321
- source_dir = os.path.abspath(args.source_dir)
322
- printer.print_text(f"开始对目录 {source_dir} 中的源代码进行索引", style="green")
323
- if args.project_type == "py":
324
- pp = PyProject(llm=llm, args=args)
325
- else:
326
- pp = SuffixProject(llm=llm, args=args)
327
- pp.run()
328
- _sources = pp.sources
329
- index_manager = IndexManager(args=args, source_codes=_sources, llm=llm)
330
- index_manager.build_index()
331
-
332
-
333
- def index_export(export_path: str) -> bool:
334
- try:
335
- index_path = os.path.join(project_root, ".auto-coder", "index.json")
336
- if not os.path.exists(index_path):
337
- printer.print_text(Text(f"索引文件不存在. ", style="bold red"))
338
- return False
339
-
340
- with open(index_path, "r", encoding="utf-8") as f:
341
- index_data = json.load(f)
342
-
343
- converted_data = {}
344
- for abs_path, data in index_data.items():
345
- try:
346
- rel_path = os.path.relpath(abs_path, project_root)
347
- data["module_name"] = rel_path
348
- converted_data[rel_path] = data
349
- except ValueError:
350
- printer.print_text(Text(f"索引转换路径失败. ", style="dim yellow"))
351
- converted_data[abs_path] = data
352
-
353
- export_file = os.path.join(export_path, "index.json")
354
- with open(export_file, "w", encoding="utf-8") as f:
355
- json.dump(converted_data, f, indent=2)
356
- printer.print_text(Text(f"索引文件导出成功. ", style="bold green"))
357
- return True
358
- except Exception as err:
359
- printer.print_text(Text(f"索引文件导出失败: {err}", style="bold red"))
360
- return False
361
-
362
-
363
- def index_import(import_path: str):
364
- try:
365
- import_file = os.path.join(import_path, "index.json")
366
- if not os.path.exists(import_file):
367
- printer.print_text(Text(f"导入索引文件不存在", style="bold red"))
368
- return False
369
- with open(import_file, "r", encoding="utf-8") as f:
370
- index_data = json.load(f)
371
- converted_data = {}
372
- for rel_path, data in index_data.items():
373
- try:
374
- abs_path = os.path.join(project_root, rel_path)
375
- data["module_name"] = abs_path
376
- converted_data[abs_path] = data
377
- except Exception as err:
378
- printer.print_text(Text(f"{rel_path} 索引转换路径失败: {err}", style="dim yellow"))
379
- converted_data[rel_path] = data
380
- # Backup existing index
381
- index_path = os.path.join(project_root, ".auto-coder", "index.json")
382
- if os.path.exists(index_path):
383
- printer.print_text(Text(f"原索引文件不存在", style="bold yellow"))
384
- backup_path = index_path + ".bak"
385
- shutil.copy2(index_path, backup_path)
386
-
387
- # Write new index
388
- with open(index_path, "w", encoding="utf-8") as f:
389
- json.dump(converted_data, f, indent=2)
390
- return True
391
- except Exception as err:
392
- printer.print_text(Text(f"索引文件导入失败: {err}", style="bold red"))
393
- return False
318
+ index_build(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
319
+ return
394
320
 
395
321
 
396
322
  def index_query_command(query: str, llm: AutoLLM):
397
323
  args = get_final_config(query=query, delete_execute_file=True)
398
-
399
- # args.query = query
400
- if args.project_type == "py":
401
- pp = PyProject(llm=llm, args=args)
402
- else:
403
- pp = SuffixProject(llm=llm, args=args)
404
- pp.run()
405
- _sources = pp.sources
406
-
407
- final_files = []
408
- index_manager = IndexManager(args=args, source_codes=_sources, llm=llm)
409
- target_files = index_manager.get_target_files_by_query(query)
410
-
411
- if target_files:
412
- final_files.extend(target_files.file_list)
413
-
414
- if target_files and args.index_filter_level >= 2:
415
-
416
- related_fiels = index_manager.get_related_files([file.file_path for file in target_files.file_list])
417
-
418
- if related_fiels is not None:
419
- final_files.extend(related_fiels.file_list)
420
-
421
- all_results = list({file.file_path: file for file in final_files}.values())
422
- printer.print_key_value(
423
- {"索引过滤级别": f"{args.index_filter_level}", "查询条件": f"{args.query}", "过滤后的文件数": f"{len(all_results)}"},
424
- panel=True
425
- )
426
-
427
- printer.print_table_compact(
428
- headers=["文件路径", "原因"],
429
- data=[[_target_file.file_path, _target_file.reason] for _target_file in all_results],
430
- title="Index Query 结果",
431
- show_lines=True,
432
- )
324
+ index_build_and_filter(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
433
325
  return
434
326
 
435
327
 
@@ -539,10 +431,8 @@ def chat(query: str, llm: AutoLLM):
539
431
  old_chat_history = json.load(f)
540
432
  if "conversation_history" not in old_chat_history:
541
433
  old_chat_history["conversation_history"] = []
542
- old_chat_history["conversation_history"].append(
543
- old_chat_history.get("ask_conversation", []))
544
- chat_history = {"ask_conversation": [
545
- ], "conversation_history": old_chat_history["conversation_history"]}
434
+ old_chat_history["conversation_history"].append(old_chat_history.get("ask_conversation", []))
435
+ chat_history = {"ask_conversation": [], "conversation_history": old_chat_history["conversation_history"]}
546
436
  else:
547
437
  chat_history = {"ask_conversation": [],
548
438
  "conversation_history": []}
@@ -569,8 +459,6 @@ def chat(query: str, llm: AutoLLM):
569
459
 
570
460
  if is_history:
571
461
  show_chat = []
572
- # if "conversation_history" in chat_history:
573
- # show_chat.extend(chat_history["conversation_history"])
574
462
  if "ask_conversation" in chat_history:
575
463
  show_chat.extend(chat_history["ask_conversation"])
576
464
  print_chat_history(show_chat)
@@ -583,13 +471,15 @@ def chat(query: str, llm: AutoLLM):
583
471
  chat_llm = llm
584
472
  pre_conversations = []
585
473
 
586
- if args.project_type == "py":
587
- pp = PyProject(llm=llm, args=args)
588
- else:
589
- pp = SuffixProject(llm=llm, args=args)
590
- pp.run()
591
- _sources = pp.sources
592
- s = build_index_and_filter_files(args=args, llm=llm, sources=_sources)
474
+ # if args.project_type == "py":
475
+ # pp = PyProject(llm=llm, args=args)
476
+ # else:
477
+ # pp = SuffixProject(llm=llm, args=args)
478
+ # pp.run()
479
+ # _sources = pp.sources
480
+ # _sources = project_source(source_llm=llm, args=args)
481
+ # s = build_index_and_filter_files(args=args, llm=llm, sources=_sources)
482
+ s = index_build_and_filter(llm=llm, args=args, sources_codes=project_source(source_llm=llm, args=args))
593
483
  if s:
594
484
  pre_conversations.append(
595
485
  {
@@ -606,51 +496,6 @@ def chat(query: str, llm: AutoLLM):
606
496
 
607
497
  assistant_response = stream_chat_display(chat_llm=llm, args=args, conversations=loaded_conversations)
608
498
 
609
- # v = chat_llm.stream_chat_ai(conversations=loaded_conversations, model=args.chat_model)
610
- #
611
- # MAX_HISTORY_LINES = 15 # 最大保留历史行数
612
- # lines_buffer = []
613
- # current_line = ""
614
- # assistant_response = ""
615
- #
616
- # try:
617
- # with Live(Panel("", title="Response", style="cyan"), refresh_per_second=12) as live:
618
- # for chunk in v:
619
- # if chunk.choices and chunk.choices[0].delta.content:
620
- # content = chunk.choices[0].delta.content
621
- # assistant_response += content
622
- #
623
- # # 处理换行符分割
624
- # parts = (current_line + content).split('\n')
625
- #
626
- # # 最后一部分是未完成的新行
627
- # if len(parts) > 1:
628
- # # 将完整行加入缓冲区
629
- # lines_buffer.extend(parts[:-1])
630
- # # 保留最近N行历史
631
- # if len(lines_buffer) > MAX_HISTORY_LINES:
632
- # del lines_buffer[0: len(lines_buffer) - MAX_HISTORY_LINES]
633
- # # 更新当前行(最后未完成的部分)
634
- # current_line = parts[-1]
635
- # # 构建显示内容 = 历史行 + 当前行
636
- # display_content = '\n'.join(lines_buffer[-MAX_HISTORY_LINES:] + [current_line])
637
- #
638
- # live.update(
639
- # Panel(Markdown(display_content), title="模型返回", border_style="cyan",
640
- # height=min(25, live.console.height - 4))
641
- # )
642
- #
643
- # # 处理最后未换行的内容
644
- # if current_line:
645
- # lines_buffer.append(current_line)
646
- #
647
- # # 最终完整渲染
648
- # live.update(
649
- # Panel(Markdown(assistant_response), title="模型返回", border_style="dim blue")
650
- # )
651
- # except Exception as e:
652
- # printer.print_panel(Text(f"{str(e)}", style="red"), title="模型返回", center=True)
653
-
654
499
  chat_history["ask_conversation"].append({"role": "assistant", "content": assistant_response})
655
500
 
656
501
  with open(memory_file, "w") as fp:
@@ -772,14 +617,46 @@ def prepare_chat_yaml():
772
617
  return
773
618
 
774
619
 
775
- def coding(query: str, llm: AutoLLM):
620
+ def get_conversation_history() -> str:
621
+ memory_dir = os.path.join(project_root, ".auto-coder", "memory")
622
+ os.makedirs(memory_dir, exist_ok=True)
623
+ memory_file = os.path.join(memory_dir, "chat_history.json")
624
+
625
+ def error_message():
626
+ printer.print_panel(Text("未找到可应用聊天记录.", style="yellow"), title="Chat History", center=True)
627
+
628
+ if not os.path.exists(memory_file):
629
+ error_message()
630
+ return ""
631
+
632
+ with open(memory_file, "r") as f:
633
+ chat_history = json.load(f)
634
+
635
+ if not chat_history["ask_conversation"]:
636
+ error_message()
637
+ return ""
638
+
639
+ conversations = chat_history["ask_conversation"]
640
+
641
+ context = ""
642
+ context += f"下面是我们的历史对话,参考我们的历史对话从而更好的理解需求和修改代码。\n\n<history>\n"
643
+ for conv in conversations:
644
+ if conv["role"] == "user":
645
+ context += f"用户: {conv['content']}\n"
646
+ elif conv["role"] == "assistant":
647
+ context += f"你: {conv['content']}\n"
648
+ context += "</history>\n"
649
+ return context
650
+
651
+
652
+ def coding_command(query: str, llm: AutoLLM):
776
653
  is_apply = query.strip().startswith("/apply")
777
654
  if is_apply:
778
655
  query = query.replace("/apply", "", 1).strip()
656
+ is_rules = False
779
657
 
780
658
  memory["conversation"].append({"role": "user", "content": query})
781
659
  conf = memory.get("conf", {})
782
- current_files = memory["current_files"]["files"]
783
660
 
784
661
  prepare_chat_yaml() # 复制上一个序号的 yaml 文件, 生成一个新的聊天 yaml 文件
785
662
  latest_yaml_file = get_last_yaml_file(os.path.join(project_root, "actions"))
@@ -800,52 +677,14 @@ def coding(query: str, llm: AutoLLM):
800
677
  if converted_value is not None:
801
678
  yaml_config[key] = converted_value
802
679
 
803
- yaml_config["urls"] = current_files
680
+ yaml_config["urls"] = memory["current_files"]["files"]
804
681
  yaml_config["query"] = query
805
682
 
806
683
  if is_apply:
807
- memory_dir = os.path.join(project_root, ".auto-coder", "memory")
808
- os.makedirs(memory_dir, exist_ok=True)
809
- memory_file = os.path.join(memory_dir, "chat_history.json")
810
-
811
- def error_message():
812
- printer.print_panel(
813
- Text("No chat history found to apply.", style="yellow"), title="Chat History", center=True
814
- )
684
+ yaml_config["context"] += get_conversation_history()
815
685
 
816
- if not os.path.exists(memory_file):
817
- error_message()
818
- return
819
-
820
- with open(memory_file, "r") as f:
821
- chat_history = json.load(f)
822
-
823
- if not chat_history["ask_conversation"]:
824
- error_message()
825
- return
826
- conversations = chat_history["ask_conversation"]
827
-
828
- yaml_config["context"] += f"下面是我们的历史对话,参考我们的历史对话从而更好的理解需求和修改代码。\n\n<history>\n"
829
- for conv in conversations:
830
- if conv["role"] == "user":
831
- yaml_config["context"] += f"用户: {conv['content']}\n"
832
- elif conv["role"] == "assistant":
833
- yaml_config["context"] += f"你: {conv['content']}\n"
834
- yaml_config["context"] += "</history>\n"
835
-
836
- # todo:暂时注释,后续通过一个 is_rules 的参数来控制
837
- # if args.enable_rules:
838
- # rules_dir_path = os.path.join(project_root, ".auto-coder", "autocoderrules")
839
- # printer.print_text("已开启 Rules 模式", style="green")
840
- # yaml_config["context"] += f"下面是我们对代码进行深入分析,提取具有通用价值的功能模式和设计模式,可在其他需求中复用的Rules\n"
841
- # yaml_config["context"] += "你在编写代码时可以参考以下Rules\n"
842
- # yaml_config["context"] += "<rules>\n"
843
- # for rules_name in os.listdir(rules_dir_path):
844
- # printer.print_text(f"正在加载 Rules:{rules_name}", style="green")
845
- # rules_file_path = os.path.join(rules_dir_path, rules_name)
846
- # with open(rules_file_path, "r") as fp:
847
- # yaml_config["context"] += f"{fp.read()}\n"
848
- # yaml_config["context"] += "</rules>\n"
686
+ if is_rules:
687
+ yaml_config["context"] += get_rules_context()
849
688
 
850
689
  yaml_config["file"] = latest_yaml_file
851
690
  yaml_content = convert_yaml_config_to_str(yaml_config=yaml_config)
@@ -854,8 +693,7 @@ def coding(query: str, llm: AutoLLM):
854
693
  f.write(yaml_content)
855
694
  args = convert_yaml_to_config(execute_file)
856
695
 
857
- dispacher = Dispacher(args=args, llm=llm)
858
- dispacher.dispach()
696
+ coding(llm=llm, args=args)
859
697
  else:
860
698
  printer.print_text(f"创建新的 YAML 文件失败.", style="yellow")
861
699
 
@@ -1688,43 +1526,15 @@ def rules(query_args: List[str], llm: AutoLLM):
1688
1526
 
1689
1527
  if query_args[0] == "/commit":
1690
1528
  commit_id = query_args[1].strip()
1691
- auto_learn = AutoRulesLearn(llm=llm, args=args)
1692
-
1693
- try:
1694
- result = auto_learn.analyze_commit_changes(commit_id=commit_id, conversations=[])
1695
- rules_file = os.path.join(rules_dir_path, f"rules-commit-{uuid.uuid4()}.md")
1696
- with open(rules_file, "w", encoding="utf-8") as f:
1697
- f.write(result)
1698
- printer.print_text(f"代码变更[{commit_id}]生成 Rules 成功", style="green")
1699
- except Exception as e:
1700
- printer.print_text(f"代码变更[{commit_id}]生成 Rules 失败: {e}", style="red")
1529
+ rules_from_commit_changes(commit_id=commit_id, llm=llm, args=args)
1701
1530
 
1702
1531
  if query_args[0] == "/analyze":
1703
- auto_learn = AutoRulesLearn(llm=llm, args=args)
1704
-
1705
1532
  files = memory.get("current_files", {}).get("files", [])
1706
1533
  if not files:
1707
1534
  printer.print_text("当前无活跃文件用于生成 Rules", style="yellow")
1708
1535
  return
1709
1536
 
1710
- sources = SourceCodeList([])
1711
- for file in files:
1712
- try:
1713
- with open(file, "r", encoding="utf-8") as f:
1714
- source_code = f.read()
1715
- sources.sources.append(SourceCode(module_name=file, source_code=source_code))
1716
- except Exception as e:
1717
- printer.print_text(f"读取文件生成 Rules 失败: {e}", style="yellow")
1718
- continue
1719
-
1720
- try:
1721
- result = auto_learn.analyze_modules(sources=sources, conversations=[])
1722
- rules_file = os.path.join(rules_dir_path, f"rules-modules-{uuid.uuid4()}.md")
1723
- with open(rules_file, "w", encoding="utf-8") as f:
1724
- f.write(result)
1725
- printer.print_text(f"活跃文件[Files:{len(files)}]生成 Rules 成功", style="green")
1726
- except Exception as e:
1727
- printer.print_text(f"活跃文件生成 Rules 失败: {e}", style="red")
1537
+ rules_from_active_files(files=files, llm=llm, args=args)
1728
1538
 
1729
1539
  completer.refresh_files()
1730
1540
 
@@ -1881,10 +1691,10 @@ def main():
1881
1691
  index_query_command(query=query, llm=auto_llm)
1882
1692
  elif user_input.startswith("/index/export"):
1883
1693
  export_path = user_input[len("/index/export"):].strip()
1884
- index_export(export_path)
1694
+ index_export(project_root, export_path)
1885
1695
  elif user_input.startswith("/index/import"):
1886
1696
  import_path = user_input[len("/index/import"):].strip()
1887
- index_import(import_path)
1697
+ index_import(project_root, import_path)
1888
1698
  elif user_input.startswith("/list_files"):
1889
1699
  list_files()
1890
1700
  elif user_input.startswith("/conf"):
@@ -1915,7 +1725,7 @@ def main():
1915
1725
  if not query:
1916
1726
  printer.print_text("Please enter your request.", style="yellow")
1917
1727
  continue
1918
- coding(query=query, llm=auto_llm)
1728
+ coding_command(query=query, llm=auto_llm)
1919
1729
  elif user_input.startswith("/auto"):
1920
1730
  query = user_input[len("/auto"):].strip()
1921
1731
  if not query:
@@ -17,4 +17,12 @@ class Dispacher:
17
17
  ]
18
18
  for action in dispacher_actions:
19
19
  if action.run():
20
- return
20
+ return
21
+
22
+
23
+ def coding(llm: AutoLLM, args: AutoCoderArgs):
24
+ dispacher = Dispacher(args=args, llm=llm)
25
+ dispacher.dispach()
26
+
27
+
28
+ __all__ = ["coding"]
@@ -1,4 +1,93 @@
1
+ import json
2
+ import os
3
+ import shutil
4
+
1
5
  from autocoder_nano.index.entry import build_index_and_filter_files
6
+ from autocoder_nano.index.index_manager import IndexManager
7
+ from autocoder_nano.index.symbols_utils import extract_symbols
8
+ from autocoder_nano.llm_client import AutoLLM
9
+ from autocoder_nano.llm_types import AutoCoderArgs, SourceCode
10
+ from autocoder_nano.project import project_source
11
+ from autocoder_nano.utils.printer_utils import Printer
12
+
13
+
14
+ printer = Printer()
15
+
16
+
17
+ def index_build(llm: AutoLLM, args: AutoCoderArgs, sources_codes: list[SourceCode] = None):
18
+ if not sources_codes:
19
+ sources_codes = project_source(source_llm=llm, args=args)
20
+ index = IndexManager(args=args, source_codes=sources_codes, llm=llm)
21
+ index.build_index()
22
+
23
+
24
+ def index_build_and_filter(llm: AutoLLM, args: AutoCoderArgs, sources_codes: list[SourceCode] = None) -> str:
25
+ if not sources_codes:
26
+ sources_codes = project_source(source_llm=llm, args=args)
27
+ return build_index_and_filter_files(args=args, llm=llm, sources=sources_codes)
28
+
29
+
30
+ def index_export(project_root: str, export_path: str) -> bool:
31
+ try:
32
+ index_path = os.path.join(project_root, ".auto-coder", "index.json")
33
+ if not os.path.exists(index_path):
34
+ printer.print_text(f"索引文件不存在. ", style="red")
35
+ return False
36
+
37
+ with open(index_path, "r", encoding="utf-8") as f:
38
+ index_data = json.load(f)
39
+
40
+ converted_data = {}
41
+ for abs_path, data in index_data.items():
42
+ try:
43
+ rel_path = os.path.relpath(abs_path, project_root)
44
+ data["module_name"] = rel_path
45
+ converted_data[rel_path] = data
46
+ except ValueError:
47
+ printer.print_text(f"索引转换路径失败. ", style="yellow")
48
+ converted_data[abs_path] = data
49
+
50
+ export_file = os.path.join(export_path, "index.json")
51
+ with open(export_file, "w", encoding="utf-8") as f:
52
+ json.dump(converted_data, f, indent=2)
53
+ printer.print_text(f"索引文件导出成功.", style="green")
54
+ return True
55
+ except Exception as err:
56
+ printer.print_text(f"索引文件导出失败: {err}", style="red")
57
+ return False
58
+
59
+
60
+ def index_import(project_root: str, import_path: str):
61
+ try:
62
+ import_file = os.path.join(import_path, "index.json")
63
+ if not os.path.exists(import_file):
64
+ printer.print_text(f"导入索引文件不存在. ", style="red")
65
+ return False
66
+ with open(import_file, "r", encoding="utf-8") as f:
67
+ index_data = json.load(f)
68
+ converted_data = {}
69
+ for rel_path, data in index_data.items():
70
+ try:
71
+ abs_path = os.path.join(project_root, rel_path)
72
+ data["module_name"] = abs_path
73
+ converted_data[abs_path] = data
74
+ except Exception as err:
75
+ printer.print_text(f"{rel_path} 索引转换路径失败: {err}", style="yellow")
76
+ converted_data[rel_path] = data
77
+ # Backup existing index
78
+ index_path = os.path.join(project_root, ".auto-coder", "index.json")
79
+ if os.path.exists(index_path):
80
+ printer.print_text(f"原索引文件不存在", style="yellow")
81
+ backup_path = index_path + ".bak"
82
+ shutil.copy2(index_path, backup_path)
83
+
84
+ # Write new index
85
+ with open(index_path, "w", encoding="utf-8") as f:
86
+ json.dump(converted_data, f, indent=2)
87
+ return True
88
+ except Exception as err:
89
+ printer.print_text(f"索引文件导入失败: {err}", style="red")
90
+ return False
2
91
 
3
92
 
4
- __all__ = ["build_index_and_filter_files"]
93
+ __all__ = ["index_build", "index_export", "index_import", "index_build_and_filter", "extract_symbols", "IndexManager"]
@@ -1,5 +1,19 @@
1
+ from autocoder_nano.llm_client import AutoLLM
2
+ from autocoder_nano.llm_types import AutoCoderArgs, SourceCode
1
3
  from autocoder_nano.project.pyproject import PyProject
2
4
  from autocoder_nano.project.suffixproject import SuffixProject
3
5
  from autocoder_nano.project.tsproject import TSProject
4
6
 
5
- __all__ = ["PyProject", "SuffixProject", "TSProject"]
7
+
8
+ def project_source(source_llm: AutoLLM, args: AutoCoderArgs) -> list[SourceCode]:
9
+ if args.project_type == "py":
10
+ pp = PyProject(llm=source_llm, args=args)
11
+ elif args.project_type == "ts":
12
+ pp = TSProject(llm=source_llm, args=args)
13
+ else:
14
+ pp = SuffixProject(llm=source_llm, args=args)
15
+ pp.run()
16
+ return pp.sources
17
+
18
+
19
+ __all__ = ["PyProject", "SuffixProject", "TSProject", "project_source"]
@@ -0,0 +1,67 @@
1
+ import os
2
+ import uuid
3
+
4
+ from autocoder_nano.llm_client import AutoLLM
5
+ from autocoder_nano.llm_types import AutoCoderArgs, SourceCodeList, SourceCode
6
+ from autocoder_nano.rules.rules_learn import AutoRulesLearn
7
+ from autocoder_nano.utils.printer_utils import Printer
8
+
9
+
10
+ printer = Printer()
11
+
12
+
13
+ def rules_from_commit_changes(commit_id: str, llm: AutoLLM, args: AutoCoderArgs):
14
+ rules_dir_path = os.path.join(args.source_dir, ".auto-coder", "autocoderrules")
15
+ auto_learn = AutoRulesLearn(llm=llm, args=args)
16
+
17
+ try:
18
+ result = auto_learn.analyze_commit_changes(commit_id=commit_id, conversations=[])
19
+ rules_file = os.path.join(rules_dir_path, f"rules-commit-{uuid.uuid4()}.md")
20
+ with open(rules_file, "w", encoding="utf-8") as f:
21
+ f.write(result)
22
+ printer.print_text(f"代码变更[{commit_id}]生成 Rules 成功", style="green")
23
+ except Exception as e:
24
+ printer.print_text(f"代码变更[{commit_id}]生成 Rules 失败: {e}", style="red")
25
+
26
+
27
+ def rules_from_active_files(files: list[str], llm: AutoLLM, args: AutoCoderArgs):
28
+ rules_dir_path = os.path.join(args.source_dir, ".auto-coder", "autocoderrules")
29
+ auto_learn = AutoRulesLearn(llm=llm, args=args)
30
+
31
+ sources = SourceCodeList([])
32
+ for file in files:
33
+ try:
34
+ with open(file, "r", encoding="utf-8") as f:
35
+ source_code = f.read()
36
+ sources.sources.append(SourceCode(module_name=file, source_code=source_code))
37
+ except Exception as e:
38
+ printer.print_text(f"读取文件生成 Rules 失败: {e}", style="yellow")
39
+ continue
40
+
41
+ try:
42
+ result = auto_learn.analyze_modules(sources=sources, conversations=[])
43
+ rules_file = os.path.join(rules_dir_path, f"rules-modules-{uuid.uuid4()}.md")
44
+ with open(rules_file, "w", encoding="utf-8") as f:
45
+ f.write(result)
46
+ printer.print_text(f"活跃文件[Files:{len(files)}]生成 Rules 成功", style="green")
47
+ except Exception as e:
48
+ printer.print_text(f"活跃文件生成 Rules 失败: {e}", style="red")
49
+
50
+
51
+ def get_rules_context(project_root):
52
+ rules_dir_path = os.path.join(project_root, ".auto-coder", "autocoderrules")
53
+ printer.print_text("已开启 Rules 模式", style="green")
54
+ context = ""
55
+ context += f"下面是我们对代码进行深入分析,提取具有通用价值的功能模式和设计模式,可在其他需求中复用的Rules\n"
56
+ context += "你在编写代码时可以参考以下Rules\n"
57
+ context += "<rules>\n"
58
+ for rules_name in os.listdir(rules_dir_path):
59
+ printer.print_text(f"正在加载 Rules:{rules_name}", style="green")
60
+ rules_file_path = os.path.join(rules_dir_path, rules_name)
61
+ with open(rules_file_path, "r") as fp:
62
+ context += f"{fp.read()}\n"
63
+ context += "</rules>\n"
64
+ return context
65
+
66
+
67
+ __all__ = ["get_rules_context", "rules_from_commit_changes", "rules_from_active_files"]
autocoder_nano/version.py CHANGED
@@ -1,3 +1,3 @@
1
- __version__ = "0.1.36"
1
+ __version__ = "0.1.38"
2
2
  __author__ = "moofs"
3
3
  __license__ = "Apache License 2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: autocoder_nano
3
- Version: 0.1.36
3
+ Version: 0.1.38
4
4
  Summary: AutoCoder Nano
5
5
  Author: moofs
6
6
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
@@ -1,5 +1,5 @@
1
1
  autocoder_nano/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder_nano/auto_coder_nano.py,sha256=75BNVyuktY2gdH8dXKBGMa-DVePWORf_5kgN5OvBODc,80571
2
+ autocoder_nano/auto_coder_nano.py,sha256=rTcAq-GXnGxxmN5pIQfh7siYQAFjyIlZiPLjsaUXI9U,71685
3
3
  autocoder_nano/auto_coder_nano_rag.py,sha256=9BtNZ6nC5D5SPTIuziXZOfouCBLOMNzvJMTdDPQEgO8,10436
4
4
  autocoder_nano/auto_coder_nano_ui.py,sha256=ZBskcIJMeTJY7_JipGJaee58G9fUJaOv3LV4hptLc6c,12669
5
5
  autocoder_nano/file_utils.py,sha256=iGbkbQ191nKL4aNufdexYYYQSDM1XrDC9Uxp_PIbawY,661
@@ -10,7 +10,7 @@ autocoder_nano/llm_prompt.py,sha256=ViWUfCZp0gDESAAPHBhZc2WhHiFUHIxK6a2xbFu0sjU,
10
10
  autocoder_nano/llm_types.py,sha256=T0ugeWdwejy6BJaQrAlk8Pk5qweW2xbggxzHaSpTBOg,11588
11
11
  autocoder_nano/sys_utils.py,sha256=Sn6kr5diaEkVWbYDBrtenr9zw32jVIWvsAReY7_uEd0,1638
12
12
  autocoder_nano/templates.py,sha256=fqlRtnx6HvPE4CbdnPcnLBB-flPwufwcGRpsFD3aW2c,4271
13
- autocoder_nano/version.py,sha256=w6lOdNu-e-YHiAO2e5DN0oFTe4239b-ik57CnftvY_w,79
13
+ autocoder_nano/version.py,sha256=n-gEsFbSQhkVooPpwNmF2t1Qt1jwBdkbwO_3nOzXhPA,79
14
14
  autocoder_nano/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  autocoder_nano/agent/agent_base.py,sha256=O5Hq6VnoqrXnBE_oXZHXlbmSRdOEe28H65bJ1WhAQjg,16377
16
16
  autocoder_nano/agent/agentic_edit.py,sha256=I1HjRhMabDmtfxcCOKawUJV0wU1GNzKtof19_GNgAjU,88749
@@ -50,18 +50,18 @@ autocoder_nano/app/templates/partials/input.html,sha256=8CY3JcHaA4nPZ2Vu4ragdYZz
50
50
  autocoder_nano/app/templates/partials/message.html,sha256=HWEh_j_yJAbP7zFs6jt88BDzkP7dG6VgPUbS2MT5Ax4,1548
51
51
  autocoder_nano/chat/__init__.py,sha256=FuXp0tcnegngct9Jp8HbgwFkwnhxMirwNFHtoa_vACw,2441
52
52
  autocoder_nano/data/tokenizer.json,sha256=7Lb5_DaYlDRvBRH0B0ynXO5c1fOwbQLxujX805-OEh0,7847602
53
- autocoder_nano/edit/__init__.py,sha256=QPMuW7tBTUe0Q00gUPJEmdxWqvunqko9_dsim0ncr7c,623
53
+ autocoder_nano/edit/__init__.py,sha256=9_6am33w8U6nh1oMjWF-KmE1VmXe6UTTGd2CxSRaf5A,765
54
54
  autocoder_nano/edit/actions.py,sha256=N4qzSIE7Ifm7r6Sk-HbgWmbDqMP6jfrpByfpV7rbEo8,6480
55
55
  autocoder_nano/edit/text.py,sha256=nC7VkQYHCDdT3ULpy0DIjkFwB9suhjIxK39AEzXqbno,1150
56
56
  autocoder_nano/edit/code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
57
  autocoder_nano/edit/code/generate_editblock.py,sha256=s-VTZK0G1OhjEyZXqyjj4sY48fOo02EvHhaxTIw4ytY,13110
58
58
  autocoder_nano/edit/code/merge_editblock.py,sha256=Vk-FOVvaEzKcSRDMyMyR_M77kqj-s5-zejChn4QwLAY,17557
59
59
  autocoder_nano/edit/code/modification_ranker.py,sha256=hnF1acqAzPYKm9hEFxobJHfGGDdM-GclZLxvtt83lGA,3431
60
- autocoder_nano/index/__init__.py,sha256=r8HvwfyKJxnXMtAuxXIdbU0CWBGwJNlxIB4VZaUlBbo,112
60
+ autocoder_nano/index/__init__.py,sha256=fYrXsjRMrL2cjHjH37Bcl51Uqr17_aqlTH-c_2WQcok,3767
61
61
  autocoder_nano/index/entry.py,sha256=S71dfnYC201eQLXwqNCo_Y83ImI1ZxuJ0_m2hz5nCJc,7729
62
62
  autocoder_nano/index/index_manager.py,sha256=ek7AqU8M-Snl5qZYhO_U0SEK3-y1u5OOxD9z-LdDesE,15619
63
63
  autocoder_nano/index/symbols_utils.py,sha256=z_16X6BozTfmric1uU-r2GqzDabJ5ChfAOB4lo7i-_8,1450
64
- autocoder_nano/project/__init__.py,sha256=8R90zhCcRTHWScAOYw20lkcHI4IhSm-ywCLcfezn0Oc,227
64
+ autocoder_nano/project/__init__.py,sha256=KfSsvUVi-MCUJ-AITl8jQpOTPMIW55VmwPzSUP6LnlI,708
65
65
  autocoder_nano/project/pyproject.py,sha256=UZqHBrUmsCW73YkG8shjeFSEYGB_zFDH1ezoPP_f33Q,4478
66
66
  autocoder_nano/project/suffixproject.py,sha256=190GCS25qYi4kPav0Hpk2qgSFalkvJk7VM_pchnfurY,4717
67
67
  autocoder_nano/project/tsproject.py,sha256=3gBS-2aup2W5ehSbhD7Bdr-9v9uL7MgY_7TkLHShh9I,5565
@@ -79,7 +79,7 @@ autocoder_nano/rag/doc_storage.py,sha256=sEfX-2PsRTOk7MiwqtY3u0lzqMBwTsPXeIknkAY
79
79
  autocoder_nano/rag/long_context_rag.py,sha256=jpTfJg38pfVgL0FGFwe6nmBgQAMEAYtBw9ZLQQcFfpM,21862
80
80
  autocoder_nano/rag/token_counter.py,sha256=tHuht9huViEnpqiUVN_xUcgBOHJ0T-6dmk4IWzc_Cd0,1979
81
81
  autocoder_nano/research/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
- autocoder_nano/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
+ autocoder_nano/rules/__init__.py,sha256=cNglrWEQ4d-xXhbuS6CCFY6DZHRRWANmUayCNnhYOJY,2941
83
83
  autocoder_nano/rules/rules_learn.py,sha256=P65_wwZ1sBxcQPTwdb7roqmkW_bj1SJQaZMLpUkglL4,7297
84
84
  autocoder_nano/ss/__init__.py,sha256=jp9Az7c0uafZcC6qfxjyZnSnVLtgA_4UdakSOcp8osE,34
85
85
  autocoder_nano/ss/search_engine.py,sha256=4_RcxF1almJX5XlLWB7d9UXM92YDK2bOqoCrkuGg5Mc,3720
@@ -91,9 +91,9 @@ autocoder_nano/utils/config_utils.py,sha256=r5n0De4mz5sL_nj-CeT_F5TxtgWQIN5vv0Z5
91
91
  autocoder_nano/utils/formatted_log_utils.py,sha256=1d3xvZ1Bo3-I1wQOMdXpwsMX5cl2FWkmpgHGHvTPEvI,5457
92
92
  autocoder_nano/utils/printer_utils.py,sha256=6rGHihCh8DDESWs6qWqwsf3B6qaeM_CNx6crzkl9UCk,15303
93
93
  autocoder_nano/utils/shell_utils.py,sha256=llVTrOrmS1RH2ws7W69tofVtf53Kq04uh-sURphejrU,2477
94
- autocoder_nano-0.1.36.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
95
- autocoder_nano-0.1.36.dist-info/METADATA,sha256=7-k89fLfFGXd67c6xAaIvmZV2Q1vix4B5YecTSn6Qcw,13591
96
- autocoder_nano-0.1.36.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
97
- autocoder_nano-0.1.36.dist-info/entry_points.txt,sha256=Dj8gGZ_AgLy8ANqr2do_DJjpsR3JMh-ztsrUXo4Vn5Q,194
98
- autocoder_nano-0.1.36.dist-info/top_level.txt,sha256=D7s34cwIs1F4EAjRRDvO_zTHtUz1Z7UVccFUNlJn7HI,15
99
- autocoder_nano-0.1.36.dist-info/RECORD,,
94
+ autocoder_nano-0.1.38.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
95
+ autocoder_nano-0.1.38.dist-info/METADATA,sha256=TMDwPdAc0EKiR8VAMbV6z8Xjs6yBnuGpzHR9Q09AmeQ,13591
96
+ autocoder_nano-0.1.38.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
97
+ autocoder_nano-0.1.38.dist-info/entry_points.txt,sha256=Dj8gGZ_AgLy8ANqr2do_DJjpsR3JMh-ztsrUXo4Vn5Q,194
98
+ autocoder_nano-0.1.38.dist-info/top_level.txt,sha256=D7s34cwIs1F4EAjRRDvO_zTHtUz1Z7UVccFUNlJn7HI,15
99
+ autocoder_nano-0.1.38.dist-info/RECORD,,