jarvis-ai-assistant 0.3.30__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +458 -152
- jarvis/jarvis_agent/agent_manager.py +17 -13
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +329 -0
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +628 -55
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +34 -10
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +105 -9
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +20 -22
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +31 -6
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/utils.py +5 -1
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +786 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +575 -0
- jarvis/jarvis_c2rust/collector.py +250 -0
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +1254 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1272 -0
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +2157 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2983 -0
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +132 -0
- jarvis/jarvis_code_agent/code_agent.py +1371 -220
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +65 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +106 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +72 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +70 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +53 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +47 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +61 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +153 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +648 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +110 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +49 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +299 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +215 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +269 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +281 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +605 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +252 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +58 -0
- jarvis/jarvis_code_agent/lint.py +501 -8
- jarvis/jarvis_code_agent/utils.py +141 -0
- jarvis/jarvis_code_analysis/code_review.py +493 -584
- jarvis/jarvis_data/config_schema.json +128 -12
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +82 -75
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -29
- jarvis/jarvis_mcp/stdio_mcp_client.py +12 -13
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +287 -55
- jarvis/jarvis_multi_agent/main.py +36 -4
- jarvis/jarvis_platform/base.py +524 -202
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +88 -25
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +32 -43
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +53 -55
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +305 -0
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +139 -0
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +336 -0
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +226 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +2 -2
- jarvis/jarvis_stats/stats.py +8 -8
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_stats/visualizer.py +1 -1
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +21 -23
- jarvis/jarvis_tools/edit_file.py +1019 -132
- jarvis/jarvis_tools/execute_script.py +83 -25
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +14 -21
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1736 -35
- jarvis/jarvis_tools/read_symbols.py +140 -0
- jarvis/jarvis_tools/read_webpage.py +12 -13
- jarvis/jarvis_tools/registry.py +427 -200
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +72 -158
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +18 -18
- jarvis/jarvis_tools/sub_agent.py +36 -43
- jarvis/jarvis_tools/sub_code_agent.py +25 -26
- jarvis/jarvis_tools/virtual_tty.py +55 -33
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +232 -45
- jarvis/jarvis_utils/embedding.py +8 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +225 -36
- jarvis/jarvis_utils/globals.py +3 -3
- jarvis/jarvis_utils/http.py +1 -1
- jarvis/jarvis_utils/input.py +99 -48
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +52 -48
- jarvis/jarvis_utils/utils.py +819 -491
- jarvis_ai_assistant-0.7.6.dist-info/METADATA +600 -0
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +4 -0
- jarvis/jarvis_agent/config.py +0 -92
- jarvis/jarvis_agent/edit_file_handler.py +0 -296
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.3.30.dist-info/METADATA +0 -381
- jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -14,10 +14,9 @@ import os
|
|
|
14
14
|
import re
|
|
15
15
|
import subprocess
|
|
16
16
|
import sys
|
|
17
|
-
from typing import Any, Dict, List, Set, Tuple
|
|
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
|
|
|
@@ -34,7 +33,13 @@ def find_git_root_and_cd(start_dir: str = ".") -> str:
|
|
|
34
33
|
"""
|
|
35
34
|
os.chdir(start_dir)
|
|
36
35
|
try:
|
|
37
|
-
|
|
36
|
+
result = subprocess.run(
|
|
37
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
38
|
+
capture_output=True,
|
|
39
|
+
text=True,
|
|
40
|
+
check=True,
|
|
41
|
+
)
|
|
42
|
+
git_root = result.stdout.strip()
|
|
38
43
|
if not git_root:
|
|
39
44
|
subprocess.run(["git", "init"], check=True)
|
|
40
45
|
git_root = os.path.abspath(".")
|
|
@@ -105,7 +110,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
105
110
|
)
|
|
106
111
|
if result.returncode != 0:
|
|
107
112
|
error_msg = result.stderr.decode("utf-8", errors="replace")
|
|
108
|
-
|
|
113
|
+
print(f"❌ 获取commit历史失败: {error_msg}")
|
|
109
114
|
return []
|
|
110
115
|
|
|
111
116
|
output = result.stdout.decode("utf-8", errors="replace")
|
|
@@ -117,7 +122,7 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
117
122
|
return commits
|
|
118
123
|
|
|
119
124
|
except Exception as e:
|
|
120
|
-
|
|
125
|
+
print(f"❌ 获取commit历史异常: {str(e)}")
|
|
121
126
|
return []
|
|
122
127
|
|
|
123
128
|
|
|
@@ -166,6 +171,59 @@ def get_diff() -> str:
|
|
|
166
171
|
return f"发生意外错误: {str(e)}"
|
|
167
172
|
|
|
168
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
|
+
|
|
169
227
|
def revert_file(filepath: str) -> None:
|
|
170
228
|
"""增强版git恢复,处理新文件"""
|
|
171
229
|
import subprocess
|
|
@@ -185,7 +243,7 @@ def revert_file(filepath: str) -> None:
|
|
|
185
243
|
subprocess.run(["git", "clean", "-f", "--", filepath], check=True)
|
|
186
244
|
except subprocess.CalledProcessError as e:
|
|
187
245
|
error_msg = e.stderr.decode("utf-8", errors="replace") if e.stderr else str(e)
|
|
188
|
-
|
|
246
|
+
print(f"❌ 恢复文件失败: {error_msg}")
|
|
189
247
|
|
|
190
248
|
|
|
191
249
|
# 修改后的恢复函数
|
|
@@ -206,7 +264,101 @@ def revert_change() -> None:
|
|
|
206
264
|
subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)
|
|
207
265
|
subprocess.run(["git", "clean", "-fd"], check=True)
|
|
208
266
|
except subprocess.CalledProcessError as e:
|
|
209
|
-
|
|
267
|
+
print(f"❌ 恢复更改失败: {str(e)}")
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def detect_large_code_deletion(threshold: int = 30) -> Optional[Dict[str, int]]:
|
|
271
|
+
"""检测是否有大量代码删除
|
|
272
|
+
|
|
273
|
+
参数:
|
|
274
|
+
threshold: 净删除行数阈值,默认200行
|
|
275
|
+
|
|
276
|
+
返回:
|
|
277
|
+
Optional[Dict[str, int]]: 如果检测到大量删除,返回包含统计信息的字典:
|
|
278
|
+
{
|
|
279
|
+
'insertions': int, # 新增行数
|
|
280
|
+
'deletions': int, # 删除行数
|
|
281
|
+
'net_deletions': int # 净删除行数
|
|
282
|
+
}
|
|
283
|
+
如果没有大量删除或发生错误,返回None
|
|
284
|
+
"""
|
|
285
|
+
try:
|
|
286
|
+
# 临时暂存所有文件以便获取完整的diff统计
|
|
287
|
+
subprocess.run(["git", "add", "-N", "."], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
288
|
+
|
|
289
|
+
# 检查是否有HEAD
|
|
290
|
+
head_check = subprocess.run(
|
|
291
|
+
["git", "rev-parse", "--verify", "HEAD"],
|
|
292
|
+
stderr=subprocess.DEVNULL,
|
|
293
|
+
stdout=subprocess.DEVNULL,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
if head_check.returncode == 0:
|
|
297
|
+
# 有HEAD,获取相对于HEAD的diff统计
|
|
298
|
+
diff_result = subprocess.run(
|
|
299
|
+
["git", "diff", "HEAD", "--shortstat"],
|
|
300
|
+
capture_output=True,
|
|
301
|
+
text=True,
|
|
302
|
+
encoding="utf-8",
|
|
303
|
+
errors="replace",
|
|
304
|
+
check=False,
|
|
305
|
+
)
|
|
306
|
+
else:
|
|
307
|
+
# 空仓库,获取工作区diff统计
|
|
308
|
+
diff_result = subprocess.run(
|
|
309
|
+
["git", "diff", "--shortstat"],
|
|
310
|
+
capture_output=True,
|
|
311
|
+
text=True,
|
|
312
|
+
encoding="utf-8",
|
|
313
|
+
errors="replace",
|
|
314
|
+
check=False,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# 重置暂存区
|
|
318
|
+
subprocess.run(["git", "reset"], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
319
|
+
|
|
320
|
+
# 解析插入和删除行数
|
|
321
|
+
if diff_result.returncode == 0 and diff_result.stdout:
|
|
322
|
+
insertions = 0
|
|
323
|
+
deletions = 0
|
|
324
|
+
insertions_match = re.search(r"(\d+)\s+insertions?\(\+\)", diff_result.stdout)
|
|
325
|
+
deletions_match = re.search(r"(\d+)\s+deletions?\(\-\)", diff_result.stdout)
|
|
326
|
+
if insertions_match:
|
|
327
|
+
insertions = int(insertions_match.group(1))
|
|
328
|
+
if deletions_match:
|
|
329
|
+
deletions = int(deletions_match.group(1))
|
|
330
|
+
|
|
331
|
+
# 检查是否有大量代码删除(净删除超过阈值)
|
|
332
|
+
net_deletions = deletions - insertions
|
|
333
|
+
if net_deletions > threshold:
|
|
334
|
+
return {
|
|
335
|
+
'insertions': insertions,
|
|
336
|
+
'deletions': deletions,
|
|
337
|
+
'net_deletions': net_deletions
|
|
338
|
+
}
|
|
339
|
+
return None
|
|
340
|
+
except Exception:
|
|
341
|
+
# 如果检查过程中出错,返回None
|
|
342
|
+
return None
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
# confirm_large_code_deletion函数已废弃,统一使用大模型询问
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def check_large_code_deletion(threshold: int = 30) -> bool:
|
|
349
|
+
"""检查是否有大量代码删除
|
|
350
|
+
|
|
351
|
+
参数:
|
|
352
|
+
threshold: 净删除行数阈值,默认200行
|
|
353
|
+
|
|
354
|
+
返回:
|
|
355
|
+
bool: 始终返回True,由调用方统一处理大模型询问
|
|
356
|
+
"""
|
|
357
|
+
# 检测功能现在由调用方统一处理
|
|
358
|
+
return True
|
|
359
|
+
|
|
360
|
+
# 直接返回True,让调用方统一处理大模型询问
|
|
361
|
+
return True
|
|
210
362
|
|
|
211
363
|
|
|
212
364
|
def handle_commit_workflow() -> bool:
|
|
@@ -229,6 +381,10 @@ def handle_commit_workflow() -> bool:
|
|
|
229
381
|
if not has_uncommitted_changes():
|
|
230
382
|
return False
|
|
231
383
|
|
|
384
|
+
# 在提交前检查是否有大量代码删除
|
|
385
|
+
if not check_large_code_deletion():
|
|
386
|
+
return False
|
|
387
|
+
|
|
232
388
|
# 获取当前分支的提交总数
|
|
233
389
|
commit_result = subprocess.run(
|
|
234
390
|
["git", "rev-list", "--count", "HEAD"], capture_output=True, text=True
|
|
@@ -291,7 +447,13 @@ def get_modified_line_ranges() -> Dict[str, List[Tuple[int, int]]]:
|
|
|
291
447
|
行号从1开始。
|
|
292
448
|
"""
|
|
293
449
|
# 获取所有文件的Git差异
|
|
294
|
-
|
|
450
|
+
# 仅用于解析修改行范围,减少上下文以降低输出体积和解析成本
|
|
451
|
+
proc = subprocess.run(
|
|
452
|
+
["git", "show", "--no-color"],
|
|
453
|
+
capture_output=True,
|
|
454
|
+
text=True,
|
|
455
|
+
)
|
|
456
|
+
diff_output = proc.stdout
|
|
295
457
|
|
|
296
458
|
# 解析差异以获取修改的文件及其行范围
|
|
297
459
|
result: Dict[str, List[Tuple[int, int]]] = {}
|
|
@@ -329,7 +491,7 @@ def is_file_in_git_repo(filepath: str) -> bool:
|
|
|
329
491
|
|
|
330
492
|
# 检查文件路径是否在仓库根目录下
|
|
331
493
|
return os.path.abspath(filepath).startswith(os.path.abspath(repo_root))
|
|
332
|
-
except:
|
|
494
|
+
except Exception:
|
|
333
495
|
return False
|
|
334
496
|
|
|
335
497
|
|
|
@@ -394,23 +556,17 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
394
556
|
and remote_tag_result.returncode == 0
|
|
395
557
|
and local_tag_result.stdout.strip() != remote_tag_result.stdout.strip()
|
|
396
558
|
):
|
|
397
|
-
|
|
398
|
-
f"检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...",
|
|
399
|
-
OutputType.INFO,
|
|
400
|
-
)
|
|
559
|
+
print(f"ℹ️ 检测到新版本tag {remote_tag_result.stdout.strip()},正在更新Jarvis...")
|
|
401
560
|
subprocess.run(
|
|
402
561
|
["git", "checkout", remote_tag_result.stdout.strip()],
|
|
403
562
|
cwd=git_root,
|
|
404
563
|
check=True,
|
|
405
564
|
)
|
|
406
|
-
|
|
407
|
-
f"Jarvis已更新到tag {remote_tag_result.stdout.strip()}",
|
|
408
|
-
OutputType.SUCCESS,
|
|
409
|
-
)
|
|
565
|
+
print(f"✅ Jarvis已更新到tag {remote_tag_result.stdout.strip()}")
|
|
410
566
|
|
|
411
567
|
# 执行pip安装更新代码
|
|
412
568
|
try:
|
|
413
|
-
|
|
569
|
+
print("ℹ️ 正在安装更新后的代码...")
|
|
414
570
|
|
|
415
571
|
# 检查是否在虚拟环境中
|
|
416
572
|
in_venv = hasattr(sys, "real_prefix") or (
|
|
@@ -467,7 +623,7 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
467
623
|
)
|
|
468
624
|
|
|
469
625
|
if result.returncode == 0:
|
|
470
|
-
|
|
626
|
+
print("✅ 代码更新安装成功")
|
|
471
627
|
return True
|
|
472
628
|
|
|
473
629
|
# 处理权限错误
|
|
@@ -485,23 +641,21 @@ def check_and_update_git_repo(repo_path: str) -> bool:
|
|
|
485
641
|
text=True,
|
|
486
642
|
)
|
|
487
643
|
if user_result.returncode == 0:
|
|
488
|
-
|
|
644
|
+
print("✅ 用户级代码安装成功")
|
|
489
645
|
return True
|
|
490
646
|
error_msg = user_result.stderr.strip()
|
|
491
647
|
|
|
492
|
-
|
|
648
|
+
print(f"❌ 代码安装失败: {error_msg}")
|
|
493
649
|
return False
|
|
494
650
|
except Exception as e:
|
|
495
|
-
|
|
496
|
-
f"安装过程中发生意外错误: {str(e)}", OutputType.ERROR
|
|
497
|
-
)
|
|
651
|
+
print(f"❌ 安装过程中发生意外错误: {str(e)}")
|
|
498
652
|
return False
|
|
499
653
|
# 更新检查日期文件
|
|
500
654
|
with open(last_check_file, "w") as f:
|
|
501
655
|
f.write(today_str)
|
|
502
656
|
return False
|
|
503
657
|
except Exception as e:
|
|
504
|
-
|
|
658
|
+
print(f"⚠️ Git仓库更新检查失败: {e}")
|
|
505
659
|
return False
|
|
506
660
|
finally:
|
|
507
661
|
os.chdir(curr_dir)
|
|
@@ -528,18 +682,16 @@ def get_diff_file_list() -> List[str]:
|
|
|
528
682
|
subprocess.run(["git", "reset"], check=True)
|
|
529
683
|
|
|
530
684
|
if result.returncode != 0:
|
|
531
|
-
|
|
532
|
-
f"获取差异文件列表失败: {result.stderr}", OutputType.ERROR
|
|
533
|
-
)
|
|
685
|
+
print(f"❌ 获取差异文件列表失败: {result.stderr}")
|
|
534
686
|
return []
|
|
535
687
|
|
|
536
688
|
return [f for f in result.stdout.splitlines() if f]
|
|
537
689
|
|
|
538
690
|
except subprocess.CalledProcessError as e:
|
|
539
|
-
|
|
691
|
+
print(f"❌ 获取差异文件列表失败: {str(e)}")
|
|
540
692
|
return []
|
|
541
693
|
except Exception as e:
|
|
542
|
-
|
|
694
|
+
print(f"❌ 获取差异文件列表异常: {str(e)}")
|
|
543
695
|
return []
|
|
544
696
|
|
|
545
697
|
|
|
@@ -610,7 +762,7 @@ def get_recent_commits_with_files() -> List[Dict[str, Any]]:
|
|
|
610
762
|
if files_result.returncode == 0:
|
|
611
763
|
file_lines = files_result.stdout.splitlines()
|
|
612
764
|
unique_files: Set[str] = set(filter(None, file_lines))
|
|
613
|
-
commit["files"] = list(unique_files)[:20] #
|
|
765
|
+
commit["files"] = list(unique_files)[:20] # 限制最多20个文件
|
|
614
766
|
|
|
615
767
|
return commits
|
|
616
768
|
|
|
@@ -688,10 +840,8 @@ def confirm_add_new_files() -> None:
|
|
|
688
840
|
need_confirm = True
|
|
689
841
|
|
|
690
842
|
if output_lines:
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
OutputType.WARNING if need_confirm else OutputType.INFO,
|
|
694
|
-
)
|
|
843
|
+
emoji = "⚠️ " if need_confirm else "ℹ️ "
|
|
844
|
+
print(emoji + ("\n" + emoji).join(output_lines))
|
|
695
845
|
|
|
696
846
|
return need_confirm
|
|
697
847
|
|
|
@@ -705,8 +855,47 @@ def confirm_add_new_files() -> None:
|
|
|
705
855
|
|
|
706
856
|
if not user_confirm(
|
|
707
857
|
"是否要添加这些变更(如果不需要请修改.gitignore文件以忽略不需要的文件)?",
|
|
708
|
-
|
|
858
|
+
True,
|
|
709
859
|
):
|
|
860
|
+
# 用户选择 N:自动将未跟踪文件列表添加到仓库根目录的 .gitignore
|
|
861
|
+
try:
|
|
862
|
+
repo_root_result = subprocess.run(
|
|
863
|
+
["git", "rev-parse", "--show-toplevel"],
|
|
864
|
+
capture_output=True,
|
|
865
|
+
text=True,
|
|
866
|
+
check=True,
|
|
867
|
+
)
|
|
868
|
+
repo_root = repo_root_result.stdout.strip() or "."
|
|
869
|
+
except Exception:
|
|
870
|
+
repo_root = "."
|
|
871
|
+
gitignore_path = os.path.join(repo_root, ".gitignore")
|
|
872
|
+
|
|
873
|
+
# 仅对未跟踪的新文件进行忽略(已跟踪文件无法通过 .gitignore 忽略)
|
|
874
|
+
files_to_ignore = sorted(set(new_files))
|
|
875
|
+
|
|
876
|
+
# 读取已存在的 .gitignore 以避免重复添加
|
|
877
|
+
existing_lines: Set[str] = set()
|
|
878
|
+
try:
|
|
879
|
+
if os.path.exists(gitignore_path):
|
|
880
|
+
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
881
|
+
existing_lines = set(line.strip() for line in f if line.strip())
|
|
882
|
+
except Exception:
|
|
883
|
+
existing_lines = set()
|
|
884
|
+
|
|
885
|
+
# 追加未存在的文件路径到 .gitignore(使用相对于仓库根目录的路径)
|
|
886
|
+
try:
|
|
887
|
+
with open(gitignore_path, "a", encoding="utf-8") as f:
|
|
888
|
+
for file in files_to_ignore:
|
|
889
|
+
abs_path = os.path.abspath(file)
|
|
890
|
+
rel_path = os.path.relpath(abs_path, repo_root)
|
|
891
|
+
# 避免无效的相对路径(不应出现 .. 前缀),有则回退用原始值
|
|
892
|
+
entry = rel_path if not rel_path.startswith("..") else file
|
|
893
|
+
if entry not in existing_lines:
|
|
894
|
+
f.write(entry + "\n")
|
|
895
|
+
print("ℹ️ 已将未跟踪文件添加到 .gitignore,正在重新检测...")
|
|
896
|
+
except Exception as e:
|
|
897
|
+
print(f"⚠️ 更新 .gitignore 失败: {str(e)}")
|
|
898
|
+
|
|
710
899
|
continue
|
|
711
900
|
|
|
712
901
|
break
|
jarvis/jarvis_utils/globals.py
CHANGED
|
@@ -19,9 +19,9 @@ MAX_HISTORY_SIZE = 50
|
|
|
19
19
|
short_term_memories: List[Dict[str, Any]] = []
|
|
20
20
|
MAX_SHORT_TERM_MEMORIES = 100
|
|
21
21
|
|
|
22
|
-
import colorama
|
|
23
|
-
from rich.console import Console
|
|
24
|
-
from rich.theme import Theme
|
|
22
|
+
import colorama # noqa: E402
|
|
23
|
+
from rich.console import Console # noqa: E402
|
|
24
|
+
from rich.theme import Theme # noqa: E402
|
|
25
25
|
|
|
26
26
|
# 初始化colorama以支持跨平台的彩色文本
|
|
27
27
|
colorama.init()
|