jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__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 (159) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +243 -139
  3. jarvis/jarvis_agent/agent_manager.py +5 -10
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +265 -15
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +113 -98
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +6 -12
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +77 -14
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +12 -21
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/task_analyzer.py +26 -4
  31. jarvis/jarvis_agent/task_manager.py +11 -27
  32. jarvis/jarvis_agent/tool_executor.py +2 -3
  33. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  34. jarvis/jarvis_agent/web_server.py +55 -20
  35. jarvis/jarvis_c2rust/__init__.py +5 -5
  36. jarvis/jarvis_c2rust/cli.py +461 -499
  37. jarvis/jarvis_c2rust/collector.py +45 -53
  38. jarvis/jarvis_c2rust/constants.py +26 -0
  39. jarvis/jarvis_c2rust/library_replacer.py +264 -132
  40. jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
  41. jarvis/jarvis_c2rust/loaders.py +207 -0
  42. jarvis/jarvis_c2rust/models.py +28 -0
  43. jarvis/jarvis_c2rust/optimizer.py +1592 -395
  44. jarvis/jarvis_c2rust/transpiler.py +1722 -1064
  45. jarvis/jarvis_c2rust/utils.py +385 -0
  46. jarvis/jarvis_code_agent/build_validation_config.py +2 -3
  47. jarvis/jarvis_code_agent/code_agent.py +394 -320
  48. jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
  61. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
  62. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
  63. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
  64. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
  65. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  66. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
  68. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
  69. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  70. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
  71. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  72. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
  73. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
  74. jarvis/jarvis_code_agent/lint.py +258 -27
  75. jarvis/jarvis_code_agent/utils.py +0 -1
  76. jarvis/jarvis_code_analysis/code_review.py +19 -24
  77. jarvis/jarvis_data/config_schema.json +53 -26
  78. jarvis/jarvis_git_squash/main.py +4 -5
  79. jarvis/jarvis_git_utils/git_commiter.py +44 -49
  80. jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
  81. jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
  82. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  83. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  84. jarvis/jarvis_methodology/main.py +32 -48
  85. jarvis/jarvis_multi_agent/__init__.py +79 -61
  86. jarvis/jarvis_multi_agent/main.py +3 -7
  87. jarvis/jarvis_platform/base.py +469 -199
  88. jarvis/jarvis_platform/human.py +7 -8
  89. jarvis/jarvis_platform/kimi.py +30 -36
  90. jarvis/jarvis_platform/openai.py +65 -27
  91. jarvis/jarvis_platform/registry.py +26 -10
  92. jarvis/jarvis_platform/tongyi.py +24 -25
  93. jarvis/jarvis_platform/yuanbao.py +31 -42
  94. jarvis/jarvis_platform_manager/main.py +66 -77
  95. jarvis/jarvis_platform_manager/service.py +8 -13
  96. jarvis/jarvis_rag/cli.py +49 -51
  97. jarvis/jarvis_rag/embedding_manager.py +13 -18
  98. jarvis/jarvis_rag/llm_interface.py +8 -9
  99. jarvis/jarvis_rag/query_rewriter.py +10 -21
  100. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  101. jarvis/jarvis_rag/reranker.py +4 -5
  102. jarvis/jarvis_rag/retriever.py +28 -30
  103. jarvis/jarvis_sec/__init__.py +220 -3520
  104. jarvis/jarvis_sec/agents.py +143 -0
  105. jarvis/jarvis_sec/analysis.py +276 -0
  106. jarvis/jarvis_sec/cli.py +29 -6
  107. jarvis/jarvis_sec/clustering.py +1439 -0
  108. jarvis/jarvis_sec/file_manager.py +427 -0
  109. jarvis/jarvis_sec/parsers.py +73 -0
  110. jarvis/jarvis_sec/prompts.py +268 -0
  111. jarvis/jarvis_sec/report.py +83 -4
  112. jarvis/jarvis_sec/review.py +453 -0
  113. jarvis/jarvis_sec/utils.py +499 -0
  114. jarvis/jarvis_sec/verification.py +848 -0
  115. jarvis/jarvis_sec/workflow.py +7 -0
  116. jarvis/jarvis_smart_shell/main.py +38 -87
  117. jarvis/jarvis_stats/cli.py +1 -1
  118. jarvis/jarvis_stats/stats.py +7 -7
  119. jarvis/jarvis_stats/storage.py +15 -21
  120. jarvis/jarvis_tools/clear_memory.py +3 -20
  121. jarvis/jarvis_tools/cli/main.py +20 -23
  122. jarvis/jarvis_tools/edit_file.py +1066 -0
  123. jarvis/jarvis_tools/execute_script.py +42 -21
  124. jarvis/jarvis_tools/file_analyzer.py +6 -9
  125. jarvis/jarvis_tools/generate_new_tool.py +11 -20
  126. jarvis/jarvis_tools/lsp_client.py +1552 -0
  127. jarvis/jarvis_tools/methodology.py +2 -3
  128. jarvis/jarvis_tools/read_code.py +1525 -87
  129. jarvis/jarvis_tools/read_symbols.py +2 -3
  130. jarvis/jarvis_tools/read_webpage.py +7 -10
  131. jarvis/jarvis_tools/registry.py +370 -181
  132. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  133. jarvis/jarvis_tools/rewrite_file.py +105 -0
  134. jarvis/jarvis_tools/save_memory.py +3 -15
  135. jarvis/jarvis_tools/search_web.py +3 -7
  136. jarvis/jarvis_tools/sub_agent.py +17 -6
  137. jarvis/jarvis_tools/sub_code_agent.py +14 -16
  138. jarvis/jarvis_tools/virtual_tty.py +54 -32
  139. jarvis/jarvis_utils/clipboard.py +7 -10
  140. jarvis/jarvis_utils/config.py +98 -63
  141. jarvis/jarvis_utils/embedding.py +5 -5
  142. jarvis/jarvis_utils/fzf.py +8 -8
  143. jarvis/jarvis_utils/git_utils.py +81 -67
  144. jarvis/jarvis_utils/input.py +24 -49
  145. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  146. jarvis/jarvis_utils/methodology.py +33 -35
  147. jarvis/jarvis_utils/utils.py +245 -202
  148. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
  149. jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
  150. jarvis/jarvis_agent/edit_file_handler.py +0 -584
  151. jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
  152. jarvis/jarvis_agent/task_planner.py +0 -496
  153. jarvis/jarvis_platform/ai8.py +0 -332
  154. jarvis/jarvis_tools/ask_user.py +0 -54
  155. jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
  156. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
  157. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
  158. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
  159. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
@@ -63,13 +63,7 @@ def get_replace_map() -> dict:
63
63
  if not os.path.exists(replace_map_path):
64
64
  return BUILTIN_REPLACE_MAP.copy()
65
65
 
66
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
67
-
68
- PrettyOutput.print(
69
- "警告:使用replace_map.yaml进行配置的方式已被弃用,将在未来版本中移除。"
70
- "请迁移到使用GLOBAL_CONFIG_DATA中的JARVIS_REPLACE_MAP配置。",
71
- output_type=OutputType.WARNING,
72
- )
66
+ print("⚠️ 警告:使用replace_map.yaml进行配置的方式已被弃用,将在未来版本中移除。请迁移到使用GLOBAL_CONFIG_DATA中的JARVIS_REPLACE_MAP配置。")
73
67
 
74
68
  with open(replace_map_path, "r", encoding="utf-8", errors="ignore") as file:
75
69
  file_map = yaml.safe_load(file) or {}
@@ -139,10 +133,24 @@ def _get_resolved_model_config(
139
133
  model_groups = GLOBAL_CONFIG_DATA.get("JARVIS_LLM_GROUPS", [])
140
134
 
141
135
  if model_group_name and isinstance(model_groups, list):
136
+ found = False
142
137
  for group_item in model_groups:
143
138
  if isinstance(group_item, dict) and model_group_name in group_item:
144
139
  group_config = group_item[model_group_name]
140
+ found = True
145
141
  break
142
+
143
+ # 当显式指定了模型组但未找到时,报错并退出
144
+ if model_group_override and not found:
145
+ print(f"❌ 错误:指定的模型组 '{model_group_name}' 不存在于配置中。")
146
+ print("ℹ️ 可用的模型组: " +
147
+ ", ".join(
148
+ list(group.keys())[0]
149
+ for group in model_groups
150
+ if isinstance(group, dict)
151
+ ) if model_groups else "无可用模型组")
152
+ import sys
153
+ sys.exit(1)
146
154
 
147
155
  _apply_llm_group_env_override(group_config)
148
156
 
@@ -157,6 +165,10 @@ def _get_resolved_model_config(
157
165
  "JARVIS_PLATFORM",
158
166
  "JARVIS_MODEL",
159
167
  "JARVIS_MAX_INPUT_TOKEN_COUNT",
168
+ "JARVIS_CHEAP_PLATFORM",
169
+ "JARVIS_CHEAP_MODEL",
170
+ "JARVIS_SMART_PLATFORM",
171
+ "JARVIS_SMART_MODEL",
160
172
  ]
161
173
  for key in override_keys:
162
174
  if key in GLOBAL_CONFIG_DATA:
@@ -176,10 +188,10 @@ def get_normal_platform_name(model_group_override: Optional[str] = None) -> str:
176
188
  获取正常操作的平台名称。
177
189
 
178
190
  返回:
179
- str: 平台名称,默认为'yuanbao'
191
+ str: 平台名称,默认为'openai'
180
192
  """
181
193
  config = _get_resolved_model_config(model_group_override)
182
- return cast(str, config.get("JARVIS_PLATFORM", "yuanbao"))
194
+ return cast(str, config.get("JARVIS_PLATFORM", "openai"))
183
195
 
184
196
 
185
197
  def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
@@ -187,10 +199,10 @@ def get_normal_model_name(model_group_override: Optional[str] = None) -> str:
187
199
  获取正常操作的模型名称。
188
200
 
189
201
  返回:
190
- str: 模型名称,默认为'deep_seek_v3'
202
+ str: 模型名称,默认为'gpt-5'
191
203
  """
192
204
  config = _get_resolved_model_config(model_group_override)
193
- return cast(str, config.get("JARVIS_MODEL", "deep_seek_v3"))
205
+ return cast(str, config.get("JARVIS_MODEL", "gpt-5"))
194
206
 
195
207
 
196
208
  def _deprecated_platform_name_v1(model_group_override: Optional[str] = None) -> str:
@@ -217,6 +229,62 @@ def _deprecated_model_name_v1(model_group_override: Optional[str] = None) -> str
217
229
  return get_normal_model_name(model_group_override)
218
230
 
219
231
 
232
+ def get_cheap_platform_name(model_group_override: Optional[str] = None) -> str:
233
+ """
234
+ 获取廉价操作的平台名称。
235
+
236
+ 返回:
237
+ str: 平台名称,如果未配置则回退到正常操作平台
238
+ """
239
+ config = _get_resolved_model_config(model_group_override)
240
+ cheap_platform = config.get("JARVIS_CHEAP_PLATFORM")
241
+ if cheap_platform:
242
+ return cast(str, cheap_platform)
243
+ return get_normal_platform_name(model_group_override)
244
+
245
+
246
+ def get_cheap_model_name(model_group_override: Optional[str] = None) -> str:
247
+ """
248
+ 获取廉价操作的模型名称。
249
+
250
+ 返回:
251
+ str: 模型名称,如果未配置则回退到正常操作模型
252
+ """
253
+ config = _get_resolved_model_config(model_group_override)
254
+ cheap_model = config.get("JARVIS_CHEAP_MODEL")
255
+ if cheap_model:
256
+ return cast(str, cheap_model)
257
+ return get_normal_model_name(model_group_override)
258
+
259
+
260
+ def get_smart_platform_name(model_group_override: Optional[str] = None) -> str:
261
+ """
262
+ 获取智能操作的平台名称。
263
+
264
+ 返回:
265
+ str: 平台名称,如果未配置则回退到正常操作平台
266
+ """
267
+ config = _get_resolved_model_config(model_group_override)
268
+ smart_platform = config.get("JARVIS_SMART_PLATFORM")
269
+ if smart_platform:
270
+ return cast(str, smart_platform)
271
+ return get_normal_platform_name(model_group_override)
272
+
273
+
274
+ def get_smart_model_name(model_group_override: Optional[str] = None) -> str:
275
+ """
276
+ 获取智能操作的模型名称。
277
+
278
+ 返回:
279
+ str: 模型名称,如果未配置则回退到正常操作模型
280
+ """
281
+ config = _get_resolved_model_config(model_group_override)
282
+ smart_model = config.get("JARVIS_SMART_MODEL")
283
+ if smart_model:
284
+ return cast(str, smart_model)
285
+ return get_normal_model_name(model_group_override)
286
+
287
+
220
288
  def is_execute_tool_confirm() -> bool:
221
289
  """
222
290
  检查工具执行是否需要确认。
@@ -237,28 +305,11 @@ def is_confirm_before_apply_patch() -> bool:
237
305
  return cast(bool, GLOBAL_CONFIG_DATA.get("JARVIS_CONFIRM_BEFORE_APPLY_PATCH", False))
238
306
 
239
307
 
240
- def get_patch_format() -> str:
241
- """
242
- 获取补丁格式。
243
-
244
- - "search": 仅使用精确匹配的 `SEARCH` 模式。此模式对能力较弱的模型更稳定,因为它要求代码片段完全匹配。
245
- - "search_range": 仅使用 `SEARCH_START` 和 `SEARCH_END` 的范围匹配模式。此模式对能力较强的模型更灵活,因为它允许在代码块内部进行修改,而不要求整个块完全匹配。
246
- - "all": 同时支持以上两种模式(默认)。
247
-
248
- 返回:
249
- str: "all", "search", or "search_range"
250
- """
251
- mode = GLOBAL_CONFIG_DATA.get("JARVIS_PATCH_FORMAT", "all")
252
- if mode in ["all", "search", "search_range"]:
253
- return cast(str, mode)
254
- return "all"
255
-
256
-
257
308
  def get_data_dir() -> str:
258
309
  """
259
310
  获取Jarvis数据存储目录路径。
260
311
 
261
- 返回:
312
+ 返回:
262
313
  str: 数据目录路径,优先从JARVIS_DATA_PATH环境变量获取,
263
314
  如果未设置或为空,则使用~/.jarvis作为默认值
264
315
  """
@@ -730,40 +781,6 @@ def get_tool_filter_threshold() -> int:
730
781
  """
731
782
  return int(GLOBAL_CONFIG_DATA.get("JARVIS_TOOL_FILTER_THRESHOLD", 30))
732
783
 
733
- def get_plan_max_depth() -> int:
734
- """
735
- 获取任务规划的最大层数。
736
-
737
- 返回:
738
- int: 最大规划层数,默认为2(可通过 GLOBAL_CONFIG_DATA['JARVIS_PLAN_MAX_DEPTH'] 配置)
739
- """
740
- try:
741
- return int(GLOBAL_CONFIG_DATA.get("JARVIS_PLAN_MAX_DEPTH", 2))
742
- except Exception:
743
- return 2
744
-
745
-
746
- def is_plan_enabled() -> bool:
747
- """
748
- 获取是否默认启用任务规划。
749
-
750
- 返回:
751
- bool: 如果启用任务规划则返回True,默认为True
752
- """
753
- return GLOBAL_CONFIG_DATA.get("JARVIS_PLAN_ENABLED", True) is True
754
-
755
-
756
- def get_auto_summary_rounds() -> int:
757
- """
758
- 获取基于对话轮次的自动总结阈值。
759
-
760
- 返回:
761
- int: 轮次阈值,默认20
762
- """
763
- try:
764
- return int(GLOBAL_CONFIG_DATA.get("JARVIS_AUTO_SUMMARY_ROUNDS", 50))
765
- except Exception:
766
- return 50
767
784
 
768
785
 
769
786
 
@@ -871,3 +888,21 @@ def is_enable_intent_recognition() -> bool:
871
888
  bool: 是否启用意图识别,默认为True(可通过 GLOBAL_CONFIG_DATA['JARVIS_ENABLE_INTENT_RECOGNITION'] 配置)
872
889
  """
873
890
  return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_INTENT_RECOGNITION", True) is True
891
+
892
+
893
+ def is_enable_memory_organizer() -> bool:
894
+ """
895
+ 获取是否启用自动记忆整理功能。
896
+
897
+ 返回:
898
+ bool: 是否启用自动记忆整理,默认为False(可通过 GLOBAL_CONFIG_DATA['JARVIS_ENABLE_MEMORY_ORGANIZER'] 配置)
899
+ """
900
+ return GLOBAL_CONFIG_DATA.get("JARVIS_ENABLE_MEMORY_ORGANIZER", False) is True
901
+ def get_conversation_turn_threshold() -> int:
902
+ """
903
+ 获取对话轮次阈值,用于触发总结。
904
+
905
+ 返回:
906
+ int: 对话轮次阈值,默认为50
907
+ """
908
+ return int(GLOBAL_CONFIG_DATA.get("JARVIS_CONVERSATION_TURN_THRESHOLD", 50))
@@ -3,7 +3,6 @@ import os
3
3
  from pathlib import Path
4
4
  from typing import List
5
5
 
6
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
7
6
 
8
7
  # 设置tiktoken缓存目录
9
8
  script_dir = Path(__file__).parent
@@ -28,10 +27,11 @@ def get_context_token_count(text: str) -> int:
28
27
  import tiktoken
29
28
 
30
29
  encoding = tiktoken.get_encoding("cl100k_base")
31
- return len(encoding.encode(text))
30
+ # 调整token计算为原来的10/7倍
31
+ return int(len(encoding.encode(text)) * 10 / 7)
32
32
  except Exception as e:
33
- PrettyOutput.print(f"计算token失败: {str(e)}", OutputType.WARNING)
34
- return len(text) // 4 # 每个token大约4个字符的粗略估计
33
+ print(f"⚠️ 计算token失败: {str(e)}")
34
+ return int(len(text) // 4 * 10 / 7) # 每个token大约4个字符的粗略估计,调整为10/7倍
35
35
 
36
36
 
37
37
  def split_text_into_chunks(
@@ -80,6 +80,6 @@ def split_text_into_chunks(
80
80
  return chunks
81
81
 
82
82
  except Exception as e:
83
- PrettyOutput.print(f"文本分割失败: {str(e)}", OutputType.WARNING)
83
+ print(f"⚠️ 文本分割失败: {str(e)}")
84
84
  # 发生错误时回退到简单的字符分割
85
85
  return [text[i : i + max_length] for i in range(0, len(text), max_length)]
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- """FZF selector utility."""
2
+ """FZF选择器工具。"""
3
3
  import shutil
4
4
  import subprocess
5
5
  from typing import List, Optional, Union, Dict, Any, cast
@@ -10,15 +10,15 @@ def fzf_select(
10
10
  key: Optional[str] = None,
11
11
  ) -> Optional[str]:
12
12
  """
13
- Uses fzf to select an item from a list.
13
+ 使用fzf从列表中选择一个项目。
14
14
 
15
- Args:
16
- options: A list of strings or dicts to choose from.
17
- prompt: The prompt to display in fzf.
18
- key: If options is a list of dicts, this is the key to display.
15
+ 参数:
16
+ options: 可供选择的字符串或字典列表。
17
+ prompt: fzf中显示的提示信息。
18
+ key: 如果options是字典列表,则此参数指定要显示的键名。
19
19
 
20
- Returns:
21
- The selected item, or None if fzf is not available or the selection is cancelled.
20
+ 返回:
21
+ 选中的项目,如果fzf不可用或选择被取消则返回None
22
22
  """
23
23
  if shutil.which("fzf") is None:
24
24
  return None
@@ -17,7 +17,6 @@ import sys
17
17
  from typing import Any, Dict, List, Optional, Set, Tuple
18
18
 
19
19
  from jarvis.jarvis_utils.config import get_data_dir, is_confirm_before_apply_patch
20
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
21
20
  from jarvis.jarvis_utils.input import user_confirm
22
21
  from jarvis.jarvis_utils.utils import is_rag_installed
23
22
 
@@ -111,7 +110,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
111
110
  )
112
111
  if result.returncode != 0:
113
112
  error_msg = result.stderr.decode("utf-8", errors="replace")
114
- PrettyOutput.print(f"获取commit历史失败: {error_msg}", OutputType.ERROR)
113
+ print(f"获取commit历史失败: {error_msg}")
115
114
  return []
116
115
 
117
116
  output = result.stdout.decode("utf-8", errors="replace")
@@ -123,7 +122,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
123
122
  return commits
124
123
 
125
124
  except Exception as e:
126
- PrettyOutput.print(f"获取commit历史异常: {str(e)}", OutputType.ERROR)
125
+ print(f"获取commit历史异常: {str(e)}")
127
126
  return []
128
127
 
129
128
 
@@ -172,6 +171,59 @@ def get_diff() -> str:
172
171
  return f"发生意外错误: {str(e)}"
173
172
 
174
173
 
174
+ def get_diff_between_commits(start_hash: str, end_hash: Optional[str] = None) -> str:
175
+ """获取两个commit之间的差异
176
+
177
+ 参数:
178
+ start_hash: 起始commit哈希值(不包含)
179
+ end_hash: 结束commit哈希值(包含),如果为None则使用HEAD
180
+
181
+ 返回:
182
+ str: 差异内容或错误信息
183
+ """
184
+ try:
185
+ if end_hash is None:
186
+ # 如果end_hash为None,使用HEAD
187
+ end_hash = "HEAD"
188
+
189
+ # 检查start_hash是否存在
190
+ start_check = subprocess.run(
191
+ ["git", "rev-parse", "--verify", start_hash],
192
+ stderr=subprocess.PIPE,
193
+ stdout=subprocess.PIPE,
194
+ )
195
+ if start_check.returncode != 0:
196
+ return f"起始commit不存在: {start_hash}"
197
+
198
+ # 检查end_hash是否存在
199
+ end_check = subprocess.run(
200
+ ["git", "rev-parse", "--verify", end_hash],
201
+ stderr=subprocess.PIPE,
202
+ stdout=subprocess.PIPE,
203
+ )
204
+ if end_check.returncode != 0:
205
+ return f"结束commit不存在: {end_hash}"
206
+
207
+ # 获取两个commit之间的差异
208
+ result = subprocess.run(
209
+ ["git", "diff", f"{start_hash}..{end_hash}"],
210
+ capture_output=True,
211
+ text=False,
212
+ check=True,
213
+ )
214
+
215
+ try:
216
+ return result.stdout.decode("utf-8")
217
+ except UnicodeDecodeError:
218
+ return result.stdout.decode("utf-8", errors="replace")
219
+
220
+ except subprocess.CalledProcessError as e:
221
+ error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
222
+ return f"获取commit差异失败: {error_msg}"
223
+ except Exception as e:
224
+ return f"发生意外错误: {str(e)}"
225
+
226
+
175
227
  def revert_file(filepath: str) -> None:
176
228
  """增强版git恢复,处理新文件"""
177
229
  import subprocess
@@ -191,7 +243,7 @@ def revert_file(filepath: str) -> None:
191
243
  subprocess.run(["git", "clean", "-f", "--", filepath], check=True)
192
244
  except subprocess.CalledProcessError as e:
193
245
  error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
194
- PrettyOutput.print(f"恢复文件失败: {error_msg}", OutputType.ERROR)
246
+ print(f"恢复文件失败: {error_msg}")
195
247
 
196
248
 
197
249
  # 修改后的恢复函数
@@ -212,10 +264,10 @@ def revert_change() -> None:
212
264
  subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)
213
265
  subprocess.run(["git", "clean", "-fd"], check=True)
214
266
  except subprocess.CalledProcessError as e:
215
- PrettyOutput.print(f"恢复更改失败: {str(e)}", OutputType.ERROR)
267
+ print(f"恢复更改失败: {str(e)}")
216
268
 
217
269
 
218
- def detect_large_code_deletion(threshold: int = 200) -> Optional[Dict[str, int]]:
270
+ def detect_large_code_deletion(threshold: int = 30) -> Optional[Dict[str, int]]:
219
271
  """检测是否有大量代码删除
220
272
 
221
273
  参数:
@@ -290,49 +342,23 @@ def detect_large_code_deletion(threshold: int = 200) -> Optional[Dict[str, int]]
290
342
  return None
291
343
 
292
344
 
293
- def confirm_large_code_deletion(detection_result: Dict[str, int]) -> bool:
294
- """询问用户是否确认大量代码删除
295
-
296
- 参数:
297
- detection_result: 检测结果字典,包含 'insertions', 'deletions', 'net_deletions'
298
-
299
- 返回:
300
- bool: 如果用户确认,返回True;如果用户拒绝,返回False
301
- """
302
- insertions = detection_result['insertions']
303
- deletions = detection_result['deletions']
304
- net_deletions = detection_result['net_deletions']
305
-
306
- PrettyOutput.print(
307
- f"⚠️ 检测到大量代码删除:净删除 {net_deletions} 行(删除 {deletions} 行,新增 {insertions} 行)",
308
- OutputType.WARNING,
309
- )
310
- if not user_confirm(
311
- "此补丁包含大量代码删除,是否合理?", default=True
312
- ):
313
- # 用户认为不合理,拒绝提交
314
- revert_change()
315
- PrettyOutput.print(
316
- "已拒绝本次提交(用户认为补丁不合理)", OutputType.INFO
317
- )
318
- return False
319
- return True
345
+ # confirm_large_code_deletion函数已废弃,统一使用大模型询问
320
346
 
321
347
 
322
- def check_large_code_deletion(threshold: int = 200) -> bool:
323
- """检查是否有大量代码删除并询问用户确认
348
+ def check_large_code_deletion(threshold: int = 30) -> bool:
349
+ """检查是否有大量代码删除
324
350
 
325
351
  参数:
326
352
  threshold: 净删除行数阈值,默认200行
327
353
 
328
354
  返回:
329
- bool: 如果检测到大量删除且用户拒绝提交,返回False;否则返回True
355
+ bool: 始终返回True,由调用方统一处理大模型询问
330
356
  """
331
- detection_result = detect_large_code_deletion(threshold)
332
- if detection_result is None:
333
- return True
357
+ # 检测功能现在由调用方统一处理
358
+ return True
334
359
 
335
- return confirm_large_code_deletion(detection_result)
360
+ # 直接返回True,让调用方统一处理大模型询问
361
+ return True
336
362
 
337
363
 
338
364
  def handle_commit_workflow() -> bool:
@@ -530,23 +556,17 @@ def check_and_update_git_repo(repo_path: str) -> bool:
530
556
  and remote_tag_result.returncode == 0
531
557
  and local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()
532
558
  ):
533
- PrettyOutput.print(
534
- f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...",
535
- OutputType.INFO,
536
- )
559
+ print(f"ℹ️ 检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...")
537
560
  subprocess.run(
538
561
  ["git", "checkout", remote_tag_result.stdout.strip()],
539
562
  cwd=git_root,
540
563
  check=True,
541
564
  )
542
- PrettyOutput.print(
543
- f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}",
544
- OutputType.SUCCESS,
545
- )
565
+ print(f"✅ Jarvis已更新到tag {remote_tag_result.stdout.strip()}")
546
566
 
547
567
  # 执行pip安装更新代码
548
568
  try:
549
- PrettyOutput.print("正在安装更新后的代码...", OutputType.INFO)
569
+ print("ℹ️ 正在安装更新后的代码...")
550
570
 
551
571
  # 检查是否在虚拟环境中
552
572
  in_venv = hasattr(sys, "real_prefix") or (
@@ -603,7 +623,7 @@ def check_and_update_git_repo(repo_path: str) -> bool:
603
623
  )
604
624
 
605
625
  if result.returncode == 0:
606
- PrettyOutput.print("代码更新安装成功", OutputType.SUCCESS)
626
+ print("代码更新安装成功")
607
627
  return True
608
628
 
609
629
  # 处理权限错误
@@ -621,23 +641,21 @@ def check_and_update_git_repo(repo_path: str) -> bool:
621
641
  text=True,
622
642
  )
623
643
  if user_result.returncode == 0:
624
- PrettyOutput.print("用户级代码安装成功", OutputType.SUCCESS)
644
+ print("用户级代码安装成功")
625
645
  return True
626
646
  error_msg = user_result.stderr.strip()
627
647
 
628
- PrettyOutput.print(f"代码安装失败: {error_msg}", OutputType.ERROR)
648
+ print(f"代码安装失败: {error_msg}")
629
649
  return False
630
650
  except Exception as e:
631
- PrettyOutput.print(
632
- f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR
633
- )
651
+ print(f"❌ 安装过程中发生意外错误: {str(e)}")
634
652
  return False
635
653
  # 更新检查日期文件
636
654
  with open(last_check_file, "w") as f:
637
655
  f.write(today_str)
638
656
  return False
639
657
  except Exception as e:
640
- PrettyOutput.print(f"Git仓库更新检查失败: {e}", OutputType.WARNING)
658
+ print(f"⚠️ Git仓库更新检查失败: {e}")
641
659
  return False
642
660
  finally:
643
661
  os.chdir(curr_dir)
@@ -664,18 +682,16 @@ def get_diff_file_list() -> List[str]:
664
682
  subprocess.run(["git", "reset"], check=True)
665
683
 
666
684
  if result.returncode != 0:
667
- PrettyOutput.print(
668
- f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
669
- )
685
+ print(f"❌ 获取差异文件列表失败: {result.stderr}")
670
686
  return []
671
687
 
672
688
  return [f for f in result.stdout.splitlines() if f]
673
689
 
674
690
  except subprocess.CalledProcessError as e:
675
- PrettyOutput.print(f"获取差异文件列表失败: {str(e)}", OutputType.ERROR)
691
+ print(f"获取差异文件列表失败: {str(e)}")
676
692
  return []
677
693
  except Exception as e:
678
- PrettyOutput.print(f"获取差异文件列表异常: {str(e)}", OutputType.ERROR)
694
+ print(f"获取差异文件列表异常: {str(e)}")
679
695
  return []
680
696
 
681
697
 
@@ -824,10 +840,8 @@ def confirm_add_new_files() -> None:
824
840
  need_confirm = True
825
841
 
826
842
  if output_lines:
827
- PrettyOutput.print(
828
- "\n".join(output_lines),
829
- OutputType.WARNING if need_confirm else OutputType.INFO,
830
- )
843
+ emoji = "⚠️ " if need_confirm else "ℹ️ "
844
+ print(emoji + ("\n" + emoji).join(output_lines))
831
845
 
832
846
  return need_confirm
833
847
 
@@ -878,9 +892,9 @@ def confirm_add_new_files() -> None:
878
892
  entry = rel_path if not rel_path.startswith("..") else file
879
893
  if entry not in existing_lines:
880
894
  f.write(entry + "\n")
881
- PrettyOutput.print("已将未跟踪文件添加到 .gitignore,正在重新检测...", OutputType.INFO)
895
+ print("ℹ️ 已将未跟踪文件添加到 .gitignore,正在重新检测...")
882
896
  except Exception as e:
883
- PrettyOutput.print(f"更新 .gitignore 失败: {str(e)}", OutputType.WARNING)
897
+ print(f"⚠️ 更新 .gitignore 失败: {str(e)}")
884
898
 
885
899
  continue
886
900