jarvis-ai-assistant 0.1.193__py3-none-any.whl → 0.1.195__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.
Files changed (92) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +45 -41
  3. jarvis/jarvis_agent/builtin_input_handler.py +26 -4
  4. jarvis/jarvis_agent/jarvis.py +30 -19
  5. jarvis/jarvis_agent/main.py +20 -12
  6. jarvis/jarvis_agent/output_handler.py +7 -7
  7. jarvis/jarvis_agent/shell_input_handler.py +14 -11
  8. jarvis/jarvis_code_agent/code_agent.py +81 -79
  9. jarvis/jarvis_code_agent/lint.py +92 -105
  10. jarvis/jarvis_code_analysis/checklists/__init__.py +1 -1
  11. jarvis/jarvis_code_analysis/checklists/c_cpp.py +1 -1
  12. jarvis/jarvis_code_analysis/checklists/csharp.py +1 -1
  13. jarvis/jarvis_code_analysis/checklists/data_format.py +1 -1
  14. jarvis/jarvis_code_analysis/checklists/devops.py +1 -1
  15. jarvis/jarvis_code_analysis/checklists/docs.py +1 -1
  16. jarvis/jarvis_code_analysis/checklists/go.py +1 -1
  17. jarvis/jarvis_code_analysis/checklists/infrastructure.py +1 -1
  18. jarvis/jarvis_code_analysis/checklists/java.py +1 -1
  19. jarvis/jarvis_code_analysis/checklists/javascript.py +1 -1
  20. jarvis/jarvis_code_analysis/checklists/kotlin.py +1 -1
  21. jarvis/jarvis_code_analysis/checklists/loader.py +31 -29
  22. jarvis/jarvis_code_analysis/checklists/php.py +1 -1
  23. jarvis/jarvis_code_analysis/checklists/python.py +1 -1
  24. jarvis/jarvis_code_analysis/checklists/ruby.py +1 -1
  25. jarvis/jarvis_code_analysis/checklists/rust.py +1 -1
  26. jarvis/jarvis_code_analysis/checklists/shell.py +1 -1
  27. jarvis/jarvis_code_analysis/checklists/sql.py +1 -1
  28. jarvis/jarvis_code_analysis/checklists/swift.py +1 -1
  29. jarvis/jarvis_code_analysis/checklists/web.py +1 -1
  30. jarvis/jarvis_code_analysis/code_review.py +292 -190
  31. jarvis/jarvis_dev/main.py +73 -56
  32. jarvis/jarvis_git_details/main.py +29 -33
  33. jarvis/jarvis_git_squash/main.py +13 -11
  34. jarvis/jarvis_git_utils/git_commiter.py +15 -5
  35. jarvis/jarvis_mcp/__init__.py +8 -10
  36. jarvis/jarvis_mcp/sse_mcp_client.py +182 -205
  37. jarvis/jarvis_mcp/stdio_mcp_client.py +93 -120
  38. jarvis/jarvis_mcp/streamable_mcp_client.py +117 -142
  39. jarvis/jarvis_methodology/main.py +71 -39
  40. jarvis/jarvis_multi_agent/__init__.py +24 -16
  41. jarvis/jarvis_multi_agent/main.py +10 -4
  42. jarvis/jarvis_platform/__init__.py +1 -1
  43. jarvis/jarvis_platform/base.py +44 -18
  44. jarvis/jarvis_platform/human.py +15 -3
  45. jarvis/jarvis_platform/kimi.py +117 -81
  46. jarvis/jarvis_platform/openai.py +23 -28
  47. jarvis/jarvis_platform/registry.py +43 -29
  48. jarvis/jarvis_platform/tongyi.py +16 -10
  49. jarvis/jarvis_platform/yuanbao.py +197 -144
  50. jarvis/jarvis_platform_manager/main.py +4 -2
  51. jarvis/jarvis_smart_shell/main.py +35 -30
  52. jarvis/jarvis_tools/ask_user.py +8 -16
  53. jarvis/jarvis_tools/base.py +3 -2
  54. jarvis/jarvis_tools/chdir.py +7 -19
  55. jarvis/jarvis_tools/cli/main.py +14 -10
  56. jarvis/jarvis_tools/code_plan.py +10 -31
  57. jarvis/jarvis_tools/create_code_agent.py +6 -11
  58. jarvis/jarvis_tools/create_sub_agent.py +10 -22
  59. jarvis/jarvis_tools/edit_file.py +98 -76
  60. jarvis/jarvis_tools/execute_script.py +46 -46
  61. jarvis/jarvis_tools/file_analyzer.py +22 -34
  62. jarvis/jarvis_tools/file_operation.py +69 -62
  63. jarvis/jarvis_tools/generate_new_tool.py +0 -2
  64. jarvis/jarvis_tools/methodology.py +19 -23
  65. jarvis/jarvis_tools/read_code.py +35 -35
  66. jarvis/jarvis_tools/read_webpage.py +7 -16
  67. jarvis/jarvis_tools/registry.py +63 -30
  68. jarvis/jarvis_tools/rewrite_file.py +26 -29
  69. jarvis/jarvis_tools/search_web.py +5 -8
  70. jarvis/jarvis_tools/virtual_tty.py +133 -122
  71. jarvis/jarvis_utils/__init__.py +0 -1
  72. jarvis/jarvis_utils/builtin_replace_map.py +9 -9
  73. jarvis/jarvis_utils/config.py +60 -37
  74. jarvis/jarvis_utils/embedding.py +24 -19
  75. jarvis/jarvis_utils/file_processors.py +16 -9
  76. jarvis/jarvis_utils/git_utils.py +157 -107
  77. jarvis/jarvis_utils/globals.py +1 -1
  78. jarvis/jarvis_utils/input.py +85 -52
  79. jarvis/jarvis_utils/jarvis_history.py +43 -0
  80. jarvis/jarvis_utils/methodology.py +31 -24
  81. jarvis/jarvis_utils/output.py +164 -80
  82. jarvis/jarvis_utils/tag.py +2 -1
  83. jarvis/jarvis_utils/utils.py +84 -52
  84. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/METADATA +362 -230
  85. jarvis_ai_assistant-0.1.195.dist-info/RECORD +98 -0
  86. jarvis/jarvis_agent/file_input_handler.py +0 -112
  87. jarvis/jarvis_event/__init__.py +0 -0
  88. jarvis_ai_assistant-0.1.193.dist-info/RECORD +0 -99
  89. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/WHEEL +0 -0
  90. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/entry_points.txt +0 -0
  91. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/licenses/LICENSE +0 -0
  92. {jarvis_ai_assistant-0.1.193.dist-info → jarvis_ai_assistant-0.1.195.dist-info}/top_level.txt +0 -0
@@ -14,8 +14,7 @@ import re
14
14
  import subprocess
15
15
  from typing import Any, Dict, List, Tuple
16
16
 
17
- from jarvis.jarvis_utils.config import (get_auto_update,
18
- is_confirm_before_apply_patch)
17
+ from jarvis.jarvis_utils.config import get_auto_update, is_confirm_before_apply_patch
19
18
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
20
19
  from jarvis.jarvis_utils.utils import user_confirm
21
20
 
@@ -42,29 +41,47 @@ def find_git_root(start_dir: str = ".") -> str:
42
41
  git_root = os.path.abspath(".")
43
42
  os.chdir(git_root)
44
43
  return git_root
44
+
45
+
45
46
  def has_uncommitted_changes() -> bool:
46
47
  """检查Git仓库中是否有未提交的更改
47
-
48
+
48
49
  返回:
49
50
  bool: 如果有未提交的更改返回True,否则返回False
50
51
  """
51
52
  # 静默添加所有更改
52
- subprocess.run(["git", "add", "."], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
53
+ subprocess.run(
54
+ ["git", "add", "."], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
55
+ )
53
56
 
54
57
  # 检查工作目录更改
55
- working_changes = subprocess.run(["git", "diff", "--exit-code"],
56
- stdout=subprocess.DEVNULL,
57
- stderr=subprocess.DEVNULL).returncode != 0
58
+ working_changes = (
59
+ subprocess.run(
60
+ ["git", "diff", "--exit-code"],
61
+ stdout=subprocess.DEVNULL,
62
+ stderr=subprocess.DEVNULL,
63
+ ).returncode
64
+ != 0
65
+ )
58
66
 
59
67
  # 检查暂存区更改
60
- staged_changes = subprocess.run(["git", "diff", "--cached", "--exit-code"],
61
- stdout=subprocess.DEVNULL,
62
- stderr=subprocess.DEVNULL).returncode != 0
68
+ staged_changes = (
69
+ subprocess.run(
70
+ ["git", "diff", "--cached", "--exit-code"],
71
+ stdout=subprocess.DEVNULL,
72
+ stderr=subprocess.DEVNULL,
73
+ ).returncode
74
+ != 0
75
+ )
63
76
 
64
77
  # 静默重置更改
65
- subprocess.run(["git", "reset"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
78
+ subprocess.run(
79
+ ["git", "reset"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
80
+ )
66
81
 
67
82
  return working_changes or staged_changes
83
+
84
+
68
85
  def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]:
69
86
  """获取两个提交哈希值之间的提交列表
70
87
 
@@ -78,103 +95,112 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
78
95
  try:
79
96
  # 使用git log和pretty格式获取哈希值和信息
80
97
  result = subprocess.run(
81
- ['git', 'log', f'{start_hash}..{end_hash}', '--pretty=format:%H|%s'],
98
+ ["git", "log", f"{start_hash}..{end_hash}", "--pretty=format:%H|%s"],
82
99
  stdout=subprocess.PIPE,
83
100
  stderr=subprocess.PIPE,
84
- text=False # 禁用自动文本解码
101
+ text=False, # 禁用自动文本解码
85
102
  )
86
103
  if result.returncode != 0:
87
- error_msg = result.stderr.decode('utf-8', errors='replace')
104
+ error_msg = result.stderr.decode("utf-8", errors="replace")
88
105
  PrettyOutput.print(f"获取commit历史失败: {error_msg}", OutputType.ERROR)
89
106
  return []
90
107
 
91
- output = result.stdout.decode('utf-8', errors='replace')
108
+ output = result.stdout.decode("utf-8", errors="replace")
92
109
  commits = []
93
110
  for line in output.splitlines():
94
- if '|' in line:
95
- commit_hash, message = line.split('|', 1)
111
+ if "|" in line:
112
+ commit_hash, message = line.split("|", 1)
96
113
  commits.append((commit_hash, message))
97
114
  return commits
98
115
 
99
116
  except Exception as e:
100
117
  PrettyOutput.print(f"获取commit历史异常: {str(e)}", OutputType.ERROR)
101
118
  return []
102
-
119
+
103
120
 
104
121
  # 修改后的获取差异函数
105
122
 
106
123
 
107
124
  def get_diff() -> str:
108
125
  """使用git获取工作区差异,包括修改和新增的文件内容
109
-
126
+
110
127
  返回:
111
128
  str: 差异内容或错误信息
112
129
  """
113
130
  try:
114
- # 暂存新增文件
115
- subprocess.run(['git', 'add', '-N', '.'], check=True)
116
-
117
- # 获取所有差异(包括新增文件)
118
- result = subprocess.run(
119
- ['git', 'diff', 'HEAD'],
120
- capture_output=True,
121
- text=False,
122
- check=True
131
+ # 检查是否为空仓库
132
+ head_check = subprocess.run(
133
+ ["git", "rev-parse", "--verify", "HEAD"],
134
+ stderr=subprocess.PIPE,
135
+ stdout=subprocess.PIPE,
123
136
  )
124
-
125
- # 重置暂存区
126
- subprocess.run(['git', 'reset'], check=True)
127
-
137
+ if head_check.returncode != 0:
138
+ # 空仓库情况,直接获取工作区差异
139
+ result = subprocess.run(
140
+ ["git", "diff"], capture_output=True, text=False, check=True
141
+ )
142
+ else:
143
+ # 暂存新增文件
144
+ subprocess.run(["git", "add", "-N", "."], check=True)
145
+
146
+ # 获取所有差异(包括新增文件)
147
+ result = subprocess.run(
148
+ ["git", "diff", "HEAD"], capture_output=True, text=False, check=True
149
+ )
150
+
151
+ # 重置暂存区
152
+ subprocess.run(["git", "reset"], check=True)
153
+
128
154
  try:
129
- return result.stdout.decode('utf-8')
155
+ return result.stdout.decode("utf-8")
130
156
  except UnicodeDecodeError:
131
- return result.stdout.decode('utf-8', errors='replace')
132
-
157
+ return result.stdout.decode("utf-8", errors="replace")
158
+
133
159
  except subprocess.CalledProcessError as e:
134
160
  return f"获取差异失败: {str(e)}"
135
161
  except Exception as e:
136
162
  return f"发生意外错误: {str(e)}"
137
163
 
138
164
 
139
-
140
-
141
-
142
165
  def revert_file(filepath: str) -> None:
143
166
  """增强版git恢复,处理新文件"""
144
167
  import subprocess
168
+
145
169
  try:
146
170
  # 检查文件是否在版本控制中
147
171
  result = subprocess.run(
148
- ['git', 'ls-files', '--error-unmatch', filepath],
172
+ ["git", "ls-files", "--error-unmatch", filepath],
149
173
  stderr=subprocess.PIPE,
150
- text=False # 禁用自动文本解码
174
+ text=False, # 禁用自动文本解码
151
175
  )
152
176
  if result.returncode == 0:
153
- subprocess.run(['git', 'checkout', 'HEAD',
154
- '--', filepath], check=True)
177
+ subprocess.run(["git", "checkout", "HEAD", "--", filepath], check=True)
155
178
  else:
156
179
  if os.path.exists(filepath):
157
180
  os.remove(filepath)
158
- subprocess.run(['git', 'clean', '-f', '--', filepath], check=True)
181
+ subprocess.run(["git", "clean", "-f", "--", filepath], check=True)
159
182
  except subprocess.CalledProcessError as e:
160
- error_msg = e.stderr.decode('utf-8', errors='replace') if e.stderr else str(e)
183
+ error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
161
184
  PrettyOutput.print(f"恢复文件失败: {error_msg}", OutputType.ERROR)
185
+
186
+
162
187
  # 修改后的恢复函数
163
188
 
164
189
 
165
190
  def revert_change() -> None:
166
191
  """恢复所有未提交的修改到HEAD状态"""
167
192
  import subprocess
193
+
168
194
  try:
169
195
  # 检查是否为空仓库
170
196
  head_check = subprocess.run(
171
- ['git', 'rev-parse', '--verify', 'HEAD'],
197
+ ["git", "rev-parse", "--verify", "HEAD"],
172
198
  stderr=subprocess.PIPE,
173
- stdout=subprocess.PIPE
199
+ stdout=subprocess.PIPE,
174
200
  )
175
201
  if head_check.returncode == 0:
176
- subprocess.run(['git', 'reset', '--hard', 'HEAD'], check=True)
177
- subprocess.run(['git', 'clean', '-fd'], check=True)
202
+ subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)
203
+ subprocess.run(["git", "clean", "-fd"], check=True)
178
204
  except subprocess.CalledProcessError as e:
179
205
  PrettyOutput.print(f"恢复更改失败: {str(e)}", OutputType.ERROR)
180
206
 
@@ -188,27 +214,25 @@ def handle_commit_workflow() -> bool:
188
214
  if is_confirm_before_apply_patch() and not user_confirm("是否要提交代码?", default=True):
189
215
  revert_change()
190
216
  return False
191
-
217
+
192
218
  import subprocess
219
+
193
220
  try:
194
221
  # 获取当前分支的提交总数
195
222
  commit_result = subprocess.run(
196
- ['git', 'rev-list', '--count', 'HEAD'],
197
- capture_output=True,
198
- text=True
223
+ ["git", "rev-list", "--count", "HEAD"], capture_output=True, text=True
199
224
  )
200
225
  if commit_result.returncode != 0:
201
226
  return False
202
-
227
+
203
228
  commit_count = int(commit_result.stdout.strip())
204
-
229
+
205
230
  # 暂存所有修改
206
- subprocess.run(['git', 'add', '.'], check=True)
207
-
231
+ subprocess.run(["git", "add", "."], check=True)
232
+
208
233
  # 提交变更
209
234
  subprocess.run(
210
- ['git', 'commit', '-m', f'CheckPoint #{commit_count + 1}'],
211
- check=True
235
+ ["git", "commit", "-m", f"CheckPoint #{commit_count + 1}"], check=True
212
236
  )
213
237
  return True
214
238
  except subprocess.CalledProcessError as e:
@@ -224,24 +248,30 @@ def get_latest_commit_hash() -> str:
224
248
  try:
225
249
  # 首先检查是否存在HEAD引用
226
250
  head_check = subprocess.run(
227
- ['git', 'rev-parse', '--verify', 'HEAD'],
251
+ ["git", "rev-parse", "--verify", "HEAD"],
228
252
  stdout=subprocess.PIPE,
229
253
  stderr=subprocess.PIPE,
230
- text=False
254
+ text=False,
231
255
  )
232
256
  if head_check.returncode != 0:
233
257
  return "" # 空仓库或无效HEAD
234
258
 
235
259
  # 获取HEAD的完整哈希值
236
260
  result = subprocess.run(
237
- ['git', 'rev-parse', 'HEAD'],
261
+ ["git", "rev-parse", "HEAD"],
238
262
  stdout=subprocess.PIPE,
239
263
  stderr=subprocess.PIPE,
240
- text=False
264
+ text=False,
265
+ )
266
+ return (
267
+ result.stdout.decode("utf-8", errors="replace").strip()
268
+ if result.returncode == 0
269
+ else ""
241
270
  )
242
- return result.stdout.decode('utf-8', errors='replace').strip() if result.returncode == 0 else ""
243
271
  except Exception:
244
272
  return ""
273
+
274
+
245
275
  def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
246
276
  """从Git差异中获取所有更改文件的修改行范围
247
277
 
@@ -274,18 +304,16 @@ def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
274
304
  return result
275
305
 
276
306
 
277
-
278
307
  def is_file_in_git_repo(filepath: str) -> bool:
279
308
  """检查文件是否在当前Git仓库中"""
280
309
  import subprocess
310
+
281
311
  try:
282
312
  # 获取Git仓库根目录
283
313
  repo_root = subprocess.run(
284
- ['git', 'rev-parse', '--show-toplevel'],
285
- capture_output=True,
286
- text=True
314
+ ["git", "rev-parse", "--show-toplevel"], capture_output=True, text=True
287
315
  ).stdout.strip()
288
-
316
+
289
317
  # 检查文件路径是否在仓库根目录下
290
318
  return os.path.abspath(filepath).startswith(os.path.abspath(repo_root))
291
319
  except:
@@ -316,25 +344,49 @@ def check_and_update_git_repo(repo_path: str) -> bool:
316
344
  # 获取远程tag更新
317
345
  subprocess.run(["git", "fetch", "--tags"], cwd=git_root, check=True)
318
346
  # 获取最新本地tag
319
- local_tag_result = subprocess.run(["git", "describe", "--tags", "--abbrev=0"],
320
- cwd=git_root, capture_output=True, text=True)
347
+ local_tag_result = subprocess.run(
348
+ ["git", "describe", "--tags", "--abbrev=0"],
349
+ cwd=git_root,
350
+ capture_output=True,
351
+ text=True,
352
+ )
321
353
  # 获取最新远程tag
322
354
  remote_tag_result = subprocess.run(
323
355
  ["git", "ls-remote", "--tags", "--refs", "origin"],
324
- cwd=git_root, capture_output=True, text=True
356
+ cwd=git_root,
357
+ capture_output=True,
358
+ text=True,
325
359
  )
326
360
  if remote_tag_result.returncode == 0:
327
361
  # 提取最新的tag名称
328
362
  tags = [ref.split("/")[-1] for ref in remote_tag_result.stdout.splitlines()]
329
- tags = sorted(tags, key=lambda x: [int(i) if i.isdigit() else i for i in re.split(r'([0-9]+)', x)])
363
+ tags = sorted(
364
+ tags,
365
+ key=lambda x: [
366
+ int(i) if i.isdigit() else i for i in re.split(r"([0-9]+)", x)
367
+ ],
368
+ )
330
369
  remote_tag = tags[-1] if tags else ""
331
370
  remote_tag_result.stdout = remote_tag
332
371
 
333
- if (local_tag_result.returncode == 0 and remote_tag_result.returncode == 0 and
334
- local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()):
335
- PrettyOutput.print(f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...", OutputType.INFO)
336
- subprocess.run(["git", "checkout", remote_tag_result.stdout.strip()], cwd=git_root, check=True)
337
- PrettyOutput.print(f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}", OutputType.SUCCESS)
372
+ if (
373
+ local_tag_result.returncode == 0
374
+ and remote_tag_result.returncode == 0
375
+ and local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()
376
+ ):
377
+ PrettyOutput.print(
378
+ f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...",
379
+ OutputType.INFO,
380
+ )
381
+ subprocess.run(
382
+ ["git", "checkout", remote_tag_result.stdout.strip()],
383
+ cwd=git_root,
384
+ check=True,
385
+ )
386
+ PrettyOutput.print(
387
+ f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}",
388
+ OutputType.SUCCESS,
389
+ )
338
390
  return True
339
391
  return False
340
392
  except Exception as e:
@@ -346,30 +398,28 @@ def check_and_update_git_repo(repo_path: str) -> bool:
346
398
 
347
399
  def get_diff_file_list() -> List[str]:
348
400
  """获取HEAD到当前变更的文件列表,包括修改和新增的文件
349
-
401
+
350
402
  返回:
351
403
  List[str]: 修改和新增的文件路径列表
352
404
  """
353
405
  try:
354
406
  # 暂存新增文件
355
- subprocess.run(['git', 'add', '-N', '.'], check=True)
356
-
407
+ subprocess.run(["git", "add", "-N", "."], check=True)
408
+
357
409
  # 获取所有差异文件(包括新增文件)
358
410
  result = subprocess.run(
359
- ['git', 'diff', '--name-only', 'HEAD'],
360
- capture_output=True,
361
- text=True
411
+ ["git", "diff", "--name-only", "HEAD"], capture_output=True, text=True
362
412
  )
363
-
413
+
364
414
  # 重置暂存区
365
- subprocess.run(['git', 'reset'], check=True)
366
-
415
+ subprocess.run(["git", "reset"], check=True)
416
+
367
417
  if result.returncode != 0:
368
418
  PrettyOutput.print(f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR)
369
419
  return []
370
-
420
+
371
421
  return [f for f in result.stdout.splitlines() if f]
372
-
422
+
373
423
  except subprocess.CalledProcessError as e:
374
424
  PrettyOutput.print(f"获取差异文件列表失败: {str(e)}", OutputType.ERROR)
375
425
  return []
@@ -378,19 +428,18 @@ def get_diff_file_list() -> List[str]:
378
428
  return []
379
429
 
380
430
 
381
-
382
431
  def get_recent_commits_with_files() -> List[Dict[str, Any]]:
383
432
  """获取最近5次提交的commit信息和文件清单
384
-
433
+
385
434
  返回:
386
435
  List[Dict[str, Any]]: 包含commit信息和文件清单的字典列表,格式为:
387
436
  [
388
437
  {
389
- 'hash': 提交hash,
390
- 'message': 提交信息,
391
- 'author': 作者,
392
- 'date': 提交日期,
393
- 'files': [修改的文件列表] (最多20个文件)
438
+ 'hash': str,
439
+ 'message': str,
440
+ 'author': str,
441
+ 'date': str,
442
+ 'files': List[str] # 修改的文件列表 (最多20个文件)
394
443
  },
395
444
  ...
396
445
  ]
@@ -399,9 +448,9 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
399
448
  try:
400
449
  # 获取最近5次提交的基本信息
401
450
  result = subprocess.run(
402
- ['git', 'log', '-5', '--pretty=format:%H%n%s%n%an%n%ad'],
451
+ ["git", "log", "-5", "--pretty=format:%H%n%s%n%an%n%ad"],
403
452
  capture_output=True,
404
- text=True
453
+ text=True,
405
454
  )
406
455
  if result.returncode != 0:
407
456
  return []
@@ -413,26 +462,27 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
413
462
  if i + 3 >= len(lines):
414
463
  break
415
464
  commit = {
416
- 'hash': lines[i],
417
- 'message': lines[i+1],
418
- 'author': lines[i+2],
419
- 'date': lines[i+3],
420
- 'files': []
465
+ "hash": lines[i],
466
+ "message": lines[i + 1],
467
+ "author": lines[i + 2],
468
+ "date": lines[i + 3],
469
+ "files": [],
421
470
  }
422
471
  commits.append(commit)
423
472
 
424
473
  # 获取每个提交的文件修改清单
425
474
  for commit in commits:
426
475
  files_result = subprocess.run(
427
- ['git', 'show', '--name-only', '--pretty=format:', commit['hash']],
476
+ ["git", "show", "--name-only", "--pretty=format:", commit["hash"]],
428
477
  capture_output=True,
429
- text=True
478
+ text=True,
430
479
  )
431
480
  if files_result.returncode == 0:
432
- files = list(set(filter(None, files_result.stdout.splitlines())))
433
- commit['files'] = files[:20] # 限制最多20个文件
481
+ file_lines = files_result.stdout.splitlines()
482
+ unique_files = set(filter(None, file_lines))
483
+ commit["files"] = list(unique_files)[:20] # 限制最多20个文件
434
484
 
435
485
  return commits
436
486
 
437
487
  except subprocess.CalledProcessError:
438
- return []
488
+ return []
@@ -8,7 +8,7 @@
8
8
  - 环境初始化
9
9
  """
10
10
  import os
11
- from typing import Any, Dict, Set
11
+ from typing import Any, Set
12
12
 
13
13
  import colorama
14
14
  from rich.console import Console