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.
- autocoder_nano/auto_coder_nano.py +67 -257
- autocoder_nano/edit/__init__.py +9 -1
- autocoder_nano/index/__init__.py +90 -1
- autocoder_nano/project/__init__.py +15 -1
- autocoder_nano/rules/__init__.py +67 -0
- autocoder_nano/version.py +1 -1
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/METADATA +1 -1
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/RECORD +12 -12
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/LICENSE +0 -0
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/WHEEL +0 -0
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/entry_points.txt +0 -0
- {autocoder_nano-0.1.36.dist-info → autocoder_nano-0.1.38.dist-info}/top_level.txt +0 -0
@@ -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
|
14
|
+
from autocoder_nano.edit import coding
|
15
15
|
from autocoder_nano.helper import show_help
|
16
|
-
from autocoder_nano.
|
17
|
-
from autocoder_nano.index
|
18
|
-
|
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
|
-
|
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
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
588
|
-
else:
|
589
|
-
|
590
|
-
pp.run()
|
591
|
-
_sources = pp.sources
|
592
|
-
|
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
|
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
|
-
|
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
|
-
|
817
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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:
|
autocoder_nano/edit/__init__.py
CHANGED
autocoder_nano/index/__init__.py
CHANGED
@@ -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__ = ["
|
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
|
-
|
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"]
|
autocoder_nano/rules/__init__.py
CHANGED
@@ -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,5 +1,5 @@
|
|
1
1
|
autocoder_nano/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
autocoder_nano/auto_coder_nano.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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.
|
95
|
-
autocoder_nano-0.1.
|
96
|
-
autocoder_nano-0.1.
|
97
|
-
autocoder_nano-0.1.
|
98
|
-
autocoder_nano-0.1.
|
99
|
-
autocoder_nano-0.1.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|