auto-coder 0.1.363__py3-none-any.whl → 0.1.365__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.
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/METADATA +2 -2
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/RECORD +39 -23
- autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py +1 -1
- autocoder/auto_coder.py +46 -2
- autocoder/auto_coder_runner.py +2 -0
- autocoder/common/__init__.py +5 -0
- autocoder/common/file_checkpoint/__init__.py +21 -0
- autocoder/common/file_checkpoint/backup.py +264 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +182 -0
- autocoder/common/file_checkpoint/examples.py +217 -0
- autocoder/common/file_checkpoint/manager.py +611 -0
- autocoder/common/file_checkpoint/models.py +156 -0
- autocoder/common/file_checkpoint/store.py +383 -0
- autocoder/common/file_checkpoint/test_backup.py +242 -0
- autocoder/common/file_checkpoint/test_manager.py +570 -0
- autocoder/common/file_checkpoint/test_models.py +360 -0
- autocoder/common/file_checkpoint/test_store.py +327 -0
- autocoder/common/file_checkpoint/test_utils.py +297 -0
- autocoder/common/file_checkpoint/utils.py +119 -0
- autocoder/common/rulefiles/autocoderrules_utils.py +114 -55
- autocoder/common/save_formatted_log.py +76 -5
- autocoder/common/utils_code_auto_generate.py +2 -1
- autocoder/common/v2/agent/agentic_edit.py +545 -225
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +83 -43
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +116 -29
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +179 -48
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +101 -56
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +322 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +173 -132
- autocoder/common/v2/agent/agentic_edit_types.py +4 -0
- autocoder/compilers/normal_compiler.py +64 -0
- autocoder/events/event_manager_singleton.py +133 -4
- autocoder/linters/normal_linter.py +373 -0
- autocoder/linters/python_linter.py +4 -2
- autocoder/version.py +1 -1
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.363.dist-info → auto_coder-0.1.365.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: auto-coder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.365
|
|
4
4
|
Summary: AutoCoder: AutoCoder
|
|
5
5
|
Author: allwefantasy
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -28,7 +28,7 @@ Requires-Dist: prompt-toolkit
|
|
|
28
28
|
Requires-Dist: tokenizers
|
|
29
29
|
Requires-Dist: aiofiles
|
|
30
30
|
Requires-Dist: readerwriterlock
|
|
31
|
-
Requires-Dist: byzerllm[saas] >=0.1.
|
|
31
|
+
Requires-Dist: byzerllm[saas] >=0.1.182
|
|
32
32
|
Requires-Dist: patch
|
|
33
33
|
Requires-Dist: diff-match-patch
|
|
34
34
|
Requires-Dist: GitPython
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
autocoder/auto_coder.py,sha256=
|
|
2
|
+
autocoder/auto_coder.py,sha256=7602L3tG0JErNxh8vkLAmGUgv2c-DGPzPCkmWIQt9bs,69757
|
|
3
3
|
autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
|
|
4
4
|
autocoder/auto_coder_rag.py,sha256=ru5o86IaKylyVRlVORmnrdf3Q1To2eWi2KLdT9FMW0k,37580
|
|
5
5
|
autocoder/auto_coder_rag_client_mcp.py,sha256=QRxUbjc6A8UmDMQ8lXgZkjgqtq3lgKYeatJbDY6rSo0,6270
|
|
6
6
|
autocoder/auto_coder_rag_mcp.py,sha256=-RrjNwFaS2e5v8XDIrKR-zlUNUE8UBaeOtojffBrvJo,8521
|
|
7
|
-
autocoder/auto_coder_runner.py,sha256=
|
|
7
|
+
autocoder/auto_coder_runner.py,sha256=VktQIEWjVMmraVjD7W73eZmYtdfm9Ma2w_Ib-cWZYhM,112263
|
|
8
8
|
autocoder/auto_coder_server.py,sha256=bLORGEclcVdbBVfM140JCI8WtdrU0jbgqdJIVVupiEU,20578
|
|
9
9
|
autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
|
|
10
10
|
autocoder/chat_auto_coder.py,sha256=iHy8Kt1so1ZLOPpb5GTfi4BurDe3T1hOPqOw-XIBDpQ,26851
|
|
@@ -14,7 +14,7 @@ autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,1
|
|
|
14
14
|
autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
|
|
15
15
|
autocoder/models.py,sha256=Gu50IATQtZtgEir1PpCfwgH6o4ygw6XqqbQRj3lx5dU,13798
|
|
16
16
|
autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
|
|
17
|
-
autocoder/version.py,sha256=
|
|
17
|
+
autocoder/version.py,sha256=IcO5L1bOdV3qLFshmlEIP9ycK_uaklkhdNmRNqLG91g,23
|
|
18
18
|
autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
autocoder/agent/agentic_edit.py,sha256=XsfePZ-t6M-uBSdG1VLZXk1goqXk2HPeJ_A8IYyBuWQ,58896
|
|
20
20
|
autocoder/agent/agentic_edit_types.py,sha256=oFcDd_cxJ2yH9Ed1uTpD3BipudgoIEWDMPb5pAkq4gI,3288
|
|
@@ -58,7 +58,7 @@ autocoder/agent/base_agentic/tools/ask_followup_question_tool_resolver.py,sha256
|
|
|
58
58
|
autocoder/agent/base_agentic/tools/attempt_completion_tool_resolver.py,sha256=9a_qPihfm45Q22kmxmFwYrZrtNsgtEyBePL8D4SXfes,1487
|
|
59
59
|
autocoder/agent/base_agentic/tools/base_tool_resolver.py,sha256=Y0PmRPhBLLdZpr2DNV0W5goGfAqylM5m1bHxa3T6vAY,1009
|
|
60
60
|
autocoder/agent/base_agentic/tools/example_tool_resolver.py,sha256=8WBIqEH_76S0iBHBM3RhLkk14UpJ28lRAw6dNUT-0no,1388
|
|
61
|
-
autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py,sha256=
|
|
61
|
+
autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py,sha256=FDWheOy2NVG1RDeG2lhMlj0cFjG4UpqCkWPRMEM7Atc,3755
|
|
62
62
|
autocoder/agent/base_agentic/tools/list_files_tool_resolver.py,sha256=rIKcJ0xVI6Exdmqb2LhUQFL6_GNQFuYazqQSJR0Sf2g,5468
|
|
63
63
|
autocoder/agent/base_agentic/tools/plan_mode_respond_tool_resolver.py,sha256=hiLdMRknR_Aljd7Ic2bOWZKs11aFHdhkRTKTlP3IIgw,1461
|
|
64
64
|
autocoder/agent/base_agentic/tools/read_file_tool_resolver.py,sha256=4GV8_hyVlO97MgI2pdUrxur3MFNJutlBT8r9OYfQjps,2857
|
|
@@ -78,7 +78,7 @@ autocoder/commands/auto_web.py,sha256=K0Gv7lil5UqmExr_sAJNOcwNxw_q1vhvre1jjQ7tA3
|
|
|
78
78
|
autocoder/commands/tools.py,sha256=IX_zx5mWAvQDED7wUHTqNtrCmLNo9ztFV1aZ6AflY4o,34292
|
|
79
79
|
autocoder/common/JupyterClient.py,sha256=O-wi6pXeAEYhAY24kDa0BINrLYvKS6rKyWe98pDClS0,2816
|
|
80
80
|
autocoder/common/ShellClient.py,sha256=fM1q8t_XMSbLBl2zkCNC2J9xuyKN3eXzGm6hHhqL2WY,2286
|
|
81
|
-
autocoder/common/__init__.py,sha256=
|
|
81
|
+
autocoder/common/__init__.py,sha256=qZWLTeEjimIGDUvbAq_QV1o5jgMiD1k4TQcoU0-wOo8,14887
|
|
82
82
|
autocoder/common/action_yml_file_manager.py,sha256=DdF5P1R_B_chCnnqoA2IgogakWLZk_nItiJZUfX0_Wo,17857
|
|
83
83
|
autocoder/common/anything2images.py,sha256=0ILBbWzY02M-CiWB-vzuomb_J1hVdxRcenAfIrAXq9M,25283
|
|
84
84
|
autocoder/common/anything2img.py,sha256=iZQmg8srXlD7N5uGl5b_ONKJMBjYoW8kPmokkG6ISF0,10118
|
|
@@ -129,7 +129,7 @@ autocoder/common/printer.py,sha256=T4XTAcQp5w1ZWYx5NAUXlIGd-9500Vl0JaG1JJXMdkg,2
|
|
|
129
129
|
autocoder/common/recall_validation.py,sha256=Avt9Q9dX3kG6Pf2zsdlOHmsjd-OeSj7U1PFBDp_Cve0,1700
|
|
130
130
|
autocoder/common/result_manager.py,sha256=tvWtqSDhP7yKGtmB9s1pJAuRnB7nDgjM6eVrXF9n4e0,4169
|
|
131
131
|
autocoder/common/run_cmd.py,sha256=2VrJpeqooasUoc-WKVrvFfesmRR55kOpPmmYgpQrKVc,8283
|
|
132
|
-
autocoder/common/save_formatted_log.py,sha256=
|
|
132
|
+
autocoder/common/save_formatted_log.py,sha256=VXeN3dzA1C0AX1slSwBTFMC1lZHR9GtziSVRqUDEKfU,5395
|
|
133
133
|
autocoder/common/screenshots.py,sha256=_gA-z1HxGjPShBrtgkdideq58MG6rqFB2qMUJKjrycs,3769
|
|
134
134
|
autocoder/common/search.py,sha256=245iPFgWhMldoUK3CqCP89ltaxZiNPK73evoG6Fp1h8,16518
|
|
135
135
|
autocoder/common/search_replace.py,sha256=GphFkc57Hb673CAwmbiocqTbw8vrV7TrZxtOhD0332g,22147
|
|
@@ -141,7 +141,7 @@ autocoder/common/test_run_cmd.py,sha256=0piPrNnxTPS8vJRnsVH6-lgB5zeLaXSRY5pPH13H
|
|
|
141
141
|
autocoder/common/text.py,sha256=KGRQq314GHBmY4MWG8ossRoQi1_DTotvhxchpn78c-k,1003
|
|
142
142
|
autocoder/common/token_cost_caculate.py,sha256=MSWJtl7YpQSUt-gFQoqUcJMblyPqHXe2ZioiZOFkV80,10085
|
|
143
143
|
autocoder/common/types.py,sha256=Cw_4RH-rGmAgQE-Ck69maMAMqlPCDA4Yj37QmuUY0mQ,713
|
|
144
|
-
autocoder/common/utils_code_auto_generate.py,sha256=
|
|
144
|
+
autocoder/common/utils_code_auto_generate.py,sha256=zol3E5VQgriGzpR0p51yYnx8unthyurYM83QIudkxeI,4592
|
|
145
145
|
autocoder/common/conversations/__init__.py,sha256=xGZeOFrDsgg2fkPK1zmvYBDhAyX66FtgOcZaxhYKJXU,1338
|
|
146
146
|
autocoder/common/conversations/compatibility.py,sha256=WuBXB4-dw5X9LUMsB16VWbihvRZQ1tT99m6zuBwDfqE,9606
|
|
147
147
|
autocoder/common/conversations/conversation_manager.py,sha256=ZhuhfSdOTncqgy3nHPoEU7Cg0dCsSl-VPcvLbUlL2Tk,18295
|
|
@@ -149,6 +149,19 @@ autocoder/common/conversations/example.py,sha256=Pz_EhO6qneUFMfHZiDmGAClZ6b0V4T1
|
|
|
149
149
|
autocoder/common/directory_cache/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
150
150
|
autocoder/common/directory_cache/cache.py,sha256=Jknygb_U6DkF04_SX04IwsOcQdd-2QQ4d6k9Ucc9OZ0,9358
|
|
151
151
|
autocoder/common/directory_cache/test_cache.py,sha256=0iQkHaZQPhZBwSS6dwK_je93QMLbYGY0BYrTSt45Cao,6610
|
|
152
|
+
autocoder/common/file_checkpoint/__init__.py,sha256=qwoM0tIU-IMr-zGVCMN8yZtmz0NWpRe027l8z8sCjjk,847
|
|
153
|
+
autocoder/common/file_checkpoint/backup.py,sha256=JO26vOG9k7d8b5jgT24PdccSrTuPqKghp1nz5cmjSiE,8813
|
|
154
|
+
autocoder/common/file_checkpoint/conversation_checkpoint.py,sha256=SFSTjA0fF5rsHlYdLQ-Dr9dfDl5JihndhjeqhN3OuMY,6322
|
|
155
|
+
autocoder/common/file_checkpoint/examples.py,sha256=HTik8E0ddvKjEPGwzizWJBHIP9URrWRyRUOKSjYRUG8,6272
|
|
156
|
+
autocoder/common/file_checkpoint/manager.py,sha256=mkEPURbF109qnCwXOikNmJI8INhdfCwBW1v6sRB7ubY,23757
|
|
157
|
+
autocoder/common/file_checkpoint/models.py,sha256=dcZL2QGnklsa_BV_QY81fH-H5hYfhelXrH6GSrubMZo,4730
|
|
158
|
+
autocoder/common/file_checkpoint/store.py,sha256=dgQe-1O_gPJ3QU6tHihGRp0G2jgD2IDxQ-w9zM6Yq54,12920
|
|
159
|
+
autocoder/common/file_checkpoint/test_backup.py,sha256=Z9Y2RyGqxwKPNc7nW-2jtsMAYzqt0qZGzLoq3pn2zCI,8930
|
|
160
|
+
autocoder/common/file_checkpoint/test_manager.py,sha256=jpeHTmuBJ6bgB32VWBF5MxUEutY4qn8m2Q8kZukuuNc,20109
|
|
161
|
+
autocoder/common/file_checkpoint/test_models.py,sha256=BtIF0gYRsLj7EISV8CXNS8PW7OtMd_S2ShWNIBbQDIc,10491
|
|
162
|
+
autocoder/common/file_checkpoint/test_store.py,sha256=SqHT5zExX2mD-OT9ynaayPtjjcp_HZWkd5PovFCUA8U,12038
|
|
163
|
+
autocoder/common/file_checkpoint/test_utils.py,sha256=wN0VZaM5gc2ltu-c3OPKgKDXqOjgSRCPHep_s4Ns0nI,10209
|
|
164
|
+
autocoder/common/file_checkpoint/utils.py,sha256=lWchNqiQNH13sSi5Tn9g9zit8mlWdYSdiiT59nWeFJE,3273
|
|
152
165
|
autocoder/common/file_monitor/__init__.py,sha256=9reL3IEnyLWU77WjPzeprM8-4lCetlSMZ94Nuxk5KNg,85
|
|
153
166
|
autocoder/common/file_monitor/monitor.py,sha256=biS9TJyNKga2dE-CeYAi9xfXvA9aMeMl0tBf68G-SBE,16609
|
|
154
167
|
autocoder/common/ignorefiles/__init__.py,sha256=P0hq7Avu1IeXBYEkPBZLsJhFzhzyktUWTqaRIXiAFLY,75
|
|
@@ -158,7 +171,7 @@ autocoder/common/mcp_servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
158
171
|
autocoder/common/mcp_servers/mcp_server_gpt4o_mini_search.py,sha256=TApShxgoozLluobXHOK1-oAE1zm0-9jdRoPLQB1qwMI,5688
|
|
159
172
|
autocoder/common/mcp_servers/mcp_server_perplexity.py,sha256=CIC26UkfH1lYoVCjfyY5xGGYVx8h0oz0Uj1c7YJ3OPw,5560
|
|
160
173
|
autocoder/common/rulefiles/__init__.py,sha256=babSbPdFaXk1NvdHtH2zrJLb_tWd7d2ELIyS8NApY_Y,221
|
|
161
|
-
autocoder/common/rulefiles/autocoderrules_utils.py,sha256=
|
|
174
|
+
autocoder/common/rulefiles/autocoderrules_utils.py,sha256=TvzKt41wa1uPnYXHkUaJRCuxCJL9IB-Zx6FsEwdSExg,19454
|
|
162
175
|
autocoder/common/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
163
176
|
autocoder/common/v2/code_agentic_editblock_manager.py,sha256=pAh918YMgmLenXmNKXlmDPgKyVJjOuk69901VEEQHm4,34980
|
|
164
177
|
autocoder/common/v2/code_auto_generate.py,sha256=PAySLU8ZnpdF8GelwSCiEbzv7sBbn-Vhakinf4i6udE,11646
|
|
@@ -174,9 +187,9 @@ autocoder/common/v2/code_editblock_manager.py,sha256=DMwJw-FAM6VyaBQV3p4xespHpgZ
|
|
|
174
187
|
autocoder/common/v2/code_manager.py,sha256=C403bS-f6urixwitlKHcml-J03hci-UyNwHJOqBiY6Q,9182
|
|
175
188
|
autocoder/common/v2/code_strict_diff_manager.py,sha256=Bys7tFAq4G03R1zUZuxrszBTvP4QB96jIw2y5BDLyRM,9424
|
|
176
189
|
autocoder/common/v2/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
177
|
-
autocoder/common/v2/agent/agentic_edit.py,sha256=
|
|
190
|
+
autocoder/common/v2/agent/agentic_edit.py,sha256=Fx_T6YBWPa4tlTLY8dbecsd1n5a93dGE7b4gygmK56I,115043
|
|
178
191
|
autocoder/common/v2/agent/agentic_edit_conversation.py,sha256=pFgWPWHKhZ4J9EcFmIdiGsrSolTZuYcH1qkgKdD8nwk,7726
|
|
179
|
-
autocoder/common/v2/agent/agentic_edit_types.py,sha256=
|
|
192
|
+
autocoder/common/v2/agent/agentic_edit_types.py,sha256=nEcZc2MOZ_fQLaJX-YDha_x9Iim22ao4tykYM2iIy4k,4908
|
|
180
193
|
autocoder/common/v2/agent/agentic_tool_display.py,sha256=-a-JTQLc4q03E_rdIILKMI0B6DHN-5gcGlrqq-mBYK4,7239
|
|
181
194
|
autocoder/common/v2/agent/ignore_utils.py,sha256=gnUchRzKMLbUm_jvnKL-r-K9MWKPtt-6iiuzijY7Es0,1717
|
|
182
195
|
autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=RbPZZcZg_VnGssL577GxSyFrYrxQ_LopJ4G_-mY3z_Q,1337
|
|
@@ -185,15 +198,16 @@ autocoder/common/v2/agent/agentic_edit_tools/attempt_completion_tool_resolver.py
|
|
|
185
198
|
autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py,sha256=Zid2m1uZd-2wVFGc_n_KAViXZyNjbdLSpI5n7ut1RUQ,1036
|
|
186
199
|
autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py,sha256=sX00xzczfmyW6yPG3nMm0xO8p-WARQTiD4jcoUiTxsg,3844
|
|
187
200
|
autocoder/common/v2/agent/agentic_edit_tools/list_code_definition_names_tool_resolver.py,sha256=8QoMsADUDWliqiDt_dpguz31403syB8eeW0Pcw-qfb8,3842
|
|
188
|
-
autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py,sha256=
|
|
201
|
+
autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py,sha256=1tJX9RYRU0zRjKZMzFlZzKm-4R32CzRnZ0UQJj4pxAk,8074
|
|
189
202
|
autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py,sha256=dIdV12VuczHpHuHgx2B1j_3BZYc9PL0jfHCuBk9ryk8,2005
|
|
190
203
|
autocoder/common/v2/agent/agentic_edit_tools/plan_mode_respond_tool_resolver.py,sha256=lGT4_QYJK6Fa9f6HVSGo0cSsGK7qCsDYgJGUowNxPzk,1499
|
|
191
|
-
autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py,sha256=
|
|
192
|
-
autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py,sha256=
|
|
193
|
-
autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py,sha256=
|
|
204
|
+
autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py,sha256=6JhjM3VXV3BGelh1dNcdr-M5FoVPoqLkls1-y8ND8_c,6721
|
|
205
|
+
autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py,sha256=J-GOlaLMwEu83v9VuHIstTpRR_vgPMR9wP_AzoK173s,18009
|
|
206
|
+
autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py,sha256=VtDRDFJ2qzACy2jpD1ZNhywgCT3_iYUmGoUhHHmMX3o,9581
|
|
194
207
|
autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py,sha256=9eBo3WLkrr77iNotwIwVmH1ZL3UY0JQgLpdAIc9wTTM,6127
|
|
208
|
+
autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py,sha256=ZWRPsJny_My4UMzovrB8J2_x5N0rEW-xx3DVI-kDRFI,15870
|
|
195
209
|
autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py,sha256=wM2Xy4bcnD0TSLEmcM8rvvyyWenN5_KQnJMO6hJ8lTE,1716
|
|
196
|
-
autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py,sha256=
|
|
210
|
+
autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py,sha256=ISJ2jNz0Dfv1W7P2A_mYSM0vPdN0yW1w7Qqt6QjTk98,11170
|
|
197
211
|
autocoder/compilers/__init__.py,sha256=C0HOms70QA747XD0uZEMmGtRFcIPenohyqECNStv0Bw,1647
|
|
198
212
|
autocoder/compilers/base_compiler.py,sha256=dsTzMO4H_RoqWfE-SntIk2B52hWuvSlWVLtkdCbHgGs,3244
|
|
199
213
|
autocoder/compilers/compiler_config_api.py,sha256=QRSwWm_EX7jSeZ3dtQqM9HI__x5aZ7U0c3fHIW_2N48,13839
|
|
@@ -201,6 +215,7 @@ autocoder/compilers/compiler_config_manager.py,sha256=tNwHEk3t2o2L7ZVpHICDEOOIXR
|
|
|
201
215
|
autocoder/compilers/compiler_factory.py,sha256=SLUdvBZdqr_pkY-lfArHCuBVjtiMoIs9uxCGztYj6Ro,10950
|
|
202
216
|
autocoder/compilers/java_compiler.py,sha256=gR-_GB0_A1ZU3cTgRu1H9VPtLPmCWYo2UwBLEZIMvXU,26362
|
|
203
217
|
autocoder/compilers/models.py,sha256=ZqGQhiF5vfsK71xzLlsCUS_q_Oune3mqokJ8S8ZOPSc,9527
|
|
218
|
+
autocoder/compilers/normal_compiler.py,sha256=3FQO2KK_-pa9lUotXmtCp920lQi9PpcGtdcFpwzjkIQ,1931
|
|
204
219
|
autocoder/compilers/provided_compiler.py,sha256=gFxMOmFQYzsGCHJ9oPnSPQXboRdB0C4s5evdZMD99js,14667
|
|
205
220
|
autocoder/compilers/python_compiler.py,sha256=2w2OM_6H0ZWvaquQpDo1x4VciBWczCZkfwmEyJEEpn8,14389
|
|
206
221
|
autocoder/compilers/reactjs_compiler.py,sha256=h1_9OqiA8ca84-u3DIxQifvtH-2FSsKFWmhwALzNhqM,18159
|
|
@@ -220,7 +235,7 @@ autocoder/dispacher/actions/plugins/action_translate.py,sha256=GEn7dZA22jy5WyzIN
|
|
|
220
235
|
autocoder/events/__init__.py,sha256=1x_juwr9Ows2RADDa2LyI4QlmPxOVOXZeLO1cht-slM,1443
|
|
221
236
|
autocoder/events/event_content.py,sha256=eLHf5M1BifSqhzzEBgAWKn3JD5_z_1mWeNdZ53TpMqk,12240
|
|
222
237
|
autocoder/events/event_manager.py,sha256=ObbvPfNrrhC85w5VvsnLS9oy92oHEwqMN08qGPReNNA,11884
|
|
223
|
-
autocoder/events/event_manager_singleton.py,sha256=
|
|
238
|
+
autocoder/events/event_manager_singleton.py,sha256=F2OkC-rSTONZd4KS-ERnBAtBPO74aiEAMwJ9IKYa_b0,14742
|
|
224
239
|
autocoder/events/event_store.py,sha256=y6tT3P-o3yhDptrKi-UmqI_ZBNg7v21FriI3f7lo_ME,12709
|
|
225
240
|
autocoder/events/event_types.py,sha256=W_S6PTDIBdufcuPosgz64iITzQy79flL8s3hWB-vZ9o,3638
|
|
226
241
|
autocoder/helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -243,7 +258,8 @@ autocoder/linters/base_linter.py,sha256=1_0DPESnSyF3ZcQhoFkBYJylT5w-B61Rx-3A9uhu
|
|
|
243
258
|
autocoder/linters/code_linter.py,sha256=JylTj-Mj4jl9-XSH3PVlbQ4l55Y6E1FG-glv860CGSs,22462
|
|
244
259
|
autocoder/linters/linter_factory.py,sha256=rsDzaY0jFnmEsbY8Co_xxpJe9lXgfs07Nnrht8_WWtY,10273
|
|
245
260
|
autocoder/linters/models.py,sha256=GBdayu_p50KBxoRms4X68zrDK-OsKDEKKjo926FevwE,9838
|
|
246
|
-
autocoder/linters/
|
|
261
|
+
autocoder/linters/normal_linter.py,sha256=5Yavs24XNMOryl0ZDpr1UbVboCZwaIs4x9mFqoC1ZYk,13022
|
|
262
|
+
autocoder/linters/python_linter.py,sha256=CurQa4pYeyPv_e4FxgVBHW-pHOzQTOftARLgY97AKBw,22511
|
|
247
263
|
autocoder/linters/reactjs_linter.py,sha256=LDCXmAI15LUq8nNPyYko3oryzCc2Su05ob63jEeDdIs,20815
|
|
248
264
|
autocoder/linters/shadow_linter.py,sha256=SKgRNVnTavNUviFC9osYMz18nGWCVOPOHx9LavEbnmc,15047
|
|
249
265
|
autocoder/linters/vue_linter.py,sha256=ZyvoxT0kSizFh_UkR7UZYO5DV9edbvDQZaibEF9W95I,20905
|
|
@@ -338,9 +354,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
338
354
|
autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
339
355
|
autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
|
|
340
356
|
autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
341
|
-
auto_coder-0.1.
|
|
342
|
-
auto_coder-0.1.
|
|
343
|
-
auto_coder-0.1.
|
|
344
|
-
auto_coder-0.1.
|
|
345
|
-
auto_coder-0.1.
|
|
346
|
-
auto_coder-0.1.
|
|
357
|
+
auto_coder-0.1.365.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
358
|
+
auto_coder-0.1.365.dist-info/METADATA,sha256=vo07pJAu6M2IMTWjRq9caGUXRwr88NMs05TIHDGUJKs,2775
|
|
359
|
+
auto_coder-0.1.365.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
360
|
+
auto_coder-0.1.365.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
|
|
361
|
+
auto_coder-0.1.365.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
|
|
362
|
+
auto_coder-0.1.365.dist-info/RECORD,,
|
|
@@ -3,13 +3,13 @@ import subprocess
|
|
|
3
3
|
from typing import Dict, Any, Optional
|
|
4
4
|
from autocoder.agent.base_agentic.tools.base_tool_resolver import BaseToolResolver
|
|
5
5
|
from autocoder.agent.base_agentic.types import ExecuteCommandTool, ToolResult # Import ToolResult from types
|
|
6
|
-
from autocoder.common import shells
|
|
7
6
|
from autocoder.common.printer import Printer
|
|
8
7
|
from loguru import logger
|
|
9
8
|
import typing
|
|
10
9
|
from autocoder.common import AutoCoderArgs
|
|
11
10
|
from autocoder.events.event_manager_singleton import get_event_manager
|
|
12
11
|
from autocoder.run_context import get_run_context
|
|
12
|
+
from autocoder.common.run_cmd import run_cmd_subprocess
|
|
13
13
|
if typing.TYPE_CHECKING:
|
|
14
14
|
from ..base_agent import BaseAgent
|
|
15
15
|
|
autocoder/auto_coder.py
CHANGED
|
@@ -376,8 +376,8 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
376
376
|
llm.setup_sub_client("inference_model", inference_model)
|
|
377
377
|
|
|
378
378
|
if args.index_filter_model:
|
|
379
|
-
|
|
380
|
-
|
|
379
|
+
model_name = args.index_filter_model.strip()
|
|
380
|
+
model_info = models_module.get_model_by_name(model_name)
|
|
381
381
|
index_filter_model = byzerllm.SimpleByzerLLM(default_model_name=model_name)
|
|
382
382
|
index_filter_model.deploy(
|
|
383
383
|
model_path="",
|
|
@@ -393,6 +393,41 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
393
393
|
)
|
|
394
394
|
llm.setup_sub_client("index_filter_model", index_filter_model)
|
|
395
395
|
|
|
396
|
+
if args.context_prune_model:
|
|
397
|
+
model_name = args.context_prune_model.strip()
|
|
398
|
+
model_info = models_module.get_model_by_name(model_name)
|
|
399
|
+
context_prune_model = byzerllm.SimpleByzerLLM(default_model_name=model_name)
|
|
400
|
+
context_prune_model.deploy(
|
|
401
|
+
model_path="",
|
|
402
|
+
pretrained_model_type=model_info["model_type"],
|
|
403
|
+
udf_name=model_name,
|
|
404
|
+
infer_params={
|
|
405
|
+
"saas.base_url": model_info["base_url"],
|
|
406
|
+
"saas.api_key": model_info["api_key"],
|
|
407
|
+
"saas.model": model_info["model_name"],
|
|
408
|
+
"saas.is_reasoning": model_info["is_reasoning"],
|
|
409
|
+
"saas.max_output_tokens": model_info.get("max_output_tokens", 8096)
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
llm.setup_sub_client("context_prune_model", context_prune_model)
|
|
413
|
+
|
|
414
|
+
if args.conversation_prune_model:
|
|
415
|
+
model_name = args.conversation_prune_model.strip()
|
|
416
|
+
model_info = models_module.get_model_by_name(model_name)
|
|
417
|
+
conversation_prune_model = byzerllm.SimpleByzerLLM(default_model_name=model_name)
|
|
418
|
+
conversation_prune_model.deploy(
|
|
419
|
+
model_path="",
|
|
420
|
+
pretrained_model_type=model_info["model_type"],
|
|
421
|
+
udf_name=model_name,
|
|
422
|
+
infer_params={
|
|
423
|
+
"saas.base_url": model_info["base_url"],
|
|
424
|
+
"saas.api_key": model_info["api_key"],
|
|
425
|
+
"saas.model": model_info["model_name"],
|
|
426
|
+
"saas.is_reasoning": model_info["is_reasoning"],
|
|
427
|
+
"saas.max_output_tokens": model_info.get("max_output_tokens", 8096)
|
|
428
|
+
}
|
|
429
|
+
)
|
|
430
|
+
llm.setup_sub_client("conversation_prune_model", conversation_prune_model)
|
|
396
431
|
|
|
397
432
|
if args.product_mode == "pro":
|
|
398
433
|
if args.code_model:
|
|
@@ -437,6 +472,15 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
437
472
|
index_filter_model.setup_default_model_name(args.index_filter_model)
|
|
438
473
|
llm.setup_sub_client("index_filter_model", index_filter_model)
|
|
439
474
|
|
|
475
|
+
if args.context_prune_model:
|
|
476
|
+
context_prune_model = byzerllm.ByzerLLM()
|
|
477
|
+
context_prune_model.setup_default_model_name(args.context_prune_model)
|
|
478
|
+
llm.setup_sub_client("context_prune_model", context_prune_model)
|
|
479
|
+
|
|
480
|
+
if args.conversation_prune_model:
|
|
481
|
+
conversation_prune_model = byzerllm.ByzerLLM()
|
|
482
|
+
conversation_prune_model.setup_default_model_name(args.conversation_prune_model)
|
|
483
|
+
llm.setup_sub_client("conversation_prune_model", conversation_prune_model)
|
|
440
484
|
|
|
441
485
|
if get_run_context().mode != RunMode.WEB and args.human_as_model:
|
|
442
486
|
|
autocoder/auto_coder_runner.py
CHANGED
|
@@ -2850,6 +2850,7 @@ def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
|
2850
2850
|
else:
|
|
2851
2851
|
agent.run_in_terminal(AgenticEditRequest(user_input=query))
|
|
2852
2852
|
|
|
2853
|
+
completer.refresh_files()
|
|
2853
2854
|
return
|
|
2854
2855
|
|
|
2855
2856
|
args = get_final_config()
|
|
@@ -2902,3 +2903,4 @@ def auto_command(query: str,extra_args: Dict[str,Any]={}):
|
|
|
2902
2903
|
border_style="blue",
|
|
2903
2904
|
padding=(1, 2)
|
|
2904
2905
|
))
|
|
2906
|
+
completer.refresh_files()
|
autocoder/common/__init__.py
CHANGED
|
@@ -254,6 +254,8 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
254
254
|
emb_model: Optional[str] = ""
|
|
255
255
|
code_model: Optional[str] = ""
|
|
256
256
|
generate_rerank_model: Optional[str] = ""
|
|
257
|
+
context_prune_model: Optional[str] = ""
|
|
258
|
+
conversation_prune_model: Optional[str] = ""
|
|
257
259
|
inference_model: Optional[str] = ""
|
|
258
260
|
system_prompt: Optional[str] = ""
|
|
259
261
|
planner_model: Optional[str] = ""
|
|
@@ -399,6 +401,7 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
399
401
|
|
|
400
402
|
context_prune_strategy: Optional[str] = "extract"
|
|
401
403
|
context_prune: Optional[bool] = True
|
|
404
|
+
context_prune_safe_zone_tokens: Optional[int] = 32*1024
|
|
402
405
|
context_prune_sliding_window_size: Optional[int] = 1000
|
|
403
406
|
context_prune_sliding_window_overlap: Optional[int] = 100
|
|
404
407
|
|
|
@@ -432,6 +435,8 @@ class AutoCoderArgs(pydantic.BaseModel):
|
|
|
432
435
|
auto_fix_lint_max_attempts: Optional[int] = 5
|
|
433
436
|
auto_fix_compile_max_attempts: Optional[int] = 5
|
|
434
437
|
auto_fix_merge_max_attempts: Optional[int] = 5
|
|
438
|
+
|
|
439
|
+
enable_auto_select_rules: Optional[bool] = True
|
|
435
440
|
|
|
436
441
|
ignore_clean_shadows: Optional[bool] = False
|
|
437
442
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
文件变更管理模块
|
|
3
|
+
|
|
4
|
+
该模块提供了一种可靠的机制来应用、记录和撤销对项目文件的修改。
|
|
5
|
+
主要功能包括:
|
|
6
|
+
1. 将影子系统中的文件变更安全地应用到用户的实际项目中
|
|
7
|
+
2. 记录每次变更的历史,支持多版本撤销功能
|
|
8
|
+
3. 提供简单直观的API,便于集成到现有的编辑流程中
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from autocoder.common.file_checkpoint.models import (
|
|
12
|
+
FileChange, ChangeRecord, ApplyResult, UndoResult, DiffResult
|
|
13
|
+
)
|
|
14
|
+
from autocoder.common.file_checkpoint.manager import FileChangeManager
|
|
15
|
+
from autocoder.common.file_checkpoint.store import FileChangeStore
|
|
16
|
+
from autocoder.common.file_checkpoint.backup import FileBackupManager
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
'FileChange', 'ChangeRecord', 'ApplyResult', 'UndoResult', 'DiffResult',
|
|
20
|
+
'FileChangeManager', 'FileChangeStore', 'FileBackupManager'
|
|
21
|
+
]
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
文件备份管理器
|
|
3
|
+
|
|
4
|
+
负责文件的备份和恢复操作,支持多版本文件备份。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import uuid
|
|
9
|
+
import shutil
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Optional, Dict, List, Tuple
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
import json
|
|
14
|
+
import threading
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FileBackupManager:
|
|
20
|
+
"""负责文件的备份和恢复操作"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, backup_dir: Optional[str] = None):
|
|
23
|
+
"""
|
|
24
|
+
初始化备份管理器
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
backup_dir: 备份文件存储目录,如果为None则使用默认目录
|
|
28
|
+
"""
|
|
29
|
+
if backup_dir is None:
|
|
30
|
+
# 默认备份目录为项目根目录下的.auto-coder/checkpoint
|
|
31
|
+
backup_dir = os.path.join(os.getcwd(), ".auto-coder", "checkpoint")
|
|
32
|
+
|
|
33
|
+
self.backup_dir = backup_dir
|
|
34
|
+
self.metadata_file = os.path.join(backup_dir, "backup_metadata.json")
|
|
35
|
+
self.lock = threading.RLock()
|
|
36
|
+
|
|
37
|
+
# 确保备份目录存在
|
|
38
|
+
os.makedirs(backup_dir, exist_ok=True)
|
|
39
|
+
|
|
40
|
+
# 加载备份元数据
|
|
41
|
+
self.metadata = self._load_metadata()
|
|
42
|
+
|
|
43
|
+
def backup_file(self, file_path: str) -> Optional[str]:
|
|
44
|
+
"""
|
|
45
|
+
备份指定文件
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
file_path: 文件路径
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
str: 备份文件ID,如果文件不存在则返回None
|
|
52
|
+
"""
|
|
53
|
+
if not os.path.exists(file_path):
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
with self.lock:
|
|
57
|
+
# 生成唯一的备份ID
|
|
58
|
+
backup_id = str(uuid.uuid4())
|
|
59
|
+
|
|
60
|
+
# 构建备份文件路径
|
|
61
|
+
backup_file_path = os.path.join(self.backup_dir, backup_id)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
# 复制文件到备份目录
|
|
65
|
+
shutil.copy2(file_path, backup_file_path)
|
|
66
|
+
|
|
67
|
+
# 更新元数据
|
|
68
|
+
self.metadata[backup_id] = {
|
|
69
|
+
"original_path": file_path,
|
|
70
|
+
"timestamp": datetime.now().timestamp(),
|
|
71
|
+
"size": os.path.getsize(file_path)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# 保存元数据
|
|
75
|
+
self._save_metadata()
|
|
76
|
+
|
|
77
|
+
logger.debug(f"已备份文件 {file_path} 到 {backup_file_path}")
|
|
78
|
+
return backup_id
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.error(f"备份文件 {file_path} 失败: {str(e)}")
|
|
82
|
+
# 清理可能部分创建的备份文件
|
|
83
|
+
if os.path.exists(backup_file_path):
|
|
84
|
+
os.remove(backup_file_path)
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
def restore_file(self, file_path: str, backup_id: str) -> bool:
|
|
88
|
+
"""
|
|
89
|
+
从备份恢复文件
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
file_path: 目标文件路径
|
|
93
|
+
backup_id: 备份文件ID
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
bool: 恢复是否成功
|
|
97
|
+
"""
|
|
98
|
+
with self.lock:
|
|
99
|
+
# 检查备份ID是否存在
|
|
100
|
+
if backup_id not in self.metadata:
|
|
101
|
+
logger.error(f"备份ID {backup_id} 不存在")
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
# 构建备份文件路径
|
|
105
|
+
backup_file_path = os.path.join(self.backup_dir, backup_id)
|
|
106
|
+
|
|
107
|
+
# 检查备份文件是否存在
|
|
108
|
+
if not os.path.exists(backup_file_path):
|
|
109
|
+
logger.error(f"备份文件 {backup_file_path} 不存在")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
# 确保目标目录存在
|
|
114
|
+
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
115
|
+
|
|
116
|
+
# 复制备份文件到目标路径
|
|
117
|
+
shutil.copy2(backup_file_path, file_path)
|
|
118
|
+
|
|
119
|
+
logger.debug(f"已从 {backup_file_path} 恢复文件到 {file_path}")
|
|
120
|
+
return True
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
logger.error(f"恢复文件 {file_path} 失败: {str(e)}")
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def get_backup_content(self, backup_id: str) -> Optional[str]:
|
|
127
|
+
"""
|
|
128
|
+
获取备份文件的内容
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
backup_id: 备份文件ID
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
str: 备份文件内容,如果备份不存在则返回None
|
|
135
|
+
"""
|
|
136
|
+
with self.lock:
|
|
137
|
+
# 检查备份ID是否存在
|
|
138
|
+
if backup_id not in self.metadata:
|
|
139
|
+
logger.error(f"备份ID {backup_id} 不存在")
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
# 构建备份文件路径
|
|
143
|
+
backup_file_path = os.path.join(self.backup_dir, backup_id)
|
|
144
|
+
|
|
145
|
+
# 检查备份文件是否存在
|
|
146
|
+
if not os.path.exists(backup_file_path):
|
|
147
|
+
logger.error(f"备份文件 {backup_file_path} 不存在")
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
# 读取备份文件内容
|
|
152
|
+
with open(backup_file_path, 'r', encoding='utf-8') as f:
|
|
153
|
+
return f.read()
|
|
154
|
+
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logger.error(f"读取备份文件 {backup_file_path} 失败: {str(e)}")
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
def delete_backup(self, backup_id: str) -> bool:
|
|
160
|
+
"""
|
|
161
|
+
删除指定的备份文件
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
backup_id: 备份文件ID
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
bool: 删除是否成功
|
|
168
|
+
"""
|
|
169
|
+
with self.lock:
|
|
170
|
+
# 检查备份ID是否存在
|
|
171
|
+
if backup_id not in self.metadata:
|
|
172
|
+
logger.error(f"备份ID {backup_id} 不存在")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
# 构建备份文件路径
|
|
176
|
+
backup_file_path = os.path.join(self.backup_dir, backup_id)
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
# 删除备份文件
|
|
180
|
+
if os.path.exists(backup_file_path):
|
|
181
|
+
os.remove(backup_file_path)
|
|
182
|
+
|
|
183
|
+
# 更新元数据
|
|
184
|
+
del self.metadata[backup_id]
|
|
185
|
+
|
|
186
|
+
# 保存元数据
|
|
187
|
+
self._save_metadata()
|
|
188
|
+
|
|
189
|
+
logger.debug(f"已删除备份 {backup_id}")
|
|
190
|
+
return True
|
|
191
|
+
|
|
192
|
+
except Exception as e:
|
|
193
|
+
logger.error(f"删除备份 {backup_id} 失败: {str(e)}")
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
def clean_old_backups(self, max_age_days: int = 30) -> int:
|
|
197
|
+
"""
|
|
198
|
+
清理过旧的备份文件
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
max_age_days: 最大保留天数
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
int: 清理的备份文件数量
|
|
205
|
+
"""
|
|
206
|
+
with self.lock:
|
|
207
|
+
now = datetime.now().timestamp()
|
|
208
|
+
max_age_seconds = max_age_days * 24 * 60 * 60
|
|
209
|
+
|
|
210
|
+
backup_ids_to_delete = []
|
|
211
|
+
|
|
212
|
+
# 找出过旧的备份
|
|
213
|
+
for backup_id, metadata in self.metadata.items():
|
|
214
|
+
if now - metadata["timestamp"] > max_age_seconds:
|
|
215
|
+
backup_ids_to_delete.append(backup_id)
|
|
216
|
+
|
|
217
|
+
# 删除过旧的备份
|
|
218
|
+
deleted_count = 0
|
|
219
|
+
for backup_id in backup_ids_to_delete:
|
|
220
|
+
if self.delete_backup(backup_id):
|
|
221
|
+
deleted_count += 1
|
|
222
|
+
|
|
223
|
+
return deleted_count
|
|
224
|
+
|
|
225
|
+
def get_backups_for_file(self, file_path: str) -> List[Tuple[str, float]]:
|
|
226
|
+
"""
|
|
227
|
+
获取指定文件的所有备份
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
file_path: 文件路径
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
List[Tuple[str, float]]: 备份ID和时间戳的列表,按时间戳降序排序
|
|
234
|
+
"""
|
|
235
|
+
with self.lock:
|
|
236
|
+
backups = []
|
|
237
|
+
|
|
238
|
+
for backup_id, metadata in self.metadata.items():
|
|
239
|
+
if metadata["original_path"] == file_path:
|
|
240
|
+
backups.append((backup_id, metadata["timestamp"]))
|
|
241
|
+
|
|
242
|
+
# 按时间戳降序排序
|
|
243
|
+
backups.sort(key=lambda x: x[1], reverse=True)
|
|
244
|
+
|
|
245
|
+
return backups
|
|
246
|
+
|
|
247
|
+
def _load_metadata(self) -> Dict:
|
|
248
|
+
"""加载备份元数据"""
|
|
249
|
+
if os.path.exists(self.metadata_file):
|
|
250
|
+
try:
|
|
251
|
+
with open(self.metadata_file, 'r', encoding='utf-8') as f:
|
|
252
|
+
return json.load(f)
|
|
253
|
+
except Exception as e:
|
|
254
|
+
logger.error(f"加载备份元数据失败: {str(e)}")
|
|
255
|
+
|
|
256
|
+
return {}
|
|
257
|
+
|
|
258
|
+
def _save_metadata(self) -> None:
|
|
259
|
+
"""保存备份元数据"""
|
|
260
|
+
try:
|
|
261
|
+
with open(self.metadata_file, 'w', encoding='utf-8') as f:
|
|
262
|
+
json.dump(self.metadata, f, indent=2)
|
|
263
|
+
except Exception as e:
|
|
264
|
+
logger.error(f"保存备份元数据失败: {str(e)}")
|