auto-coder 0.1.367__py3-none-any.whl → 0.1.370__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.367.dist-info → auto_coder-0.1.370.dist-info}/METADATA +1 -1
- {auto_coder-0.1.367.dist-info → auto_coder-0.1.370.dist-info}/RECORD +13 -8
- autocoder/agent/auto_learn.py +103 -346
- autocoder/common/command_file_manager/__init__.py +25 -0
- autocoder/common/command_file_manager/examples.py +142 -0
- autocoder/common/command_file_manager/manager.py +175 -0
- autocoder/common/command_file_manager/models.py +119 -0
- autocoder/common/command_file_manager/utils.py +119 -0
- autocoder/version.py +1 -1
- {auto_coder-0.1.367.dist-info → auto_coder-0.1.370.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.367.dist-info → auto_coder-0.1.370.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.367.dist-info → auto_coder-0.1.370.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.367.dist-info → auto_coder-0.1.370.dist-info}/top_level.txt +0 -0
|
@@ -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=zqOBO5WdpPJ-GjzRIIEqPqlEUWeZxaPhquf25C1uUHw,25
|
|
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
|
|
@@ -22,7 +22,7 @@ autocoder/agent/agentic_filter.py,sha256=zlInIRhawKIYTJjCiJBWqPCOV5UtMbh5VnvszfT
|
|
|
22
22
|
autocoder/agent/auto_demand_organizer.py,sha256=URAq0gSEiHeV_W4zwhOI_83kHz0Ryfj1gcfh5jwCv_w,6501
|
|
23
23
|
autocoder/agent/auto_filegroup.py,sha256=pBsAkBcpFTff-9L5OwI8xhf2xPKpl-aZwz-skF2B6dc,6296
|
|
24
24
|
autocoder/agent/auto_guess_query.py,sha256=rDSdhpPHcOGE5MuDXvIrhCXAPR4ARS1LqpyoLsx2Jhw,11374
|
|
25
|
-
autocoder/agent/auto_learn.py,sha256=
|
|
25
|
+
autocoder/agent/auto_learn.py,sha256=EMSbIVo2DK9Lp4sxFtpK4HRxqclGVKHYex51SG7SJpM,13942
|
|
26
26
|
autocoder/agent/auto_learn_from_commit.py,sha256=edD4GQJyO2qvVnTKyldeswWoNeKe1Aaua6ieJzlGlFI,10662
|
|
27
27
|
autocoder/agent/auto_review_commit.py,sha256=1z9FOUDPZTWnrPmJ-TwUlXLOTDPmRcAlYqXbUj1pi08,11015
|
|
28
28
|
autocoder/agent/auto_tool.py,sha256=DBzip-P_T6ZtT2eHexPcusmKYD0h7ufzp7TLwXAY10E,11554
|
|
@@ -142,6 +142,11 @@ 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
144
|
autocoder/common/utils_code_auto_generate.py,sha256=sqtLmVxRveRwqLwJ8UlDgwngwmh2AAo3vgl-I-ALcDQ,4597
|
|
145
|
+
autocoder/common/command_file_manager/__init__.py,sha256=ardiG_iuWhurfbN6RO4wij2U7Dmafnxn2vgWYYxKqDM,970
|
|
146
|
+
autocoder/common/command_file_manager/examples.py,sha256=kWNVK_iDvQn5NtA8D791Oxkj8xP5DWSD72PcMYIgwBQ,4067
|
|
147
|
+
autocoder/common/command_file_manager/manager.py,sha256=XmCOaWgGo3RemU1ubYOoNr40eaRqGHCwX7GS2vt3voo,5935
|
|
148
|
+
autocoder/common/command_file_manager/models.py,sha256=cDYRSQGK5O4nFI0GGHQvHcPeNKUxKePZQCgy7Mfw3kU,3471
|
|
149
|
+
autocoder/common/command_file_manager/utils.py,sha256=OA9OhB1VnkvnFGof9p6jGfIVx31usUcqucXZCkqNm4I,3488
|
|
145
150
|
autocoder/common/conversations/__init__.py,sha256=xGZeOFrDsgg2fkPK1zmvYBDhAyX66FtgOcZaxhYKJXU,1338
|
|
146
151
|
autocoder/common/conversations/compatibility.py,sha256=WuBXB4-dw5X9LUMsB16VWbihvRZQ1tT99m6zuBwDfqE,9606
|
|
147
152
|
autocoder/common/conversations/conversation_manager.py,sha256=ZhuhfSdOTncqgy3nHPoEU7Cg0dCsSl-VPcvLbUlL2Tk,18295
|
|
@@ -354,9 +359,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
354
359
|
autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
355
360
|
autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
|
|
356
361
|
autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
357
|
-
auto_coder-0.1.
|
|
358
|
-
auto_coder-0.1.
|
|
359
|
-
auto_coder-0.1.
|
|
360
|
-
auto_coder-0.1.
|
|
361
|
-
auto_coder-0.1.
|
|
362
|
-
auto_coder-0.1.
|
|
362
|
+
auto_coder-0.1.370.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
363
|
+
auto_coder-0.1.370.dist-info/METADATA,sha256=XG9OcN3l6UOPuZbFKubCHYv_-sf3NipSc_TkeAPnoS8,2775
|
|
364
|
+
auto_coder-0.1.370.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
365
|
+
auto_coder-0.1.370.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
|
|
366
|
+
auto_coder-0.1.370.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
|
|
367
|
+
auto_coder-0.1.370.dist-info/RECORD,,
|
autocoder/agent/auto_learn.py
CHANGED
|
@@ -33,17 +33,8 @@ class AutoLearn:
|
|
|
33
33
|
querie_with_urls_and_changes: List[Tuple[str, List[str], Dict[str, Tuple[str, str]]]],
|
|
34
34
|
new_query:str,
|
|
35
35
|
) -> str:
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
## 任务目标
|
|
40
|
-
- 识别代码变更中具有普遍应用价值的功能点和模式
|
|
41
|
-
- 将这些功能点提炼为结构化规则,便于在其他项目中快速复用
|
|
42
|
-
- 生成清晰的使用示例,包含完整依赖和调用方式
|
|
43
|
-
- 这些规则将被存储在项目的 {{ project_root }}/.autocoderrules 目录,供后续自动化代码生成使用
|
|
44
|
-
|
|
45
|
-
## 分析对象
|
|
46
|
-
下面是本次提交的代码变更:
|
|
36
|
+
"""
|
|
37
|
+
下面是用户一次提交的代码变更:
|
|
47
38
|
<changes>
|
|
48
39
|
{% for query,urls,changes in querie_with_urls_and_changes %}
|
|
49
40
|
## 原始的任务需求
|
|
@@ -69,360 +60,124 @@ class AutoLearn:
|
|
|
69
60
|
{% endfor %}
|
|
70
61
|
{% endfor %}
|
|
71
62
|
</changes>
|
|
63
|
+
|
|
72
64
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
请对根据上面的代码变更进行深入分析,提取具有通用价值的功能模式和设计模式,转化为可在其他项目中复用的代码规则(rules)。
|
|
66
|
+
|
|
67
|
+
- 识别代码变更中具有普遍应用价值的功能点和模式
|
|
68
|
+
- 将这些功能点提炼为结构化规则,便于在其他项目中快速复用
|
|
69
|
+
- 生成清晰的使用示例,包含完整依赖和调用方式
|
|
70
|
+
- 这些规则将被存储在项目的 {{ rules_path }} 目录,供后续自动化代码生成使用
|
|
71
|
+
- 更新 {{rules_index_path}} 文件,确保改文件有新增文件的描述信息
|
|
72
|
+
|
|
73
|
+
当前 {{rules_index_path}} 文件内容:
|
|
74
|
+
{% if index_file_content %}
|
|
79
75
|
{{ index_file_content }}
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
{% else %}
|
|
77
|
+
<为空>
|
|
82
78
|
{% endif %}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
## 生成或者更新的规则文件示例
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
description: Git提交分析工具
|
|
122
|
-
globs: "src/utils/git_analyzer.py"
|
|
123
|
-
alwaysApply: false
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
# Git提交分析工具
|
|
127
|
-
|
|
128
|
-
## 简要说明
|
|
129
|
-
提供从Git仓库中获取提交变更并分析差异的工具函数,支持首次提交和普通提交的差异获取,适用于代码审查、变更追踪和自动化分析场景。
|
|
130
|
-
|
|
131
|
-
## 典型用法
|
|
132
|
-
```python
|
|
133
|
-
import git
|
|
134
|
-
from typing import Dict, Tuple, List, Optional
|
|
135
|
-
|
|
136
|
-
def get_commit_changes(repo_path: str, commit_id: str) -> Dict[str, Tuple[Optional[str], Optional[str]]]:
|
|
137
|
-
'''
|
|
138
|
-
获取指定commit的文件变更内容
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
repo_path: Git仓库路径
|
|
142
|
-
commit_id: 提交ID
|
|
143
|
-
|
|
144
|
-
Returns:
|
|
145
|
-
Dict[str, Tuple[Optional[str], Optional[str]]]: 文件路径到(变更前内容,变更后内容)的映射
|
|
146
|
-
'''
|
|
147
|
-
changes = {}
|
|
148
|
-
try:
|
|
149
|
-
repo = git.Repo(repo_path)
|
|
150
|
-
commit = repo.commit(commit_id)
|
|
151
|
-
|
|
152
|
-
# 检查是否是首次提交(没有父提交)
|
|
153
|
-
if not commit.parents:
|
|
154
|
-
# 首次提交,获取所有文件
|
|
155
|
-
for item in commit.tree.traverse():
|
|
156
|
-
if item.type == 'blob': # 只处理文件,不处理目录
|
|
157
|
-
file_path = item.path
|
|
158
|
-
# 首次提交前没有内容
|
|
159
|
-
before_content = None
|
|
160
|
-
# 获取提交后的内容
|
|
161
|
-
after_content = repo.git.show(f"{commit.hexsha}:{file_path}")
|
|
162
|
-
changes[file_path] = (before_content, after_content)
|
|
163
|
-
else:
|
|
164
|
-
# 获取parent commit
|
|
165
|
-
parent = commit.parents[0]
|
|
166
|
-
# 获取变更的文件列表
|
|
167
|
-
for diff_item in parent.diff(commit):
|
|
168
|
-
file_path = diff_item.a_path if diff_item.a_path else diff_item.b_path
|
|
169
|
-
|
|
170
|
-
# 获取变更前内容
|
|
171
|
-
before_content = None
|
|
172
|
-
try:
|
|
173
|
-
if diff_item.a_blob:
|
|
174
|
-
before_content = repo.git.show(f"{parent.hexsha}:{file_path}")
|
|
175
|
-
except git.exc.GitCommandError:
|
|
176
|
-
pass # 文件可能是新增的
|
|
177
|
-
|
|
178
|
-
# 获取变更后内容
|
|
179
|
-
after_content = None
|
|
180
|
-
try:
|
|
181
|
-
if diff_item.b_blob:
|
|
182
|
-
after_content = repo.git.show(f"{commit.hexsha}:{file_path}")
|
|
183
|
-
except git.exc.GitCommandError:
|
|
184
|
-
pass # 文件可能被删除
|
|
185
|
-
|
|
186
|
-
changes[file_path] = (before_content, after_content)
|
|
187
|
-
|
|
188
|
-
return changes
|
|
189
|
-
except Exception as e:
|
|
190
|
-
print(f"获取提交变更时出错: {str(e)}")
|
|
191
|
-
return {}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
## 依赖说明
|
|
195
|
-
- GitPython>=3.1.0
|
|
196
|
-
- Python>=3.7
|
|
197
|
-
|
|
198
|
-
## 学习来源
|
|
199
|
-
从代码提交变更中提取的Git仓库差异分析功能
|
|
200
|
-
|
|
201
|
-
## 索引文件更新说明
|
|
202
|
-
|
|
203
|
-
除了生成规则文件外,请务必更新index.md索引文件,记录所有规则及其作用。如果 index.md 当前内容为空,请按如下格式创建:
|
|
204
|
-
|
|
205
|
-
# Rules索引
|
|
206
|
-
|
|
207
|
-
本文档记录项目中所有可用的代码规则(rules)及其用途。
|
|
208
|
-
|
|
209
|
-
## [规则文件路径]
|
|
210
|
-
[规则文件的主要功能和适用场景简述]
|
|
211
|
-
|
|
212
|
-
## 评价标准
|
|
213
|
-
- 提取的功能点必须具备独立价值,能在其他项目中实际复用
|
|
214
|
-
- 代码示例必须完整、可执行,包含所有必要组件
|
|
215
|
-
- 文档结构清晰,遵循规定格式
|
|
216
|
-
- 依赖说明明确具体,便于用户快速配置环境
|
|
217
|
-
|
|
218
|
-
请根据要求生成或者更新规则文件(markdown文件),并将规则文件存储在项目的 {{ project_root }}/.autocoderrules 目录,供后续自动化代码生成使用。
|
|
79
|
+
- {{ new_query }}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
最后,新生成的文件格式要是这种形态的:
|
|
83
|
+
|
|
84
|
+
<example_rules>
|
|
85
|
+
---
|
|
86
|
+
description: [简明描述规则的功能,20字以内]
|
|
87
|
+
globs: [匹配应用此规则的文件路径,如"src/services/*.py"]
|
|
88
|
+
alwaysApply: [是否总是应用,通常为false]
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
# [规则主标题]
|
|
92
|
+
|
|
93
|
+
## 简要说明
|
|
94
|
+
[该规则的功能、适用场景和价值,100字以内]
|
|
95
|
+
|
|
96
|
+
## 典型用法
|
|
97
|
+
```python
|
|
98
|
+
# 完整的代码示例,包含:
|
|
99
|
+
# 1. 必要的import语句
|
|
100
|
+
# 2. 类/函数定义
|
|
101
|
+
# 3. 参数说明
|
|
102
|
+
# 4. 调用方式
|
|
103
|
+
# 5. 关键注释
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 依赖说明
|
|
107
|
+
- [必要的依赖库及版本]
|
|
108
|
+
- [环境要求]
|
|
109
|
+
- [初始化流程(如有)]
|
|
110
|
+
|
|
111
|
+
## 学习来源
|
|
112
|
+
[从哪个提交变更的哪部分代码中提取的该功能点]
|
|
113
|
+
</example_rules>
|
|
219
114
|
"""
|
|
220
115
|
return {
|
|
221
116
|
"project_root": os.path.abspath(self.args.source_dir),
|
|
222
|
-
"index_file_content": self._get_index_file_content()
|
|
117
|
+
"index_file_content": self._get_index_file_content(),
|
|
118
|
+
"rules_path": os.path.join(os.path.abspath(self.args.source_dir), ".autocoderrules"),
|
|
119
|
+
"rules_index_path": os.path.join(os.path.abspath(self.args.source_dir), ".autocoderrules", "index.md")
|
|
223
120
|
}
|
|
224
121
|
|
|
225
122
|
@byzerllm.prompt()
|
|
226
123
|
def analyze_modules(self, sources: SourceCodeList, query: str) -> str:
|
|
227
124
|
"""
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
## 任务目标
|
|
231
|
-
- 识别代码中具有普遍应用价值的功能点和模式
|
|
232
|
-
- 将这些功能点提炼为结构化规则,便于在其他项目中快速复用
|
|
233
|
-
- 生成清晰的使用示例,包含完整依赖和调用方式
|
|
234
|
-
- 这些规则将被存储在项目的 {{ project_root }}/.autocoderrules 目录,供后续自动化代码生成使用
|
|
235
|
-
|
|
236
|
-
项目根目录: {{ project_root }}
|
|
237
|
-
|
|
238
|
-
## 分析对象
|
|
239
|
-
{% if sources.sources %}
|
|
240
|
-
分析目标文件:
|
|
241
|
-
{% for source in sources.sources %}
|
|
242
|
-
- {{ source.module_name }}
|
|
243
|
-
{% endfor %}
|
|
244
|
-
{% else %}
|
|
245
|
-
前面提供的文件。
|
|
246
|
-
{% endif %}
|
|
247
|
-
|
|
248
|
-
{% if sources.sources %}
|
|
249
|
-
## 源代码内容
|
|
125
|
+
下面是用户提供的需要抽取规则的代码:
|
|
250
126
|
<files>
|
|
251
127
|
{% for source in sources.sources %}
|
|
252
128
|
##File: {{ source.module_name }}
|
|
253
129
|
{{ source.source_code }}
|
|
254
130
|
{% endfor %}
|
|
255
131
|
</files>
|
|
256
|
-
{% endif %}
|
|
257
|
-
|
|
258
|
-
{% if index_file_content %}
|
|
259
|
-
## 现有索引内容
|
|
260
|
-
index.md 当前内容:
|
|
261
|
-
<files>
|
|
262
|
-
<file>
|
|
263
|
-
##File:
|
|
264
|
-
{{ index_file_content }}
|
|
265
|
-
</file>
|
|
266
|
-
</files>
|
|
267
|
-
{% endif %}
|
|
268
132
|
|
|
269
|
-
|
|
270
|
-
{{ query }}
|
|
271
|
-
|
|
272
|
-
## 生成或者更新的规则文件结构
|
|
133
|
+
请对对上面的代码进行深入分析,提取具有通用价值的功能模式和设计模式,转化为可在其他项目中复用的代码规则(rules)。
|
|
273
134
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# [规则主标题]
|
|
281
|
-
|
|
282
|
-
## 简要说明
|
|
283
|
-
[该规则的功能、适用场景和价值,100字以内]
|
|
284
|
-
|
|
285
|
-
## 典型用法
|
|
286
|
-
```python
|
|
287
|
-
# 完整的代码示例,包含:
|
|
288
|
-
# 1. 必要的import语句
|
|
289
|
-
# 2. 类/函数定义
|
|
290
|
-
# 3. 参数说明
|
|
291
|
-
# 4. 调用方式
|
|
292
|
-
# 5. 关键注释
|
|
293
|
-
|
|
294
|
-
## 依赖说明
|
|
295
|
-
- [必要的依赖库及版本]
|
|
296
|
-
- [环境要求]
|
|
297
|
-
- [初始化流程(如有)]
|
|
298
|
-
|
|
299
|
-
## 学习来源
|
|
300
|
-
[从哪个模块的哪部分代码中提取的该功能点]
|
|
301
|
-
</markdown>
|
|
302
|
-
|
|
303
|
-
## 生成或者更新的规则文件示例
|
|
135
|
+
- 识别代码变更中具有普遍应用价值的功能点和模式
|
|
136
|
+
- 将这些功能点提炼为结构化规则,便于在其他项目中快速复用
|
|
137
|
+
- 生成清晰的使用示例,包含完整依赖和调用方式
|
|
138
|
+
- 这些规则将被存储在项目的 {{ rules_path }} 目录,供后续自动化代码生成使用
|
|
139
|
+
- 更新 {{rules_index_path}} 文件,确保改文件有新增文件的描述信息
|
|
304
140
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
logging.error(f"处理请求时发生错误: {str(e)}")
|
|
346
|
-
context.set_code(grpc.StatusCode.INTERNAL)
|
|
347
|
-
context.set_details(f"服务器内部错误: {str(e)}")
|
|
348
|
-
return service_pb2.Response(
|
|
349
|
-
status=500,
|
|
350
|
-
message=f"处理失败: {str(e)}",
|
|
351
|
-
data={}
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
def _process_business_logic(self, request):
|
|
355
|
-
# 实际业务逻辑处理
|
|
356
|
-
return {"result": request.param1 + request.param2}
|
|
357
|
-
|
|
358
|
-
def serve(port=50051, max_workers=10):
|
|
359
|
-
server = grpc.server(futures.ThreadPoolExecutor(max_workers=max_workers))
|
|
360
|
-
service_pb2_grpc.add_MyServiceServicer_to_server(
|
|
361
|
-
ServiceImplementation(), server
|
|
362
|
-
)
|
|
363
|
-
server.add_insecure_port(f'[::]:{port}')
|
|
364
|
-
server.start()
|
|
365
|
-
logging.info(f"服务已启动,监听端口: {port}")
|
|
366
|
-
|
|
367
|
-
try:
|
|
368
|
-
while True:
|
|
369
|
-
time.sleep(86400) # 一天
|
|
370
|
-
except KeyboardInterrupt:
|
|
371
|
-
server.stop(0)
|
|
372
|
-
logging.info("服务已停止")
|
|
373
|
-
|
|
374
|
-
if __name__ == '__main__':
|
|
375
|
-
logging.basicConfig(level=logging.INFO)
|
|
376
|
-
serve()
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
## 依赖说明
|
|
380
|
-
- 需要安装 grpcio>=1.44.0 和 grpcio-tools>=1.44.0
|
|
381
|
-
- 需要预先定义proto文件并生成对应Python代码:
|
|
382
|
-
```bash
|
|
383
|
-
python -m grpc_tools.protoc -I./protos --python_out=. --grpc_python_out=. ./protos/service.proto
|
|
384
|
-
```
|
|
385
|
-
- 示例proto文件结构:
|
|
386
|
-
```protobuf
|
|
387
|
-
syntax = "proto3";
|
|
388
|
-
|
|
389
|
-
service MyService {
|
|
390
|
-
rpc ProcessRequest (Request) returns (Response) {}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
message Request {
|
|
394
|
-
int32 param1 = 1;
|
|
395
|
-
int32 param2 = 2;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
message Response {
|
|
399
|
-
int32 status = 1;
|
|
400
|
-
string message = 2;
|
|
401
|
-
map<string, string> data = 3;
|
|
402
|
-
}
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
## 学习来源
|
|
406
|
-
从src/services/rpc_service.py模块中的Server类和RequestHandler实现提取
|
|
407
|
-
|
|
408
|
-
## 索引文件更新说明
|
|
409
|
-
|
|
410
|
-
除了生成规则文件外,请务必更新index.md索引文件,记录所有规则及其作用。如果 index.md 当前内容为空,请按如下格式创建:
|
|
411
|
-
|
|
412
|
-
# Rules索引
|
|
413
|
-
|
|
414
|
-
本文档记录项目中所有可用的代码规则(rules)及其用途。
|
|
415
|
-
|
|
416
|
-
## [规则文件路径]
|
|
417
|
-
[规则文件的主要功能和适用场景简述]
|
|
418
|
-
|
|
419
|
-
## 评价标准
|
|
420
|
-
- 提取的功能点必须具备独立价值,能在其他项目中实际复用
|
|
421
|
-
- 代码示例必须完整、可执行,包含所有必要组件
|
|
422
|
-
- 文档结构清晰,遵循规定格式
|
|
423
|
-
- 依赖说明明确具体,便于用户快速配置环境
|
|
424
|
-
|
|
425
|
-
请根据要求生成或者更新规则文件(markdown文件),并将规则文件存储在项目的 {{ project_root }}/.autocoderrules 目录,供后续自动化代码生成使用。
|
|
141
|
+
当前 {{rules_index_path}} 文件内容:
|
|
142
|
+
{% if index_file_content %}
|
|
143
|
+
{{ index_file_content }}
|
|
144
|
+
{% else %}
|
|
145
|
+
<为空>
|
|
146
|
+
{% endif %}
|
|
147
|
+
- {{ query }}
|
|
148
|
+
|
|
149
|
+
最后,新生成的文件格式要是这种形态的:
|
|
150
|
+
|
|
151
|
+
<example_rules>
|
|
152
|
+
---
|
|
153
|
+
description: [简明描述规则的功能,20字以内]
|
|
154
|
+
globs: [匹配应用此规则的文件路径,如"src/services/*.py"]
|
|
155
|
+
alwaysApply: [是否总是应用,通常为false]
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
# [规则主标题]
|
|
159
|
+
|
|
160
|
+
## 简要说明
|
|
161
|
+
[该规则的功能、适用场景和价值,100字以内]
|
|
162
|
+
|
|
163
|
+
## 典型用法
|
|
164
|
+
```python
|
|
165
|
+
# 完整的代码示例,包含:
|
|
166
|
+
# 1. 必要的import语句
|
|
167
|
+
# 2. 类/函数定义
|
|
168
|
+
# 3. 参数说明
|
|
169
|
+
# 4. 调用方式
|
|
170
|
+
# 5. 关键注释
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 依赖说明
|
|
174
|
+
- [必要的依赖库及版本]
|
|
175
|
+
- [环境要求]
|
|
176
|
+
- [初始化流程(如有)]
|
|
177
|
+
|
|
178
|
+
## 学习来源
|
|
179
|
+
[从哪个提交变更的哪部分代码中提取的该功能点]
|
|
180
|
+
</example_rules>
|
|
426
181
|
"""
|
|
427
182
|
|
|
428
183
|
# 获取索引文件内容
|
|
@@ -430,7 +185,9 @@ class AutoLearn:
|
|
|
430
185
|
|
|
431
186
|
return {
|
|
432
187
|
"project_root": os.path.abspath(self.args.source_dir),
|
|
433
|
-
"index_file_content": index_file_content
|
|
188
|
+
"index_file_content": index_file_content,
|
|
189
|
+
"rules_path": os.path.join(os.path.abspath(self.args.source_dir), ".autocoderrules"),
|
|
190
|
+
"rules_index_path": os.path.join(os.path.abspath(self.args.source_dir), ".autocoderrules", "index.md")
|
|
434
191
|
}
|
|
435
192
|
|
|
436
193
|
def get_commit_changes(self, commit_id: str) -> Tuple[List[Tuple[str, List[str], Dict[str, Tuple[str, str]]]], Optional[str]]:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令管理模块
|
|
3
|
+
|
|
4
|
+
该模块提供了一种机制来管理和分析 .autocodercommands 目录中的命令文件。
|
|
5
|
+
主要功能包括:
|
|
6
|
+
1. 列出命令目录中的所有命令文件
|
|
7
|
+
2. 读取指定的命令文件内容
|
|
8
|
+
3. 分析命令文件,提取其中的Jinja2变量
|
|
9
|
+
4. 提供简单直观的API,便于集成到现有的项目中
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from autocoder.common.command_file_manager.models import (
|
|
13
|
+
CommandFile, JinjaVariable, CommandFileAnalysisResult, ListCommandsResult
|
|
14
|
+
)
|
|
15
|
+
from autocoder.common.command_file_manager.manager import CommandManager
|
|
16
|
+
from autocoder.common.command_file_manager.utils import (
|
|
17
|
+
extract_jinja2_variables, extract_jinja2_variables_with_metadata,
|
|
18
|
+
analyze_command_file, is_command_file
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
'CommandFile', 'JinjaVariable', 'CommandFileAnalysisResult', 'ListCommandsResult',
|
|
23
|
+
'CommandManager', 'extract_jinja2_variables', 'extract_jinja2_variables_with_metadata',
|
|
24
|
+
'analyze_command_file', 'is_command_file'
|
|
25
|
+
]
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令管理模块的使用示例
|
|
3
|
+
|
|
4
|
+
展示如何使用命令管理模块的主要功能。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
from typing import Dict, Set, List
|
|
11
|
+
|
|
12
|
+
from autocoder.common.command_manager import (
|
|
13
|
+
CommandManager, CommandFile, JinjaVariable, CommandFileAnalysisResult
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def setup_test_environment():
|
|
18
|
+
"""设置测试环境,创建示例命令文件"""
|
|
19
|
+
# 创建临时命令目录
|
|
20
|
+
test_dir = os.path.join(os.path.dirname(__file__), "test_commands")
|
|
21
|
+
os.makedirs(test_dir, exist_ok=True)
|
|
22
|
+
|
|
23
|
+
# 创建示例命令文件
|
|
24
|
+
example1 = os.path.join(test_dir, "example1.autocodercommand")
|
|
25
|
+
with open(example1, "w") as f:
|
|
26
|
+
f.write("""
|
|
27
|
+
{# @var: project_name, default: MyProject, description: 项目名称 #}
|
|
28
|
+
{# @var: author, default: User, description: 作者姓名 #}
|
|
29
|
+
# {{ project_name }}
|
|
30
|
+
|
|
31
|
+
这是一个由 {{ author }} 创建的项目。
|
|
32
|
+
|
|
33
|
+
{% if include_license %}
|
|
34
|
+
## 许可证
|
|
35
|
+
本项目使用 {{ license_type }} 许可证。
|
|
36
|
+
{% endif %}
|
|
37
|
+
""")
|
|
38
|
+
|
|
39
|
+
# 创建子目录和另一个示例文件
|
|
40
|
+
sub_dir = os.path.join(test_dir, "subdir")
|
|
41
|
+
os.makedirs(sub_dir, exist_ok=True)
|
|
42
|
+
|
|
43
|
+
example2 = os.path.join(sub_dir, "example2.j2")
|
|
44
|
+
with open(example2, "w") as f:
|
|
45
|
+
f.write("""
|
|
46
|
+
# {{ project_name }} 配置
|
|
47
|
+
|
|
48
|
+
version: {{ version }}
|
|
49
|
+
environment: {{ env }}
|
|
50
|
+
""")
|
|
51
|
+
|
|
52
|
+
return test_dir
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def list_command_files_example(manager: CommandManager):
|
|
56
|
+
"""列出命令文件示例"""
|
|
57
|
+
print("\n=== 列出命令文件 ===")
|
|
58
|
+
|
|
59
|
+
# 不递归列出
|
|
60
|
+
print("不递归列出:")
|
|
61
|
+
result = manager.list_command_files(recursive=False)
|
|
62
|
+
if result.success:
|
|
63
|
+
for file in result.command_files:
|
|
64
|
+
print(f"- {file}")
|
|
65
|
+
else:
|
|
66
|
+
print(f"错误: {result.errors}")
|
|
67
|
+
|
|
68
|
+
# 递归列出
|
|
69
|
+
print("\n递归列出:")
|
|
70
|
+
result = manager.list_command_files(recursive=True)
|
|
71
|
+
if result.success:
|
|
72
|
+
for file in result.command_files:
|
|
73
|
+
print(f"- {file}")
|
|
74
|
+
else:
|
|
75
|
+
print(f"错误: {result.errors}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def read_command_file_example(manager: CommandManager):
|
|
79
|
+
"""读取命令文件示例"""
|
|
80
|
+
print("\n=== 读取命令文件 ===")
|
|
81
|
+
|
|
82
|
+
# 读取第一个示例文件
|
|
83
|
+
command_file = manager.read_command_file("example1.autocodercommand")
|
|
84
|
+
if command_file:
|
|
85
|
+
print(f"文件名: {command_file.file_name}")
|
|
86
|
+
print(f"文件路径: {command_file.file_path}")
|
|
87
|
+
print("文件内容:")
|
|
88
|
+
print(command_file.content)
|
|
89
|
+
else:
|
|
90
|
+
print("文件不存在或读取失败")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def analyze_command_file_example(manager: CommandManager):
|
|
94
|
+
"""分析命令文件示例"""
|
|
95
|
+
print("\n=== 分析命令文件 ===")
|
|
96
|
+
|
|
97
|
+
# 分析第一个示例文件
|
|
98
|
+
analysis = manager.analyze_command_file("example1.autocodercommand")
|
|
99
|
+
if analysis:
|
|
100
|
+
print(f"文件名: {analysis.file_name}")
|
|
101
|
+
print(f"原始变量: {', '.join(analysis.raw_variables)}")
|
|
102
|
+
print("变量详情:")
|
|
103
|
+
for var in analysis.variables:
|
|
104
|
+
print(f" - {var.name}")
|
|
105
|
+
if var.default_value:
|
|
106
|
+
print(f" 默认值: {var.default_value}")
|
|
107
|
+
if var.description:
|
|
108
|
+
print(f" 描述: {var.description}")
|
|
109
|
+
else:
|
|
110
|
+
print("文件分析失败")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_all_variables_example(manager: CommandManager):
|
|
114
|
+
"""获取所有变量示例"""
|
|
115
|
+
print("\n=== 获取所有变量 ===")
|
|
116
|
+
|
|
117
|
+
# 获取所有命令文件中的变量
|
|
118
|
+
variables_map = manager.get_all_variables(recursive=True)
|
|
119
|
+
for file, variables in variables_map.items():
|
|
120
|
+
print(f"文件: {file}")
|
|
121
|
+
print(f"变量: {', '.join(variables)}")
|
|
122
|
+
print()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def main():
|
|
126
|
+
"""主函数"""
|
|
127
|
+
# 设置测试环境
|
|
128
|
+
test_dir = setup_test_environment()
|
|
129
|
+
print(f"测试目录: {test_dir}")
|
|
130
|
+
|
|
131
|
+
# 创建命令管理器
|
|
132
|
+
manager = CommandManager(test_dir)
|
|
133
|
+
|
|
134
|
+
# 运行示例
|
|
135
|
+
list_command_files_example(manager)
|
|
136
|
+
read_command_file_example(manager)
|
|
137
|
+
analyze_command_file_example(manager)
|
|
138
|
+
get_all_variables_example(manager)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
main()
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令管理器
|
|
3
|
+
|
|
4
|
+
整个模块的主入口,提供高层次的API接口,用于列出、读取和分析命令文件。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Dict, List, Optional, Set, Tuple
|
|
10
|
+
|
|
11
|
+
from autocoder.common.command_file_manager.models import (
|
|
12
|
+
CommandFile, JinjaVariable, CommandFileAnalysisResult, ListCommandsResult
|
|
13
|
+
)
|
|
14
|
+
from autocoder.common.command_file_manager.utils import (
|
|
15
|
+
extract_jinja2_variables, extract_jinja2_variables_with_metadata,
|
|
16
|
+
analyze_command_file, is_command_file
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CommandManager:
|
|
23
|
+
"""命令管理器,提供高层次的API接口"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, commands_dir: str):
|
|
26
|
+
"""
|
|
27
|
+
初始化命令管理器
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
commands_dir: 命令文件目录路径
|
|
31
|
+
"""
|
|
32
|
+
self.commands_dir = os.path.abspath(commands_dir)
|
|
33
|
+
|
|
34
|
+
# 确保目录存在
|
|
35
|
+
if not os.path.exists(self.commands_dir):
|
|
36
|
+
logger.warning(f"命令目录不存在: {self.commands_dir}")
|
|
37
|
+
os.makedirs(self.commands_dir, exist_ok=True)
|
|
38
|
+
logger.info(f"已创建命令目录: {self.commands_dir}")
|
|
39
|
+
|
|
40
|
+
def list_command_files(self, recursive: bool = False) -> ListCommandsResult:
|
|
41
|
+
"""
|
|
42
|
+
列出命令目录中的所有命令文件
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
recursive: 是否递归搜索子目录
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
ListCommandsResult: 列出结果
|
|
49
|
+
"""
|
|
50
|
+
result = ListCommandsResult(success=True)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
if recursive:
|
|
54
|
+
for root, _, files in os.walk(self.commands_dir):
|
|
55
|
+
for file in files:
|
|
56
|
+
if is_command_file(file):
|
|
57
|
+
file_path = os.path.join(root, file)
|
|
58
|
+
rel_path = os.path.relpath(file_path, self.commands_dir)
|
|
59
|
+
result.add_command_file(rel_path)
|
|
60
|
+
else:
|
|
61
|
+
for item in os.listdir(self.commands_dir):
|
|
62
|
+
item_path = os.path.join(self.commands_dir, item)
|
|
63
|
+
if os.path.isfile(item_path) and is_command_file(item):
|
|
64
|
+
result.add_command_file(item)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(f"列出命令文件时出错: {str(e)}")
|
|
67
|
+
result.add_error(self.commands_dir, f"列出命令文件时出错: {str(e)}")
|
|
68
|
+
|
|
69
|
+
return result
|
|
70
|
+
|
|
71
|
+
def read_command_file(self, file_name: str) -> Optional[CommandFile]:
|
|
72
|
+
"""
|
|
73
|
+
读取指定的命令文件
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
file_name: 命令文件名或相对路径
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Optional[CommandFile]: 命令文件对象,如果文件不存在则返回None
|
|
80
|
+
"""
|
|
81
|
+
file_path = os.path.join(self.commands_dir, file_name)
|
|
82
|
+
|
|
83
|
+
if not os.path.isfile(file_path):
|
|
84
|
+
logger.warning(f"命令文件不存在: {file_path}")
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
89
|
+
content = f.read()
|
|
90
|
+
|
|
91
|
+
return CommandFile(
|
|
92
|
+
file_path=file_path,
|
|
93
|
+
file_name=os.path.basename(file_path),
|
|
94
|
+
content=content
|
|
95
|
+
)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"读取命令文件时出错: {str(e)}")
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
def analyze_command_file(self, file_name: str) -> Optional[CommandFileAnalysisResult]:
|
|
101
|
+
"""
|
|
102
|
+
分析指定的命令文件,提取其中的Jinja2变量
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
file_name: 命令文件名或相对路径
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Optional[CommandFileAnalysisResult]: 分析结果,如果文件不存在则返回None
|
|
109
|
+
"""
|
|
110
|
+
command_file = self.read_command_file(file_name)
|
|
111
|
+
if command_file is None:
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
return analyze_command_file(command_file.file_path, command_file.content)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(f"分析命令文件时出错: {str(e)}")
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
def get_all_variables(self, recursive: bool = False) -> Dict[str, Set[str]]:
|
|
121
|
+
"""
|
|
122
|
+
获取所有命令文件中的变量
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
recursive: 是否递归搜索子目录
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Dict[str, Set[str]]: 文件路径到变量集合的映射
|
|
129
|
+
"""
|
|
130
|
+
result: Dict[str, Set[str]] = {}
|
|
131
|
+
|
|
132
|
+
list_result = self.list_command_files(recursive)
|
|
133
|
+
if not list_result.success:
|
|
134
|
+
logger.error("获取命令文件列表失败")
|
|
135
|
+
return result
|
|
136
|
+
|
|
137
|
+
for file_name in list_result.command_files:
|
|
138
|
+
command_file = self.read_command_file(file_name)
|
|
139
|
+
if command_file is None:
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
variables = extract_jinja2_variables(command_file.content)
|
|
144
|
+
result[file_name] = variables
|
|
145
|
+
except Exception as e:
|
|
146
|
+
logger.error(f"提取文件 {file_name} 的变量时出错: {str(e)}")
|
|
147
|
+
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
def get_command_file_path(self, file_name: str) -> str:
|
|
151
|
+
"""
|
|
152
|
+
获取命令文件的完整路径
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
file_name: 命令文件名或相对路径
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
str: 命令文件的完整路径
|
|
159
|
+
"""
|
|
160
|
+
return os.path.join(self.commands_dir, file_name)
|
|
161
|
+
|
|
162
|
+
def _get_absolute_path(self, file_path: str) -> str:
|
|
163
|
+
"""
|
|
164
|
+
获取文件的绝对路径
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
file_path: 文件相对路径或绝对路径
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
str: 文件的绝对路径
|
|
171
|
+
"""
|
|
172
|
+
if os.path.isabs(file_path):
|
|
173
|
+
return file_path
|
|
174
|
+
else:
|
|
175
|
+
return os.path.join(self.commands_dir, file_path)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令管理模块的数据模型
|
|
3
|
+
|
|
4
|
+
定义了表示命令文件、命令内容和操作结果的数据类。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Dict, List, Optional, Set
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class CommandFile:
|
|
15
|
+
"""表示单个命令文件的信息"""
|
|
16
|
+
file_path: str
|
|
17
|
+
file_name: str
|
|
18
|
+
content: str
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_dict(cls, data: Dict) -> 'CommandFile':
|
|
22
|
+
"""从字典创建CommandFile对象"""
|
|
23
|
+
return cls(
|
|
24
|
+
file_path=data['file_path'],
|
|
25
|
+
file_name=data['file_name'],
|
|
26
|
+
content=data['content']
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def to_dict(self) -> Dict:
|
|
30
|
+
"""将CommandFile对象转换为字典"""
|
|
31
|
+
return {
|
|
32
|
+
'file_path': self.file_path,
|
|
33
|
+
'file_name': self.file_name,
|
|
34
|
+
'content': self.content
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class JinjaVariable:
|
|
40
|
+
"""表示从命令文件中提取的Jinja2变量"""
|
|
41
|
+
name: str
|
|
42
|
+
default_value: Optional[str] = None
|
|
43
|
+
description: Optional[str] = None
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def from_dict(cls, data: Dict) -> 'JinjaVariable':
|
|
47
|
+
"""从字典创建JinjaVariable对象"""
|
|
48
|
+
return cls(
|
|
49
|
+
name=data['name'],
|
|
50
|
+
default_value=data.get('default_value'),
|
|
51
|
+
description=data.get('description')
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> Dict:
|
|
55
|
+
"""将JinjaVariable对象转换为字典"""
|
|
56
|
+
return {
|
|
57
|
+
'name': self.name,
|
|
58
|
+
'default_value': self.default_value,
|
|
59
|
+
'description': self.description
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class CommandFileAnalysisResult:
|
|
65
|
+
"""表示命令文件分析的结果"""
|
|
66
|
+
file_path: str
|
|
67
|
+
file_name: str
|
|
68
|
+
variables: List[JinjaVariable] = field(default_factory=list)
|
|
69
|
+
raw_variables: Set[str] = field(default_factory=set)
|
|
70
|
+
|
|
71
|
+
def add_variable(self, variable: JinjaVariable) -> None:
|
|
72
|
+
"""添加一个变量"""
|
|
73
|
+
self.variables.append(variable)
|
|
74
|
+
self.raw_variables.add(variable.name)
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_dict(cls, data: Dict) -> 'CommandFileAnalysisResult':
|
|
78
|
+
"""从字典创建CommandFileAnalysisResult对象"""
|
|
79
|
+
result = cls(
|
|
80
|
+
file_path=data['file_path'],
|
|
81
|
+
file_name=data['file_name'],
|
|
82
|
+
raw_variables=set(data.get('raw_variables', []))
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
for var_data in data.get('variables', []):
|
|
86
|
+
result.variables.append(JinjaVariable.from_dict(var_data))
|
|
87
|
+
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> Dict:
|
|
91
|
+
"""将CommandFileAnalysisResult对象转换为字典"""
|
|
92
|
+
return {
|
|
93
|
+
'file_path': self.file_path,
|
|
94
|
+
'file_name': self.file_name,
|
|
95
|
+
'variables': [var.to_dict() for var in self.variables],
|
|
96
|
+
'raw_variables': list(self.raw_variables)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class ListCommandsResult:
|
|
102
|
+
"""表示列出命令文件的结果"""
|
|
103
|
+
success: bool
|
|
104
|
+
command_files: List[str] = field(default_factory=list)
|
|
105
|
+
errors: Dict[str, str] = field(default_factory=dict)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def has_errors(self) -> bool:
|
|
109
|
+
"""是否有错误"""
|
|
110
|
+
return len(self.errors) > 0
|
|
111
|
+
|
|
112
|
+
def add_error(self, path: str, error_message: str) -> None:
|
|
113
|
+
"""添加错误信息"""
|
|
114
|
+
self.errors[path] = error_message
|
|
115
|
+
self.success = False
|
|
116
|
+
|
|
117
|
+
def add_command_file(self, file_path: str) -> None:
|
|
118
|
+
"""添加命令文件路径"""
|
|
119
|
+
self.command_files.append(file_path)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
命令管理模块的工具函数
|
|
3
|
+
|
|
4
|
+
提供用于处理命令文件和提取Jinja2变量的工具函数。
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
from typing import List, Set, Dict, Optional, Tuple
|
|
10
|
+
|
|
11
|
+
from autocoder.common.command_file_manager.models import JinjaVariable, CommandFileAnalysisResult
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def extract_jinja2_variables(content: str) -> Set[str]:
|
|
15
|
+
"""
|
|
16
|
+
从文本内容中提取Jinja2变量名
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
content: 文本内容
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Set[str]: 变量名集合
|
|
23
|
+
"""
|
|
24
|
+
# 匹配 {{ variable }} 格式的变量
|
|
25
|
+
pattern = r'{{\s*([a-zA-Z0-9_]+)\s*}}'
|
|
26
|
+
variables = set(re.findall(pattern, content))
|
|
27
|
+
|
|
28
|
+
# 匹配 {% if variable %} 等控制结构中的变量
|
|
29
|
+
control_pattern = r'{%\s*(?:if|for|elif|unless)\s+(?:not\s+)?([a-zA-Z0-9_]+)'
|
|
30
|
+
control_vars = set(re.findall(control_pattern, content))
|
|
31
|
+
|
|
32
|
+
# 合并结果
|
|
33
|
+
variables.update(control_vars)
|
|
34
|
+
|
|
35
|
+
return variables
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def extract_jinja2_variables_with_metadata(content: str) -> List[JinjaVariable]:
|
|
39
|
+
"""
|
|
40
|
+
从文本内容中提取Jinja2变量及其元数据(如默认值和描述)
|
|
41
|
+
|
|
42
|
+
此函数会查找特殊注释格式来提取变量的元数据:
|
|
43
|
+
{# @var: variable_name, default: default_value, description: variable description #}
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
content: 文本内容
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List[JinjaVariable]: 变量对象列表
|
|
50
|
+
"""
|
|
51
|
+
# 首先提取所有原始变量名
|
|
52
|
+
raw_variables = extract_jinja2_variables(content)
|
|
53
|
+
|
|
54
|
+
# 查找变量元数据注释
|
|
55
|
+
metadata_pattern = r'{#\s*@var:\s*([a-zA-Z0-9_]+)(?:\s*,\s*default:\s*([^,]+))?(?:\s*,\s*description:\s*([^#]+))?\s*#}'
|
|
56
|
+
metadata_matches = re.finditer(metadata_pattern, content)
|
|
57
|
+
|
|
58
|
+
# 创建变量字典,键为变量名
|
|
59
|
+
variables_dict: Dict[str, JinjaVariable] = {}
|
|
60
|
+
|
|
61
|
+
# 处理元数据注释
|
|
62
|
+
for match in metadata_matches:
|
|
63
|
+
var_name = match.group(1).strip()
|
|
64
|
+
default_value = match.group(2).strip() if match.group(2) else None
|
|
65
|
+
description = match.group(3).strip() if match.group(3) else None
|
|
66
|
+
|
|
67
|
+
variables_dict[var_name] = JinjaVariable(
|
|
68
|
+
name=var_name,
|
|
69
|
+
default_value=default_value,
|
|
70
|
+
description=description
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# 为没有元数据的变量创建基本对象
|
|
74
|
+
for var_name in raw_variables:
|
|
75
|
+
if var_name not in variables_dict:
|
|
76
|
+
variables_dict[var_name] = JinjaVariable(name=var_name)
|
|
77
|
+
|
|
78
|
+
return list(variables_dict.values())
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def analyze_command_file(file_path: str, file_content: str) -> CommandFileAnalysisResult:
|
|
82
|
+
"""
|
|
83
|
+
分析命令文件,提取其中的Jinja2变量
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
file_path: 文件路径
|
|
87
|
+
file_content: 文件内容
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
CommandFileAnalysisResult: 分析结果
|
|
91
|
+
"""
|
|
92
|
+
file_name = os.path.basename(file_path)
|
|
93
|
+
|
|
94
|
+
# 提取变量及其元数据
|
|
95
|
+
variables = extract_jinja2_variables_with_metadata(file_content)
|
|
96
|
+
raw_variable_names = extract_jinja2_variables(file_content)
|
|
97
|
+
|
|
98
|
+
# 创建分析结果
|
|
99
|
+
result = CommandFileAnalysisResult(
|
|
100
|
+
file_path=file_path,
|
|
101
|
+
file_name=file_name,
|
|
102
|
+
variables=variables,
|
|
103
|
+
raw_variables=raw_variable_names
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
return result
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def is_command_file(file_name: str) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
检查文件是否为命令文件
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
file_name: 文件名
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
bool: 是否为命令文件
|
|
118
|
+
"""
|
|
119
|
+
return file_name.endswith('.md')
|
autocoder/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.370"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|