jarvis-ai-assistant 0.1.207__py3-none-any.whl → 0.1.208__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 (35) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +71 -61
  3. jarvis/jarvis_agent/edit_file_handler.py +42 -46
  4. jarvis/jarvis_agent/jarvis.py +33 -39
  5. jarvis/jarvis_code_agent/code_agent.py +26 -27
  6. jarvis/jarvis_code_agent/lint.py +5 -5
  7. jarvis/jarvis_code_analysis/code_review.py +164 -175
  8. jarvis/jarvis_git_utils/git_commiter.py +147 -152
  9. jarvis/jarvis_methodology/main.py +70 -81
  10. jarvis/jarvis_platform/base.py +21 -17
  11. jarvis/jarvis_platform/kimi.py +39 -53
  12. jarvis/jarvis_platform/tongyi.py +108 -126
  13. jarvis/jarvis_platform/yuanbao.py +112 -120
  14. jarvis/jarvis_platform_manager/main.py +102 -502
  15. jarvis/jarvis_platform_manager/service.py +432 -0
  16. jarvis/jarvis_smart_shell/main.py +99 -33
  17. jarvis/jarvis_tools/edit_file.py +64 -55
  18. jarvis/jarvis_tools/file_analyzer.py +17 -25
  19. jarvis/jarvis_tools/read_code.py +80 -81
  20. jarvis/jarvis_utils/builtin_replace_map.py +1 -36
  21. jarvis/jarvis_utils/config.py +14 -4
  22. jarvis/jarvis_utils/git_utils.py +36 -35
  23. jarvis/jarvis_utils/methodology.py +12 -17
  24. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/METADATA +1 -10
  25. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/RECORD +29 -34
  26. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/entry_points.txt +0 -1
  27. jarvis/jarvis_dev/main.py +0 -1247
  28. jarvis/jarvis_tools/chdir.py +0 -72
  29. jarvis/jarvis_tools/code_plan.py +0 -218
  30. jarvis/jarvis_tools/create_code_agent.py +0 -95
  31. jarvis/jarvis_tools/create_sub_agent.py +0 -82
  32. jarvis/jarvis_tools/file_operation.py +0 -238
  33. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/WHEEL +0 -0
  34. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/licenses/LICENSE +0 -0
  35. {jarvis_ai_assistant-0.1.207.dist-info → jarvis_ai_assistant-0.1.208.dist-info}/top_level.txt +0 -0
@@ -19,8 +19,6 @@
19
19
  """
20
20
  from typing import Any, Dict
21
21
 
22
- from yaspin import yaspin
23
-
24
22
  from jarvis.jarvis_agent.edit_file_handler import EditFileHandler
25
23
 
26
24
 
@@ -62,12 +60,18 @@ class FileSearchReplaceTool:
62
60
  "items": {
63
61
  "type": "object",
64
62
  "properties": {
65
- "reason": {"type": "string", "description": "修改的原因"},
63
+ "reason": {
64
+ "type": "string",
65
+ "description": "修改的原因",
66
+ },
66
67
  "search": {
67
68
  "type": "string",
68
69
  "description": "需要查找的原始代码",
69
70
  },
70
- "replace": {"type": "string", "description": "替换后的新代码"},
71
+ "replace": {
72
+ "type": "string",
73
+ "description": "替换后的新代码",
74
+ },
71
75
  },
72
76
  },
73
77
  },
@@ -79,7 +83,6 @@ class FileSearchReplaceTool:
79
83
  "required": ["files"],
80
84
  }
81
85
 
82
-
83
86
  def execute(self, args: Dict) -> Dict[str, Any]:
84
87
  """执行文件编辑操作,支持快速编辑和AI辅助编辑两种模式。
85
88
 
@@ -152,46 +155,46 @@ class FileSearchReplaceTool:
152
155
  if file_exists and agent:
153
156
  files = agent.get_user_data("files")
154
157
  if not files or file_path not in files:
155
- file_results.append({
156
- "file": file_path,
157
- "success": False,
158
- "stdout": "",
159
- "stderr": f"请先读取文件 {file_path} 的内容后再编辑"
160
- })
158
+ file_results.append(
159
+ {
160
+ "file": file_path,
161
+ "success": False,
162
+ "stdout": "",
163
+ "stderr": f"请先读取文件 {file_path} 的内容后再编辑",
164
+ }
165
+ )
161
166
  continue
162
167
 
163
- with yaspin(
164
- text=f"正在处理文件 {file_path}...", color="cyan"
165
- ) as spinner:
166
- # 首先尝试fast_edit模式
167
- success, temp_content = EditFileHandler._fast_edit(file_path, changes, spinner)
168
+ print(f"⚙️ 正在处理文件 {file_path}...")
169
+ # 首先尝试fast_edit模式
170
+ success, temp_content = EditFileHandler._fast_edit(
171
+ file_path, changes
172
+ )
173
+ if not success:
174
+ # 如果fast_edit失败,尝试slow_edit模式
175
+ success, temp_content = EditFileHandler._slow_edit(
176
+ file_path, changes, agent
177
+ )
168
178
  if not success:
169
- # 如果fast_edit失败,尝试slow_edit模式
170
- success, temp_content = EditFileHandler._slow_edit(
171
- file_path,
172
- changes,
173
- spinner,
174
- agent
175
- )
176
- if not success:
177
- spinner.text = f"文件 {file_path} 处理失败"
178
- spinner.fail("❌")
179
- file_results.append({
179
+ print(f"❌ 文件 {file_path} 处理失败")
180
+ file_results.append(
181
+ {
180
182
  "file": file_path,
181
183
  "success": False,
182
184
  "stdout": "",
183
- "stderr": temp_content
184
- })
185
- continue
186
- else:
187
- spinner.text = f"文件 {file_path} 内容生成完成"
188
- spinner.ok("✅")
185
+ "stderr": temp_content,
186
+ }
187
+ )
188
+ continue
189
189
  else:
190
- spinner.text = f"文件 {file_path} 内容生成完成"
191
- spinner.ok("✅")
190
+ print(f"文件 {file_path} 内容生成完成")
191
+ else:
192
+ print(f"✅ 文件 {file_path} 内容生成完成")
192
193
 
193
194
  # 只有当所有替换操作都成功时,才写回文件
194
- if success and (temp_content != original_content or not file_exists):
195
+ if success and (
196
+ temp_content != original_content or not file_exists
197
+ ):
195
198
  # 确保目录存在
196
199
  os.makedirs(
197
200
  os.path.dirname(os.path.abspath(file_path)), exist_ok=True
@@ -208,24 +211,28 @@ class FileSearchReplaceTool:
208
211
  PrettyOutput.print(stdout_message, OutputType.SUCCESS)
209
212
  overall_success = True
210
213
 
211
- file_results.append({
212
- "file": file_path,
213
- "success": True,
214
- "stdout": stdout_message,
215
- "stderr": ""
216
- })
214
+ file_results.append(
215
+ {
216
+ "file": file_path,
217
+ "success": True,
218
+ "stdout": stdout_message,
219
+ "stderr": "",
220
+ }
221
+ )
217
222
 
218
223
  except Exception as e:
219
224
  stderr_message = f"处理文件 {file_path} 时出错: {str(e)}"
220
225
  stderr_messages.append(stderr_message)
221
226
  PrettyOutput.print(stderr_message, OutputType.WARNING)
222
227
  file_success = False
223
- file_results.append({
224
- "file": file_path,
225
- "success": False,
226
- "stdout": "",
227
- "stderr": stderr_message
228
- })
228
+ file_results.append(
229
+ {
230
+ "file": file_path,
231
+ "success": False,
232
+ "stdout": "",
233
+ "stderr": stderr_message,
234
+ }
235
+ )
229
236
 
230
237
  except Exception as e:
231
238
  error_msg = f"文件搜索替换操作失败: {str(e)}"
@@ -251,12 +258,14 @@ class FileSearchReplaceTool:
251
258
  except:
252
259
  stderr_messages.append(f"回滚文件失败: {file_path}")
253
260
 
254
- file_results.append({
255
- "file": file_path,
256
- "success": False,
257
- "stdout": "",
258
- "stderr": error_msg
259
- })
261
+ file_results.append(
262
+ {
263
+ "file": file_path,
264
+ "success": False,
265
+ "stdout": "",
266
+ "stderr": error_msg,
267
+ }
268
+ )
260
269
 
261
270
  # 整合所有错误信息到stderr
262
271
  all_stderr = []
@@ -267,5 +276,5 @@ class FileSearchReplaceTool:
267
276
  return {
268
277
  "success": overall_success,
269
278
  "stdout": "\n".join(stdout_messages) if overall_success else "",
270
- "stderr": "\n".join(all_stderr) if not overall_success else ""
279
+ "stderr": "\n".join(all_stderr) if not overall_success else "",
271
280
  }
@@ -2,8 +2,6 @@
2
2
  import os
3
3
  from typing import Any, Dict
4
4
 
5
- from yaspin import yaspin # type: ignore
6
- from yaspin.spinners import Spinners # type: ignore
7
5
 
8
6
  from jarvis.jarvis_platform.registry import PlatformRegistry
9
7
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
@@ -78,28 +76,24 @@ class FileAnalyzerTool:
78
76
  platform.set_system_prompt(system_message)
79
77
 
80
78
  # 上传文件
81
- with yaspin(Spinners.dots, text="正在上传文件...") as spinner:
82
- try:
83
- with spinner.hidden():
84
- upload_result = platform.upload_files(valid_files)
85
- if not upload_result:
86
- spinner.text = "文件上传失败"
87
- spinner.fail("❌")
88
- return {
89
- "success": False,
90
- "stdout": "",
91
- "stderr": "文件上传失败",
92
- }
93
- spinner.text = "文件上传成功"
94
- spinner.ok("✅")
95
- except Exception as e:
96
- spinner.text = "文件上传失败"
97
- spinner.fail("❌")
79
+ print(f"📤 正在上传文件...")
80
+ try:
81
+ upload_result = platform.upload_files(valid_files)
82
+ if not upload_result:
83
+ print(f"❌ 文件上传失败")
98
84
  return {
99
85
  "success": False,
100
86
  "stdout": "",
101
- "stderr": f"文件上传失败: {str(e)}",
87
+ "stderr": "文件上传失败",
102
88
  }
89
+ print(f"✅ 文件上传成功")
90
+ except Exception as e:
91
+ print(f"❌ 文件上传失败: {str(e)}")
92
+ return {
93
+ "success": False,
94
+ "stdout": "",
95
+ "stderr": f"文件上传失败: {str(e)}",
96
+ }
103
97
 
104
98
  platform.set_suppress_output(False)
105
99
 
@@ -111,11 +105,9 @@ class FileAnalyzerTool:
111
105
  请提供详细的分析结果和理由。"""
112
106
 
113
107
  # 发送请求并获取分析结果
114
- with yaspin(Spinners.dots, text="正在分析文件...") as spinner:
115
- with spinner.hidden():
116
- analysis_result = platform.chat_until_success(analysis_request)
117
- spinner.text = "分析完成"
118
- spinner.ok("✅")
108
+ print(f"🔍 正在分析文件...")
109
+ analysis_result = platform.chat_until_success(analysis_request)
110
+ print(f"✅ 分析完成")
119
111
 
120
112
  # 清理会话
121
113
  platform.delete_chat()
@@ -2,8 +2,6 @@
2
2
  import os
3
3
  from typing import Any, Dict
4
4
 
5
- from yaspin import yaspin
6
-
7
5
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
8
6
 
9
7
 
@@ -46,89 +44,90 @@ class ReadCodeTool:
46
44
  """
47
45
  try:
48
46
  abs_path = os.path.abspath(filepath)
49
- with yaspin(text=f"正在读取文件: {abs_path}...", color="cyan") as spinner:
50
- # 文件存在性检查
51
- if not os.path.exists(abs_path):
52
- return {
53
- "success": False,
54
- "stdout": "",
55
- "stderr": f"文件不存在: {abs_path}",
56
- }
57
-
58
- # 文件大小限制检查(10MB)
59
- if os.path.getsize(abs_path) > 10 * 1024 * 1024:
60
- return {
61
- "success": False,
62
- "stdout": "",
63
- "stderr": "文件过大 (>10MB)",
64
- }
65
-
66
- # 读取文件内容
67
- with open(abs_path, "r", encoding="utf-8", errors="ignore") as f:
68
- lines = f.readlines()
69
-
70
- total_lines = len(lines)
71
-
72
- # 处理空文件情况
73
- if total_lines == 0:
74
- spinner.ok("✅")
75
- return {
76
- "success": True,
77
- "stdout": f"\n🔍 文件: {abs_path}\n📄 文件为空 (0行)\n",
78
- "stderr": "",
79
- }
80
-
81
- # 处理特殊值-1表示文件末尾
82
- if end_line == -1:
83
- end_line = total_lines
84
- else:
85
- end_line = (
86
- max(1, min(end_line, total_lines))
87
- if end_line >= 0
88
- else total_lines + end_line + 1
89
- )
90
-
91
- start_line = (
92
- max(1, min(start_line, total_lines))
93
- if start_line >= 0
94
- else total_lines + start_line + 1
95
- )
47
+ print(f"📖 正在读取文件: {abs_path}...")
48
+ # 文件存在性检查
49
+ if not os.path.exists(abs_path):
50
+ return {
51
+ "success": False,
52
+ "stdout": "",
53
+ "stderr": f"文件不存在: {abs_path}",
54
+ }
55
+
56
+ # 文件大小限制检查(10MB)
57
+ if os.path.getsize(abs_path) > 10 * 1024 * 1024:
58
+ return {
59
+ "success": False,
60
+ "stdout": "",
61
+ "stderr": "文件过大 (>10MB)",
62
+ }
63
+
64
+ # 读取文件内容
65
+ with open(abs_path, "r", encoding="utf-8", errors="ignore") as f:
66
+ lines = f.readlines()
96
67
 
97
- if start_line > end_line:
98
- spinner.fail("❌")
99
- return {
100
- "success": False,
101
- "stdout": "",
102
- "stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})",
103
- }
104
-
105
- # 添加行号并构建输出内容
106
- selected_lines = lines[start_line - 1 : end_line]
107
- numbered_content = "".join(
108
- [
109
- f"{i:4d}:{line}"
110
- for i, line in enumerate(selected_lines, start=start_line)
111
- ]
68
+ total_lines = len(lines)
69
+
70
+ # 处理空文件情况
71
+ if total_lines == 0:
72
+ print(f" 文件读取完成: {abs_path}")
73
+ return {
74
+ "success": True,
75
+ "stdout": f"\n🔍 文件: {abs_path}\n📄 文件为空 (0行)\n",
76
+ "stderr": "",
77
+ }
78
+
79
+ # 处理特殊值-1表示文件末尾
80
+ if end_line == -1:
81
+ end_line = total_lines
82
+ else:
83
+ end_line = (
84
+ max(1, min(end_line, total_lines))
85
+ if end_line >= 0
86
+ else total_lines + end_line + 1
112
87
  )
113
88
 
114
- # 构建输出格式
115
- output = (
116
- f"\n🔍 文件: {abs_path}\n"
117
- f"📄 原始行号: {start_line}-{end_line} (共{total_lines}行) \n\n"
118
- f"{numbered_content}\n\n"
89
+ start_line = (
90
+ max(1, min(start_line, total_lines))
91
+ if start_line >= 0
92
+ else total_lines + start_line + 1
93
+ )
94
+
95
+ if start_line > end_line:
96
+ print(
97
+ f"❌ 无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})"
119
98
  )
120
- spinner.text = f"文件读取完成: {abs_path}"
121
- spinner.ok("")
122
-
123
- if agent:
124
- files = agent.get_user_data("files")
125
- if files:
126
- files.append(abs_path)
127
- else:
128
- files = [abs_path]
129
- agent.set_user_data("files", files)
130
-
131
- return {"success": True, "stdout": output, "stderr": ""}
99
+ return {
100
+ "success": False,
101
+ "stdout": "",
102
+ "stderr": f"无效的行范围 [{start_line}-{end_line}] (总行数: {total_lines})",
103
+ }
104
+
105
+ # 添加行号并构建输出内容
106
+ selected_lines = lines[start_line - 1 : end_line]
107
+ numbered_content = "".join(
108
+ [
109
+ f"{i:4d}:{line}"
110
+ for i, line in enumerate(selected_lines, start=start_line)
111
+ ]
112
+ )
113
+
114
+ # 构建输出格式
115
+ output = (
116
+ f"\n🔍 文件: {abs_path}\n"
117
+ f"📄 原始行号: {start_line}-{end_line} (共{total_lines}行) \n\n"
118
+ f"{numbered_content}\n\n"
119
+ )
120
+ print(f"✅ 文件读取完成: {abs_path}")
121
+
122
+ if agent:
123
+ files = agent.get_user_data("files")
124
+ if files:
125
+ files.append(abs_path)
126
+ else:
127
+ files = [abs_path]
128
+ agent.set_user_data("files", files)
129
+
130
+ return {"success": True, "stdout": output, "stderr": ""}
132
131
 
133
132
  except Exception as e:
134
133
  PrettyOutput.print(str(e), OutputType.ERROR)
@@ -29,42 +29,7 @@ arguments:
29
29
  """,
30
30
  "description": "网页搜索",
31
31
  },
32
- "Plan": {
33
- "append": True,
34
- "template": f"""
35
- 请使用code_plan工具生成代码修改计划,必须严格遵守以下工具调用格式:
36
-
37
- {ot("TOOL_CALL")}
38
- want: 想要从执行结果中获取到的信息
39
- name: code_plan
40
- arguments:
41
- requirement: "需要实现用户登录功能,包括用户名密码验证和JWT生成"
42
- {ct("TOOL_CALL")}
43
-
44
- 请提供详细的需求描述和完整上下文信息:
45
-
46
- 必须包含的上下文信息:
47
- 1. 当前会话状态 - 当前正在处理的任务和进度
48
- 2. 用户历史请求 - 与本任务相关的历史请求
49
- 3. 系统状态 - 相关的系统配置和环境状态
50
- 4. 已确定的相关文件 - 已经分析出的需要修改的文件列表
51
-
52
- 示例:
53
- 1. 需要实现用户登录功能,包括用户名密码验证和JWT生成
54
- 2. 重构订单处理模块以提高性能
55
- 3. 优化数据库查询性能,减少响应时间
56
- 4. 添加支付网关集成功能
57
- 5. 修改用户权限管理系统
58
-
59
- code_plan工具将:
60
- 1. 分析项目结构确定相关文件
61
- 2. 理解需求后制定详细修改步骤
62
- 3. 按功能模块分组修改内容
63
- 4. 评估修改影响范围
64
- 5. 生成可执行的开发计划
65
- """,
66
- "description": "生成代码修改计划",
67
- },
32
+
68
33
  "FindRelatedFiles": {
69
34
  "append": False,
70
35
  "template": f"""
@@ -111,10 +111,20 @@ def get_shell_name() -> str:
111
111
  获取系统shell名称。
112
112
 
113
113
  返回:
114
- str: Shell名称(例如bash, zsh),默认为bash
115
- """
116
- shell_path = GLOBAL_CONFIG_DATA.get("SHELL", "/bin/bash")
117
- return os.path.basename(shell_path)
114
+ str: Shell名称(例如bash, zsh, fish),默认为bash
115
+
116
+ 获取顺序:
117
+ 1. 先从GLOBAL_CONFIG_DATA中获取JARVIS_SHELL配置
118
+ 2. 再从GLOBAL_CONFIG_DATA中获取SHELL配置
119
+ 3. 最后从环境变量SHELL获取
120
+ 4. 如果都未配置,则默认返回bash
121
+ """
122
+ shell_name = GLOBAL_CONFIG_DATA.get("JARVIS_SHELL")
123
+ if shell_name:
124
+ return shell_name.lower()
125
+
126
+ shell_path = GLOBAL_CONFIG_DATA.get("SHELL", os.getenv("SHELL", "/bin/bash"))
127
+ return os.path.basename(shell_path).lower()
118
128
 
119
129
 
120
130
  def get_normal_platform_name() -> str:
@@ -12,9 +12,10 @@ Git工具模块
12
12
  import os
13
13
  import re
14
14
  import subprocess
15
- from typing import Any, Dict, List, Tuple
15
+ from typing import Any, Dict, List, Set, Tuple
16
16
 
17
- from jarvis.jarvis_utils.config import get_auto_update, is_confirm_before_apply_patch
17
+ from jarvis.jarvis_utils.config import (get_auto_update,
18
+ is_confirm_before_apply_patch)
18
19
  from jarvis.jarvis_utils.output import OutputType, PrettyOutput
19
20
  from jarvis.jarvis_utils.utils import user_confirm
20
21
 
@@ -219,7 +220,6 @@ def handle_commit_workflow() -> bool:
219
220
  import subprocess
220
221
 
221
222
  try:
222
-
223
223
  confirm_add_new_files()
224
224
 
225
225
  if not has_uncommitted_changes():
@@ -411,7 +411,7 @@ def get_diff_file_list() -> List[str]:
411
411
  """
412
412
  try:
413
413
  confirm_add_new_files()
414
-
414
+
415
415
  # 暂存新增文件
416
416
  subprocess.run(["git", "add", "-N", "."], check=True)
417
417
 
@@ -488,14 +488,15 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
488
488
  )
489
489
  if files_result.returncode == 0:
490
490
  file_lines = files_result.stdout.splitlines()
491
- unique_files = set(filter(None, file_lines))
492
- commit["files"] = list(unique_files)[:20] # 限制最多20个文件
491
+ unique_files: Set[str] = set(filter(None, file_lines))
492
+ commit["files"] = list(unique_files)[:20] # type: ignore[list-item] # 限制最多20个文件
493
493
 
494
494
  return commits
495
495
 
496
496
  except subprocess.CalledProcessError:
497
497
  return []
498
498
 
499
+
499
500
  def _get_new_files() -> List[str]:
500
501
  """获取新增文件列表"""
501
502
  return subprocess.run(
@@ -505,8 +506,10 @@ def _get_new_files() -> List[str]:
505
506
  check=True,
506
507
  ).stdout.splitlines()
507
508
 
509
+
508
510
  def confirm_add_new_files() -> None:
509
511
  """确认新增文件、代码行数和二进制文件"""
512
+
510
513
  def _get_added_lines() -> int:
511
514
  """获取新增代码行数"""
512
515
  diff_stats = subprocess.run(
@@ -515,7 +518,7 @@ def confirm_add_new_files() -> None:
515
518
  text=True,
516
519
  check=True,
517
520
  ).stdout.splitlines()
518
-
521
+
519
522
  added_lines = 0
520
523
  for stat in diff_stats:
521
524
  parts = stat.split()
@@ -531,55 +534,53 @@ def confirm_add_new_files() -> None:
531
534
  binary_files = []
532
535
  for file in files:
533
536
  try:
534
- with open(file, 'rb') as f:
535
- if b'\x00' in f.read(1024):
537
+ with open(file, "rb") as f:
538
+ if b"\x00" in f.read(1024):
536
539
  binary_files.append(file)
537
540
  except (IOError, PermissionError):
538
541
  continue
539
542
  return binary_files
540
543
 
541
- def _check_conditions(new_files: List[str], added_lines: int, binary_files: List[str]) -> bool:
544
+ def _check_conditions(
545
+ new_files: List[str], added_lines: int, binary_files: List[str]
546
+ ) -> bool:
542
547
  """检查各种条件并打印提示信息"""
543
548
  need_confirm = False
544
-
549
+ output_lines = []
550
+
545
551
  if len(new_files) > 20:
546
- PrettyOutput.print(
547
- f"检测到{len(new_files)}个新增文件(选择N将重新检测)",
548
- OutputType.WARNING
549
- )
550
- PrettyOutput.print("新增文件列表:", OutputType.INFO)
551
- for file in new_files:
552
- PrettyOutput.print(f" - {file}", OutputType.INFO)
552
+ output_lines.append(f"检测到{len(new_files)}个新增文件(选择N将重新检测)")
553
+ output_lines.append("新增文件列表:")
554
+ output_lines.extend(f" - {file}" for file in new_files)
553
555
  need_confirm = True
554
-
556
+
555
557
  if added_lines > 500:
556
- PrettyOutput.print(
557
- f"检测到{added_lines}行新增代码(选择N将重新检测)",
558
- OutputType.WARNING
559
- )
558
+ output_lines.append(f"检测到{added_lines}行新增代码(选择N将重新检测)")
560
559
  need_confirm = True
561
-
560
+
562
561
  if binary_files:
562
+ output_lines.append(f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)")
563
+ output_lines.append("二进制文件列表:")
564
+ output_lines.extend(f" - {file}" for file in binary_files)
565
+ need_confirm = True
566
+
567
+ if output_lines:
563
568
  PrettyOutput.print(
564
- f"检测到{len(binary_files)}个二进制文件(选择N将重新检测)",
565
- OutputType.WARNING
569
+ "\n".join(output_lines),
570
+ OutputType.WARNING if need_confirm else OutputType.INFO,
566
571
  )
567
- PrettyOutput.print("二进制文件列表:", OutputType.INFO)
568
- for file in binary_files:
569
- PrettyOutput.print(f" - {file}", OutputType.INFO)
570
- need_confirm = True
571
-
572
+
572
573
  return need_confirm
573
574
 
574
575
  while True:
575
576
  new_files = _get_new_files()
576
577
  added_lines = _get_added_lines()
577
578
  binary_files = _get_binary_files(new_files)
578
-
579
+
579
580
  if not _check_conditions(new_files, added_lines, binary_files):
580
581
  break
581
-
582
+
582
583
  if not user_confirm("是否要添加这些变更(如果不需要请修改.gitignore文件以忽略不需要的文件)?", False):
583
584
  continue
584
-
585
- break
585
+
586
+ break