jarvis-ai-assistant 0.1.97__py3-none-any.whl → 0.1.98__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 jarvis-ai-assistant might be problematic. Click here for more details.

@@ -20,14 +20,14 @@ index_lock = threading.Lock()
20
20
 
21
21
  class JarvisCoder:
22
22
  def __init__(self, root_dir: str, language: Optional[str] = "python"):
23
- """初始化代码修改工具"""
23
+ """Initialize code modification tool"""
24
24
  self.root_dir = root_dir
25
25
  self.language = language
26
26
  self._init_directories()
27
27
  self._init_codebase()
28
28
 
29
29
  def _init_directories(self):
30
- """初始化目录"""
30
+ """Initialize directories"""
31
31
  self.max_context_length = get_max_context_length()
32
32
 
33
33
  root_dir = find_git_root(self.root_dir)
@@ -36,9 +36,9 @@ class JarvisCoder:
36
36
 
37
37
  self.root_dir = root_dir
38
38
 
39
- PrettyOutput.print(f"Git根目录: {self.root_dir}", OutputType.INFO)
39
+ PrettyOutput.print(f"Git root directory: {self.root_dir}", OutputType.INFO)
40
40
 
41
- # 1. 判断代码库路径是否存在,如果不存在,创建
41
+ # 1. Check if the code repository path exists, if it does not exist, create it
42
42
  if not os.path.exists(self.root_dir):
43
43
  PrettyOutput.print(
44
44
  "Root directory does not exist, creating...", OutputType.INFO)
@@ -46,7 +46,7 @@ class JarvisCoder:
46
46
 
47
47
  os.chdir(self.root_dir)
48
48
 
49
- # 2. 创建 .jarvis-coder 目录
49
+ # 2. Create .jarvis-coder directory
50
50
  self.jarvis_dir = os.path.join(self.root_dir, ".jarvis-coder")
51
51
  if not os.path.exists(self.jarvis_dir):
52
52
  os.makedirs(self.jarvis_dir)
@@ -55,157 +55,157 @@ class JarvisCoder:
55
55
  if not os.path.exists(self.record_dir):
56
56
  os.makedirs(self.record_dir)
57
57
 
58
- # 3. 处理 .gitignore 文件
58
+ # 3. Process .gitignore file
59
59
  gitignore_path = os.path.join(self.root_dir, ".gitignore")
60
60
  gitignore_modified = False
61
61
  jarvis_ignore_pattern = ".jarvis-*"
62
62
 
63
- # 3.1 如果 .gitignore 不存在,创建它
63
+ # 3.1 If .gitignore does not exist, create it
64
64
  if not os.path.exists(gitignore_path):
65
- PrettyOutput.print("创建 .gitignore 文件", OutputType.INFO)
65
+ PrettyOutput.print("Create .gitignore file", OutputType.INFO)
66
66
  with open(gitignore_path, "w", encoding="utf-8") as f:
67
67
  f.write(f"{jarvis_ignore_pattern}\n")
68
68
  gitignore_modified = True
69
69
  else:
70
- # 3.2 检查是否已经包含 .jarvis-* 模式
70
+ # 3.2 Check if it already contains the .jarvis-* pattern
71
71
  with open(gitignore_path, "r", encoding="utf-8") as f:
72
72
  content = f.read()
73
73
 
74
- # 检查是否需要添加 .jarvis-* 模式
74
+ # 3.2 Check if it already contains the .jarvis-* pattern
75
75
  if jarvis_ignore_pattern not in content.split("\n"):
76
- PrettyOutput.print(" .jarvis-* 添加到 .gitignore", OutputType.INFO)
76
+ PrettyOutput.print("Add .jarvis-* to .gitignore", OutputType.INFO)
77
77
  with open(gitignore_path, "a", encoding="utf-8") as f:
78
- # 确保文件以换行符结尾
78
+ # Ensure the file ends with a newline
79
79
  if not content.endswith("\n"):
80
80
  f.write("\n")
81
81
  f.write(f"{jarvis_ignore_pattern}\n")
82
82
  gitignore_modified = True
83
83
 
84
- # 4. 判断代码库是否是git仓库,如果不是,初始化git仓库
84
+ # 4. Check if the code repository is a git repository, if not, initialize the git repository
85
85
  if not os.path.exists(os.path.join(self.root_dir, ".git")):
86
- PrettyOutput.print("初始化 Git 仓库", OutputType.INFO)
86
+ PrettyOutput.print("Initialize Git repository", OutputType.INFO)
87
87
  os.system("git init")
88
88
  os.system("git add .")
89
89
  os.system("git commit -m 'Initial commit'")
90
- # 5. 如果修改了 .gitignore,提交更改
90
+ # 5. If .gitignore is modified, commit the changes
91
91
  elif gitignore_modified:
92
- PrettyOutput.print("提交 .gitignore 更改", OutputType.INFO)
92
+ PrettyOutput.print("Commit .gitignore changes", OutputType.INFO)
93
93
  os.system("git add .gitignore")
94
94
  os.system("git commit -m 'chore: update .gitignore to exclude .jarvis-* files'")
95
- # 6. 查看代码库是否有未提交的文件,如果有,提交一次
95
+ # 6. Check if there are uncommitted files in the code repository, if there are, commit once
96
96
  elif self._has_uncommitted_files():
97
- PrettyOutput.print("提交未保存的更改", OutputType.INFO)
97
+ PrettyOutput.print("Commit uncommitted changes", OutputType.INFO)
98
98
  os.system("git add .")
99
99
  git_diff = os.popen("git diff --cached").read()
100
100
  commit_message = generate_commit_message(git_diff)
101
101
  os.system(f"git commit -m '{commit_message}'")
102
102
 
103
103
  def _init_codebase(self):
104
- """初始化代码库"""
104
+ """Initialize codebase"""
105
105
  self._codebase = CodeBase(self.root_dir)
106
106
 
107
107
  def _has_uncommitted_files(self) -> bool:
108
- """判断代码库是否有未提交的文件"""
109
- # 获取未暂存的修改
108
+ """Check if there are uncommitted files in the code repository"""
109
+ # Get unstaged modifications
110
110
  unstaged = os.popen("git diff --name-only").read()
111
- # 获取已暂存但未提交的修改
111
+ # Get staged but uncommitted modifications
112
112
  staged = os.popen("git diff --cached --name-only").read()
113
- # 获取未跟踪的文件
113
+ # Get untracked files
114
114
  untracked = os.popen("git ls-files --others --exclude-standard").read()
115
115
 
116
116
  return bool(unstaged or staged or untracked)
117
117
 
118
118
  def _prepare_execution(self) -> None:
119
- """准备执行环境"""
119
+ """Prepare execution environment"""
120
120
  self._codebase.generate_codebase()
121
121
 
122
122
 
123
123
  def _load_related_files(self, feature: str) -> List[Dict]:
124
- """加载相关文件内容"""
124
+ """Load related file content"""
125
125
  ret = []
126
- # 确保索引数据库已生成
126
+ # Ensure the index database is generated
127
127
  if not self._codebase.is_index_generated():
128
- PrettyOutput.print("检测到索引数据库未生成,正在生成...", OutputType.WARNING)
128
+ PrettyOutput.print("Index database not generated, generating...", OutputType.WARNING)
129
129
  self._codebase.generate_codebase()
130
130
 
131
131
  related_files = self._codebase.search_similar(feature)
132
132
  for file, score in related_files:
133
- PrettyOutput.print(f"相关文件: {file} 相关度: {score:.3f}", OutputType.SUCCESS)
133
+ PrettyOutput.print(f"Related file: {file} (score: {score:.3f})", OutputType.SUCCESS)
134
134
  content = open(file, "r", encoding="utf-8").read()
135
135
  ret.append({"file_path": file, "file_content": content})
136
136
  return ret
137
137
 
138
138
  def _parse_file_selection(self, input_str: str, max_index: int) -> List[int]:
139
- """解析文件选择表达式
139
+ """Parse file selection expression
140
140
 
141
- 支持的格式:
142
- - 单个数字: "1"
143
- - 逗号分隔: "1,3,5"
144
- - 范围: "1-5"
145
- - 组合: "1,3-5,7"
141
+ Supported formats:
142
+ - Single number: "1"
143
+ - Comma-separated: "1,3,5"
144
+ - Range: "1-5"
145
+ - Combination: "1,3-5,7"
146
146
 
147
147
  Args:
148
- input_str: 用户输入的选择表达式
149
- max_index: 最大可选择的索引
148
+ input_str: User input selection expression
149
+ max_index: Maximum selectable index
150
150
 
151
151
  Returns:
152
- List[int]: 选中的索引列表(从0开始)
152
+ List[int]: Selected index list (starting from 0)
153
153
  """
154
154
  selected = set()
155
155
 
156
- # 移除所有空白字符
156
+ # Remove all whitespace characters
157
157
  input_str = "".join(input_str.split())
158
158
 
159
- # 处理逗号分隔的部分
159
+ # Process comma-separated parts
160
160
  for part in input_str.split(","):
161
161
  if not part:
162
162
  continue
163
163
 
164
- # 处理范围(例如:3-6
164
+ # Process range (e.g.: 3-6)
165
165
  if "-" in part:
166
166
  try:
167
167
  start, end = map(int, part.split("-"))
168
- # 转换为从0开始的索引
168
+ # Convert to index starting from 0
169
169
  start = max(0, start - 1)
170
170
  end = min(max_index, end - 1)
171
171
  if start <= end:
172
172
  selected.update(range(start, end + 1))
173
173
  except ValueError:
174
- PrettyOutput.print(f"忽略无效的范围表达式: {part}", OutputType.WARNING)
175
- # 处理单个数字
174
+ PrettyOutput.print(f"Ignore invalid range expression: {part}", OutputType.WARNING)
175
+ # Process single number
176
176
  else:
177
177
  try:
178
- index = int(part) - 1 # 转换为从0开始的索引
178
+ index = int(part) - 1 # Convert to index starting from 0
179
179
  if 0 <= index < max_index:
180
180
  selected.add(index)
181
181
  else:
182
- PrettyOutput.print(f"忽略超出范围的索引: {part}", OutputType.WARNING)
182
+ PrettyOutput.print(f"Ignore index out of range: {part}", OutputType.WARNING)
183
183
  except ValueError:
184
- PrettyOutput.print(f"忽略无效的数字: {part}", OutputType.WARNING)
184
+ PrettyOutput.print(f"Ignore invalid number: {part}", OutputType.WARNING)
185
185
 
186
186
  return sorted(list(selected))
187
187
 
188
188
  def _get_file_completer(self) -> Completer:
189
- """创建文件路径补全器"""
189
+ """Create file path completer"""
190
190
  class FileCompleter(Completer):
191
191
  def __init__(self, root_dir: str):
192
192
  self.root_dir = root_dir
193
193
 
194
194
  def get_completions(self, document, complete_event):
195
- # 获取当前输入的文本
195
+ # Get the text of the current input
196
196
  text = document.text_before_cursor
197
197
 
198
- # 如果输入为空,返回根目录下的所有文件
198
+ # If the input is empty, return all files in the root directory
199
199
  if not text:
200
200
  for path in self._list_files(""):
201
201
  yield Completion(path, start_position=0)
202
202
  return
203
203
 
204
- # 获取当前目录和部分文件名
204
+ # Get the current directory and partial file name
205
205
  current_dir = os.path.dirname(text)
206
206
  file_prefix = os.path.basename(text)
207
207
 
208
- # 列出匹配的文件
208
+ # List matching files
209
209
  search_dir = os.path.join(self.root_dir, current_dir) if current_dir else self.root_dir
210
210
  if os.path.isdir(search_dir):
211
211
  for path in self._list_files(current_dir):
@@ -213,7 +213,7 @@ class JarvisCoder:
213
213
  yield Completion(path, start_position=-len(text))
214
214
 
215
215
  def _list_files(self, current_dir: str) -> List[str]:
216
- """列出指定目录下的所有文件(递归)"""
216
+ """List all files in the specified directory (recursively)"""
217
217
  files = []
218
218
  search_dir = os.path.join(self.root_dir, current_dir)
219
219
 
@@ -221,7 +221,7 @@ class JarvisCoder:
221
221
  for filename in filenames:
222
222
  full_path = os.path.join(root, filename)
223
223
  rel_path = os.path.relpath(full_path, self.root_dir)
224
- # 忽略 .git 目录和其他隐藏文件
224
+ # Ignore .git directory and other hidden files
225
225
  if not any(part.startswith('.') for part in rel_path.split(os.sep)):
226
226
  files.append(rel_path)
227
227
 
@@ -230,13 +230,13 @@ class JarvisCoder:
230
230
  return FileCompleter(self.root_dir)
231
231
 
232
232
  def _fuzzy_match_files(self, pattern: str) -> List[str]:
233
- """模糊匹配文件路径
233
+ """Fuzzy match file path
234
234
 
235
235
  Args:
236
- pattern: 匹配模式
236
+ pattern: Matching pattern
237
237
 
238
238
  Returns:
239
- List[str]: 匹配的文件路径列表
239
+ List[str]: List of matching file paths
240
240
  """
241
241
  matches = []
242
242
 
@@ -258,38 +258,38 @@ class JarvisCoder:
258
258
  return sorted(matches)
259
259
 
260
260
  def _select_files(self, related_files: List[Dict]) -> List[Dict]:
261
- """让用户选择和补充相关文件"""
262
- PrettyOutput.section("相关文件", OutputType.INFO)
261
+ """Let the user select and supplement related files"""
262
+ PrettyOutput.section("Related files", OutputType.INFO)
263
263
 
264
- # 显示找到的文件
265
- selected_files = list(related_files) # 默认全选
264
+ # Display found files
265
+ selected_files = list(related_files) # Default select all
266
266
  for i, file in enumerate(related_files, 1):
267
267
  PrettyOutput.print(f"[{i}] {file['file_path']}", OutputType.INFO)
268
268
 
269
- # 询问用户是否需要调整
270
- user_input = input("\n是否需要调整文件列表?(y/n) [n]: ").strip().lower() or 'n'
269
+ # Ask the user if they need to adjust the file list
270
+ user_input = input("\nDo you need to adjust the file list? (y/n) [n]: ").strip().lower() or 'n'
271
271
  if user_input == 'y':
272
- # 让用户选择文件
273
- PrettyOutput.print("\n请输入要包含的文件编号(支持: 1,3-6 格式,直接回车保持当前选择):", OutputType.INFO)
272
+ # Let the user select files
273
+ PrettyOutput.print("\nPlease enter the file numbers to include (support: 1,3-6 format, press Enter to keep the current selection):", OutputType.INFO)
274
274
  numbers = input(">>> ").strip()
275
275
  if numbers:
276
276
  selected_indices = self._parse_file_selection(numbers, len(related_files))
277
277
  if selected_indices:
278
278
  selected_files = [related_files[i] for i in selected_indices]
279
279
  else:
280
- PrettyOutput.print("未选择任何有效文件,保持原有选择", OutputType.WARNING)
280
+ PrettyOutput.print("No valid files selected, keep the current selection", OutputType.WARNING)
281
281
 
282
- # 询问是否需要补充文件
283
- user_input = input("\n是否需要补充其他文件?(y/n) [n]: ").strip().lower() or 'n'
282
+ # Ask if they need to supplement files
283
+ user_input = input("\nDo you need to supplement other files? (y/n) [n]: ").strip().lower() or 'n'
284
284
  if user_input == 'y':
285
- # 创建文件补全会话
285
+ # Create file completion session
286
286
  session = PromptSession(
287
287
  completer=self._get_file_completer(),
288
288
  complete_while_typing=True
289
289
  )
290
290
 
291
291
  while True:
292
- PrettyOutput.print("\n请输入要补充的文件路径(支持Tab补全和*?通配符,输入空行结束):", OutputType.INFO)
292
+ PrettyOutput.print("\nPlease enter the file path to supplement (support Tab completion and *? wildcard, input empty line to end):", OutputType.INFO)
293
293
  try:
294
294
  file_path = session.prompt(">>> ").strip()
295
295
  except KeyboardInterrupt:
@@ -298,20 +298,20 @@ class JarvisCoder:
298
298
  if not file_path:
299
299
  break
300
300
 
301
- # 处理通配符匹配
301
+ # Process wildcard matching
302
302
  if '*' in file_path or '?' in file_path:
303
303
  matches = self._fuzzy_match_files(file_path)
304
304
  if not matches:
305
- PrettyOutput.print("未找到匹配的文件", OutputType.WARNING)
305
+ PrettyOutput.print("No matching files found", OutputType.WARNING)
306
306
  continue
307
307
 
308
- # 显示匹配的文件
309
- PrettyOutput.print("\n找到以下匹配的文件:", OutputType.INFO)
308
+ # Display matching files
309
+ PrettyOutput.print("\nFound the following matching files:", OutputType.INFO)
310
310
  for i, path in enumerate(matches, 1):
311
311
  PrettyOutput.print(f"[{i}] {path}", OutputType.INFO)
312
312
 
313
- # 让用户选择
314
- numbers = input("\n请选择要添加的文件编号(支持: 1,3-6 格式,直接回车全选): ").strip()
313
+ # Let the user select
314
+ numbers = input("\nPlease select the file numbers to add (support: 1,3-6 format, press Enter to select all): ").strip()
315
315
  if numbers:
316
316
  indices = self._parse_file_selection(numbers, len(matches))
317
317
  if not indices:
@@ -322,11 +322,11 @@ class JarvisCoder:
322
322
  else:
323
323
  paths_to_add = [file_path]
324
324
 
325
- # 添加选中的文件
325
+ # Add selected files
326
326
  for path in paths_to_add:
327
327
  full_path = os.path.join(self.root_dir, path)
328
328
  if not os.path.isfile(full_path):
329
- PrettyOutput.print(f"文件不存在: {path}", OutputType.ERROR)
329
+ PrettyOutput.print(f"File does not exist: {path}", OutputType.ERROR)
330
330
  continue
331
331
 
332
332
  try:
@@ -336,46 +336,46 @@ class JarvisCoder:
336
336
  "file_path": path,
337
337
  "file_content": content
338
338
  })
339
- PrettyOutput.print(f"已添加文件: {path}", OutputType.SUCCESS)
339
+ PrettyOutput.print(f"File added: {path}", OutputType.SUCCESS)
340
340
  except Exception as e:
341
- PrettyOutput.print(f"读取文件失败: {str(e)}", OutputType.ERROR)
341
+ PrettyOutput.print(f"Failed to read file: {str(e)}", OutputType.ERROR)
342
342
 
343
343
  return selected_files
344
344
 
345
345
  def _finalize_changes(self, feature: str) -> None:
346
- """完成修改并提交"""
347
- PrettyOutput.print("修改确认成功,提交修改", OutputType.INFO)
346
+ """Complete changes and commit"""
347
+ PrettyOutput.print("Modification confirmed, committing...", OutputType.INFO)
348
348
 
349
- # 只添加已经在 git 控制下的修改文件
349
+ # Add only modified files under git control
350
350
  os.system("git add -u")
351
351
 
352
- # 然后获取 git diff
352
+ # Then get git diff
353
353
  git_diff = os.popen("git diff --cached").read()
354
354
 
355
- # 自动生成commit信息,传入feature
355
+ # Automatically generate commit information, pass in feature
356
356
  commit_message = generate_commit_message(git_diff)
357
357
 
358
- # 显示并确认commit信息
359
- PrettyOutput.print(f"自动生成的commit信息: {commit_message}", OutputType.INFO)
360
- user_confirm = input("是否使用该commit信息?(y/n) [y]: ") or "y"
358
+ # Display and confirm commit information
359
+ PrettyOutput.print(f"Automatically generated commit information: {commit_message}", OutputType.INFO)
360
+ user_confirm = input("Use this commit information? (y/n) [y]: ") or "y"
361
361
 
362
362
  if user_confirm.lower() != "y":
363
- commit_message = input("请输入新的commit信息: ")
363
+ commit_message = input("Please enter a new commit information: ")
364
364
 
365
- # 不需要再次 git add,因为已经添加过了
365
+ # No need to git add again, it has already been added
366
366
  os.system(f"git commit -m '{commit_message}'")
367
367
  save_edit_record(self.record_dir, commit_message, git_diff)
368
368
 
369
369
  def _revert_changes(self) -> None:
370
- """回退所有修改"""
371
- PrettyOutput.print("修改已取消,回退更改", OutputType.INFO)
370
+ """Revert all changes"""
371
+ PrettyOutput.print("Modification cancelled, reverting changes", OutputType.INFO)
372
372
  os.system(f"git reset --hard")
373
373
  os.system(f"git clean -df")
374
374
 
375
375
  def get_key_code(self, files: List[Dict], feature: str):
376
- """提取文件中与需求相关的关键代码片段"""
376
+ """Extract relevant key code snippets from files"""
377
377
  for file_info in files:
378
- PrettyOutput.print(f"分析文件: {file_info['file_path']}", OutputType.INFO)
378
+ PrettyOutput.print(f"Analyzing file: {file_info['file_path']}", OutputType.INFO)
379
379
  model = PlatformRegistry.get_global_platform_registry().get_codegen_platform()
380
380
  model.set_suppress_output(True)
381
381
  file_path = file_info["file_path"]
@@ -402,39 +402,39 @@ Code content:
402
402
  parts = re.findall(r'<PART>\n(.*?)\n</PART>', response, re.DOTALL)
403
403
  file_info["parts"] = parts
404
404
  except Exception as e:
405
- PrettyOutput.print(f"分析文件失败: {str(e)}", OutputType.ERROR)
405
+ PrettyOutput.print(f"Failed to analyze file: {str(e)}", OutputType.ERROR)
406
406
 
407
407
  def execute(self, feature: str) -> Dict[str, Any]:
408
- """执行代码修改"""
408
+ """Execute code modification"""
409
409
  try:
410
410
  self._prepare_execution()
411
411
 
412
- # 获取并选择相关文件
412
+ # Get and select related files
413
413
  initial_files = self._load_related_files(feature)
414
414
  selected_files = self._select_files(initial_files)
415
415
 
416
- # 是否是长上下文
416
+ # Whether it is a long context
417
417
  if is_long_context([file['file_path'] for file in selected_files]):
418
418
  self.get_key_code(selected_files, feature)
419
419
  else:
420
420
  for file in selected_files:
421
421
  file["parts"] = [file["file_content"]]
422
422
 
423
- # 获取修改方案
423
+ # Get modification plan
424
424
  raw_plan, structed_plan = PlanGenerator().generate_plan(feature, selected_files)
425
425
  if not raw_plan or not structed_plan:
426
426
  return {
427
427
  "success": False,
428
428
  "stdout": "",
429
- "stderr": "修改计划生成失败,请修改需求后重试",
429
+ "stderr": "Failed to generate modification plan, please modify the requirement and try again",
430
430
  }
431
431
 
432
- # 执行修改
432
+ # Execute modification
433
433
  if PatchHandler().handle_patch_application(feature ,raw_plan, structed_plan):
434
434
  self._finalize_changes(feature)
435
435
  return {
436
436
  "success": True,
437
- "stdout": "代码修改成功",
437
+ "stdout": "Code modification successful",
438
438
  "stderr": "",
439
439
  }
440
440
  else:
@@ -442,7 +442,7 @@ Code content:
442
442
  return {
443
443
  "success": False,
444
444
  "stdout": "",
445
- "stderr": "代码修改失败,请修改需求后重试",
445
+ "stderr": "Code modification failed, please modify the requirement and try again",
446
446
  }
447
447
 
448
448
  except Exception as e:
@@ -450,54 +450,54 @@ Code content:
450
450
  return {
451
451
  "success": False,
452
452
  "stdout": "",
453
- "stderr": f"执行失败: {str(e)},请修改需求后重试",
453
+ "stderr": f"Execution failed: {str(e)}, please modify the requirement and try again",
454
454
  "error": e
455
455
  }
456
456
 
457
457
  def main():
458
- """命令行入口"""
458
+ """Command line entry"""
459
459
  import argparse
460
460
 
461
461
  load_env_from_file()
462
462
 
463
- parser = argparse.ArgumentParser(description='代码修改工具')
464
- parser.add_argument('-d', '--dir', help='项目根目录', default=os.getcwd())
465
- parser.add_argument('-l', '--language', help='编程语言', default="python")
463
+ parser = argparse.ArgumentParser(description='Code modification tool')
464
+ parser.add_argument('-d', '--dir', help='Project root directory', default=os.getcwd())
465
+ parser.add_argument('-l', '--language', help='Programming language', default="python")
466
466
  args = parser.parse_args()
467
467
 
468
468
  tool = JarvisCoder(args.dir, args.language)
469
469
 
470
- # 循环处理需求
470
+ # Loop through requirements
471
471
  while True:
472
472
  try:
473
- # 获取需求,传入项目根目录
474
- feature = get_multiline_input("请输入开发需求 (输入空行退出):", tool.root_dir)
473
+ # Get requirements, pass in project root directory
474
+ feature = get_multiline_input("Please enter the development requirements (input empty line to exit):", tool.root_dir)
475
475
 
476
476
  if not feature or feature == "__interrupt__":
477
477
  break
478
478
 
479
- # 执行修改
479
+ # Execute modification
480
480
  result = tool.execute(feature)
481
481
 
482
- # 显示结果
482
+ # Display results
483
483
  if result["success"]:
484
484
  PrettyOutput.print(result["stdout"], OutputType.SUCCESS)
485
485
  else:
486
486
  if result.get("stderr"):
487
487
  PrettyOutput.print(result["stderr"], OutputType.WARNING)
488
- if result.get("error"): # 使用 get() 方法避免 KeyError
488
+ if result.get("error"): # Use get() method to avoid KeyError
489
489
  error = result["error"]
490
- PrettyOutput.print(f"错误类型: {type(error).__name__}", OutputType.WARNING)
491
- PrettyOutput.print(f"错误信息: {str(error)}", OutputType.WARNING)
492
- # 提示用户可以继续输入
493
- PrettyOutput.print("\n您可以修改需求后重试", OutputType.INFO)
490
+ PrettyOutput.print(f"Error type: {type(error).__name__}", OutputType.WARNING)
491
+ PrettyOutput.print(f"Error information: {str(error)}", OutputType.WARNING)
492
+ # Prompt user to continue input
493
+ PrettyOutput.print("\nYou can modify the requirements and try again", OutputType.INFO)
494
494
 
495
495
  except KeyboardInterrupt:
496
- print("\n用户中断执行")
496
+ print("\nUser interrupted execution")
497
497
  break
498
498
  except Exception as e:
499
- PrettyOutput.print(f"执行出错: {str(e)}", OutputType.ERROR)
500
- PrettyOutput.print("\n您可以修改需求后重试", OutputType.INFO)
499
+ PrettyOutput.print(f"Execution failed: {str(e)}", OutputType.ERROR)
500
+ PrettyOutput.print("\nYou can modify the requirements and try again", OutputType.INFO)
501
501
  continue
502
502
 
503
503
  return 0
@@ -506,93 +506,93 @@ if __name__ == "__main__":
506
506
  exit(main())
507
507
 
508
508
  class FilePathCompleter(Completer):
509
- """文件路径自动完成器"""
509
+ """File path auto-completer"""
510
510
 
511
511
  def __init__(self, root_dir: str):
512
512
  self.root_dir = root_dir
513
513
  self._file_list = None
514
514
 
515
515
  def _get_files(self) -> List[str]:
516
- """获取git管理的文件列表"""
516
+ """Get the list of files managed by git"""
517
517
  if self._file_list is None:
518
518
  try:
519
- # 切换到项目根目录
519
+ # Switch to project root directory
520
520
  old_cwd = os.getcwd()
521
521
  os.chdir(self.root_dir)
522
522
 
523
- # 获取git管理的文件列表
523
+ # Get the list of files managed by git
524
524
  self._file_list = os.popen("git ls-files").read().splitlines()
525
525
 
526
- # 恢复工作目录
526
+ # Restore working directory
527
527
  os.chdir(old_cwd)
528
528
  except Exception as e:
529
- PrettyOutput.print(f"获取文件列表失败: {str(e)}", OutputType.WARNING)
529
+ PrettyOutput.print(f"Failed to get file list: {str(e)}", OutputType.WARNING)
530
530
  self._file_list = []
531
531
  return self._file_list
532
532
 
533
533
  def get_completions(self, document, complete_event):
534
- """获取补全建议"""
534
+ """Get completion suggestions"""
535
535
  text_before_cursor = document.text_before_cursor
536
536
 
537
- # 检查是否刚输入了@
537
+ # Check if @ was just entered
538
538
  if text_before_cursor.endswith('@'):
539
- # 显示所有文件
539
+ # Display all files
540
540
  for path in self._get_files():
541
541
  yield Completion(path, start_position=0)
542
542
  return
543
543
 
544
- # 检查之前是否有@,并获取@后的搜索词
544
+ # Check if there was an @ before, and get the search word after @
545
545
  at_pos = text_before_cursor.rfind('@')
546
546
  if at_pos == -1:
547
547
  return
548
548
 
549
549
  search = text_before_cursor[at_pos + 1:].lower().strip()
550
550
 
551
- # 提供匹配的文件建议
551
+ # Provide matching file suggestions
552
552
  for path in self._get_files():
553
553
  path_lower = path.lower()
554
- if (search in path_lower or # 直接包含
555
- search in os.path.basename(path_lower) or # 文件名包含
556
- any(fnmatch.fnmatch(path_lower, f'*{s}*') for s in search.split())): # 通配符匹配
557
- # 计算正确的start_position
554
+ if (search in path_lower or # Directly included
555
+ search in os.path.basename(path_lower) or # File name included
556
+ any(fnmatch.fnmatch(path_lower, f'*{s}*') for s in search.split())): # Wildcard matching
557
+ # Calculate the correct start_position
558
558
  yield Completion(path, start_position=-(len(search)))
559
559
 
560
560
  class SmartCompleter(Completer):
561
- """智能自动完成器,组合词语和文件路径补全"""
561
+ """Smart auto-completer, combine word and file path completion"""
562
562
 
563
563
  def __init__(self, word_completer: WordCompleter, file_completer: FilePathCompleter):
564
564
  self.word_completer = word_completer
565
565
  self.file_completer = file_completer
566
566
 
567
567
  def get_completions(self, document, complete_event):
568
- """获取补全建议"""
569
- # 如果当前行以@结尾,使用文件补全
568
+ """Get completion suggestions"""
569
+ # If the current line ends with @, use file completion
570
570
  if document.text_before_cursor.strip().endswith('@'):
571
571
  yield from self.file_completer.get_completions(document, complete_event)
572
572
  else:
573
- # 否则使用词语补全
573
+ # Otherwise, use word completion
574
574
  yield from self.word_completer.get_completions(document, complete_event)
575
575
 
576
576
  def get_multiline_input(prompt_text: str, root_dir: Optional[str] = ".") -> str:
577
- """获取多行输入,支持文件路径自动完成功能
577
+ """Get multi-line input, support file path auto-completion function
578
578
 
579
579
  Args:
580
- prompt_text: 提示文本
581
- root_dir: 项目根目录,用于文件补全
580
+ prompt_text: Prompt text
581
+ root_dir: Project root directory, for file completion
582
582
 
583
583
  Returns:
584
- str: 用户输入的文本
584
+ str: User input text
585
585
  """
586
- # 创建文件补全器
586
+ # Create file completion
587
587
  file_completer = FilePathCompleter(root_dir or os.getcwd())
588
588
 
589
- # 创建提示样式
589
+ # Create prompt style
590
590
  style = Style.from_dict({
591
591
  'prompt': 'ansicyan bold',
592
592
  'input': 'ansiwhite',
593
593
  })
594
594
 
595
- # 创建会话
595
+ # Create session
596
596
  session = PromptSession(
597
597
  completer=file_completer,
598
598
  style=style,
@@ -601,20 +601,20 @@ def get_multiline_input(prompt_text: str, root_dir: Optional[str] = ".") -> str:
601
601
  complete_while_typing=True
602
602
  )
603
603
 
604
- # 显示初始提示文本
604
+ # Display initial prompt text
605
605
  print(f"\n{prompt_text}")
606
606
 
607
- # 创建提示符
607
+ # Create prompt
608
608
  prompt = FormattedText([
609
609
  ('class:prompt', ">>> ")
610
610
  ])
611
611
 
612
- # 获取输入
612
+ # Get input
613
613
  lines = []
614
614
  try:
615
615
  while True:
616
616
  line = session.prompt(prompt).strip()
617
- if not line: # 空行表示输入结束
617
+ if not line: # Empty line means input end
618
618
  break
619
619
  lines.append(line)
620
620
  except KeyboardInterrupt: