jarvis-ai-assistant 0.7.16__py3-none-any.whl → 1.0.2__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 +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
|
@@ -19,11 +19,12 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import re
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import List
|
|
22
|
+
from typing import List
|
|
23
|
+
from typing import Sequence
|
|
24
|
+
from typing import Tuple
|
|
23
25
|
|
|
24
26
|
from ..types import Issue
|
|
25
27
|
|
|
26
|
-
|
|
27
28
|
# ---------------------------
|
|
28
29
|
# 规则库(正则表达式)
|
|
29
30
|
# ---------------------------
|
|
@@ -38,11 +39,16 @@ RE_ASSUME_INIT = re.compile(r"\bassume_init\s*\(")
|
|
|
38
39
|
RE_UNWRAP = re.compile(r"\bunwrap\s*\(", re.IGNORECASE)
|
|
39
40
|
RE_EXPECT = re.compile(r"\bexpect\s*\(", re.IGNORECASE)
|
|
40
41
|
RE_EXTERN_C = re.compile(r'extern\s+"C"')
|
|
41
|
-
RE_UNSAFE_IMPL = re.compile(
|
|
42
|
+
RE_UNSAFE_IMPL = re.compile(
|
|
43
|
+
r"\bunsafe\s+impl\s+(?:Send|Sync)\b|\bimpl\s+unsafe\s+(?:Send|Sync)\b",
|
|
44
|
+
re.IGNORECASE,
|
|
45
|
+
)
|
|
42
46
|
|
|
43
47
|
# 结果忽略/下划线绑定(可能忽略错误)
|
|
44
48
|
RE_LET_UNDERSCORE = re.compile(r"\blet\s+_+\s*=\s*.+;")
|
|
45
|
-
RE_MATCH_IGNORE_ERR = re.compile(
|
|
49
|
+
RE_MATCH_IGNORE_ERR = re.compile(
|
|
50
|
+
r"\.ok\s*\(\s*\)|\.ok\?\s*;|\._?\s*=\s*.+\.err\(\s*\)", re.IGNORECASE
|
|
51
|
+
) # 粗略
|
|
46
52
|
|
|
47
53
|
# 类型转换相关
|
|
48
54
|
RE_AS_CAST = re.compile(r"\b\w+\s+as\s+[A-Za-z_]\w*", re.IGNORECASE)
|
|
@@ -90,6 +96,7 @@ RE_ZEROED = re.compile(r"\bzeroed\s*\(")
|
|
|
90
96
|
# 公共工具
|
|
91
97
|
# ---------------------------
|
|
92
98
|
|
|
99
|
+
|
|
93
100
|
def _safe_line(lines: Sequence[str], idx: int) -> str:
|
|
94
101
|
if 1 <= idx <= len(lines):
|
|
95
102
|
return lines[idx - 1]
|
|
@@ -101,7 +108,9 @@ def _strip_line(s: str, max_len: int = 200) -> str:
|
|
|
101
108
|
return s if len(s) <= max_len else s[: max_len - 3] + "..."
|
|
102
109
|
|
|
103
110
|
|
|
104
|
-
def _window(
|
|
111
|
+
def _window(
|
|
112
|
+
lines: Sequence[str], center: int, before: int = 3, after: int = 3
|
|
113
|
+
) -> List[Tuple[int, str]]:
|
|
105
114
|
start = max(1, center - before)
|
|
106
115
|
end = min(len(lines), center + after)
|
|
107
116
|
return [(i, _safe_line(lines, i)) for i in range(start, end + 1)]
|
|
@@ -118,9 +127,9 @@ def _remove_comments_preserve_strings(text: str) -> str:
|
|
|
118
127
|
n = len(text)
|
|
119
128
|
in_sl_comment = False # //
|
|
120
129
|
in_bl_comment = False # /* */
|
|
121
|
-
in_string = False
|
|
122
|
-
in_char = False
|
|
123
|
-
in_raw_string = False
|
|
130
|
+
in_string = False # "
|
|
131
|
+
in_char = False # '
|
|
132
|
+
in_raw_string = False # r"..." 或 r#"..."#
|
|
124
133
|
raw_string_hash_count = 0 # 原始字符串的 # 数量
|
|
125
134
|
escape = False
|
|
126
135
|
|
|
@@ -159,7 +168,7 @@ def _remove_comments_preserve_strings(text: str) -> str:
|
|
|
159
168
|
# 检查是否有足够的 # 来结束原始字符串
|
|
160
169
|
hash_count = 0
|
|
161
170
|
j = i - 1
|
|
162
|
-
while j >= 0 and text[j] ==
|
|
171
|
+
while j >= 0 and text[j] == "#":
|
|
163
172
|
hash_count += 1
|
|
164
173
|
j -= 1
|
|
165
174
|
if hash_count == raw_string_hash_count:
|
|
@@ -238,7 +247,7 @@ def _remove_comments_preserve_strings(text: str) -> str:
|
|
|
238
247
|
# 计算 # 的数量
|
|
239
248
|
raw_string_hash_count = 1
|
|
240
249
|
j = i + 1
|
|
241
|
-
while j < n and text[j] ==
|
|
250
|
+
while j < n and text[j] == "#":
|
|
242
251
|
raw_string_hash_count += 1
|
|
243
252
|
j += 1
|
|
244
253
|
if j < n and text[j] == '"':
|
|
@@ -252,7 +261,7 @@ def _remove_comments_preserve_strings(text: str) -> str:
|
|
|
252
261
|
# 字节原始字符串:br#"
|
|
253
262
|
raw_string_hash_count = 1
|
|
254
263
|
j = i + 2
|
|
255
|
-
while j < n and text[j] ==
|
|
264
|
+
while j < n and text[j] == "#":
|
|
256
265
|
raw_string_hash_count += 1
|
|
257
266
|
j += 1
|
|
258
267
|
if j < n and text[j] == '"':
|
|
@@ -303,21 +312,21 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
303
312
|
in_raw_string = False
|
|
304
313
|
raw_string_hash_count = 0
|
|
305
314
|
escape = False
|
|
306
|
-
|
|
315
|
+
|
|
307
316
|
i = 0
|
|
308
317
|
n = len(text)
|
|
309
|
-
|
|
318
|
+
|
|
310
319
|
while i < n:
|
|
311
320
|
ch = text[i]
|
|
312
321
|
nxt = text[i + 1] if i + 1 < n else ""
|
|
313
322
|
nxt2 = text[i + 2] if i + 2 < n else ""
|
|
314
|
-
|
|
323
|
+
|
|
315
324
|
if in_raw_string:
|
|
316
325
|
if ch == '"':
|
|
317
326
|
# 检查是否有足够的 # 来结束原始字符串
|
|
318
327
|
hash_count = 0
|
|
319
328
|
j = i - 1
|
|
320
|
-
while j >= 0 and text[j] ==
|
|
329
|
+
while j >= 0 and text[j] == "#":
|
|
321
330
|
hash_count += 1
|
|
322
331
|
j -= 1
|
|
323
332
|
if hash_count == raw_string_hash_count:
|
|
@@ -338,7 +347,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
338
347
|
res.append(" ")
|
|
339
348
|
i += 1
|
|
340
349
|
continue
|
|
341
|
-
|
|
350
|
+
|
|
342
351
|
if in_string:
|
|
343
352
|
if escape:
|
|
344
353
|
# 保留转义反斜杠为两字符(反斜杠+空格),以不破坏列对齐过多
|
|
@@ -356,7 +365,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
356
365
|
res.append(" ")
|
|
357
366
|
i += 1
|
|
358
367
|
continue
|
|
359
|
-
|
|
368
|
+
|
|
360
369
|
if in_char:
|
|
361
370
|
if escape:
|
|
362
371
|
res.append(" ")
|
|
@@ -373,7 +382,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
373
382
|
res.append(" ")
|
|
374
383
|
i += 1
|
|
375
384
|
continue
|
|
376
|
-
|
|
385
|
+
|
|
377
386
|
# 检测原始字符串开始:r"..." 或 r#"..."# 或 br"..." 或 b"..."(字节字符串)
|
|
378
387
|
if ch == "r" and nxt == '"':
|
|
379
388
|
# 简单原始字符串:r"
|
|
@@ -396,7 +405,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
396
405
|
# 带 # 的原始字符串:r#"
|
|
397
406
|
raw_string_hash_count = 1
|
|
398
407
|
j = i + 1
|
|
399
|
-
while j < n and text[j] ==
|
|
408
|
+
while j < n and text[j] == "#":
|
|
400
409
|
raw_string_hash_count += 1
|
|
401
410
|
j += 1
|
|
402
411
|
if j < n and text[j] == '"':
|
|
@@ -410,7 +419,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
410
419
|
# 字节原始字符串:br#"
|
|
411
420
|
raw_string_hash_count = 1
|
|
412
421
|
j = i + 2
|
|
413
|
-
while j < n and text[j] ==
|
|
422
|
+
while j < n and text[j] == "#":
|
|
414
423
|
raw_string_hash_count += 1
|
|
415
424
|
j += 1
|
|
416
425
|
if j < n and text[j] == '"':
|
|
@@ -422,7 +431,7 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
422
431
|
res.append(text[k])
|
|
423
432
|
i = j + 1
|
|
424
433
|
continue
|
|
425
|
-
|
|
434
|
+
|
|
426
435
|
# 处理 b"..."(字节字符串,不是原始字符串,需要在原始字符串检测之后)
|
|
427
436
|
if ch == "b" and nxt == '"' and nxt2 != "r":
|
|
428
437
|
in_string = True
|
|
@@ -440,14 +449,16 @@ def _mask_strings_preserve_len(text: str) -> str:
|
|
|
440
449
|
res.append("'")
|
|
441
450
|
i += 1
|
|
442
451
|
continue
|
|
443
|
-
|
|
452
|
+
|
|
444
453
|
res.append(ch)
|
|
445
454
|
i += 1
|
|
446
|
-
|
|
455
|
+
|
|
447
456
|
return "".join(res)
|
|
448
457
|
|
|
449
458
|
|
|
450
|
-
def _has_safety_comment_around(
|
|
459
|
+
def _has_safety_comment_around(
|
|
460
|
+
lines: Sequence[str], line_no: int, radius: int = 5
|
|
461
|
+
) -> bool:
|
|
451
462
|
"""
|
|
452
463
|
Rust 社区约定在 unsafe 附近写 SAFETY: 注释说明前置条件。
|
|
453
464
|
如存在,适当降低置信度。
|
|
@@ -489,6 +500,7 @@ def _severity_from_confidence(conf: float) -> str:
|
|
|
489
500
|
# 规则实现
|
|
490
501
|
# ---------------------------
|
|
491
502
|
|
|
503
|
+
|
|
492
504
|
def _rule_unsafe(lines: Sequence[str], relpath: str) -> List[Issue]:
|
|
493
505
|
issues: List[Issue] = []
|
|
494
506
|
for idx, s in enumerate(lines, start=1):
|
|
@@ -809,13 +821,18 @@ def _rule_unsafe_mem_ops(lines: Sequence[str], relpath: str) -> List[Issue]:
|
|
|
809
821
|
"""
|
|
810
822
|
issues: List[Issue] = []
|
|
811
823
|
for idx, s in enumerate(lines, start=1):
|
|
812
|
-
if not (
|
|
824
|
+
if not (
|
|
825
|
+
RE_COPY_NONOVERLAPPING.search(s)
|
|
826
|
+
or RE_COPY.search(s)
|
|
827
|
+
or RE_WRITE.search(s)
|
|
828
|
+
or RE_READ.search(s)
|
|
829
|
+
):
|
|
813
830
|
continue
|
|
814
831
|
# 检查是否在 unsafe 块中
|
|
815
832
|
window_text = " ".join(t for _, t in _window(lines, idx, before=5, after=5))
|
|
816
833
|
if "unsafe" not in window_text.lower():
|
|
817
834
|
continue # 这些函数必须在 unsafe 块中使用
|
|
818
|
-
|
|
835
|
+
|
|
819
836
|
conf = 0.8
|
|
820
837
|
if _has_safety_comment_around(lines, idx):
|
|
821
838
|
conf -= 0.1
|
|
@@ -938,7 +955,7 @@ def _rule_refcell_borrow(lines: Sequence[str], relpath: str) -> List[Issue]:
|
|
|
938
955
|
"""
|
|
939
956
|
issues: List[Issue] = []
|
|
940
957
|
refcell_vars: set[str] = set()
|
|
941
|
-
|
|
958
|
+
|
|
942
959
|
# 收集 RefCell 变量
|
|
943
960
|
for idx, s in enumerate(lines, start=1):
|
|
944
961
|
if RE_REFCELL.search(s):
|
|
@@ -946,7 +963,7 @@ def _rule_refcell_borrow(lines: Sequence[str], relpath: str) -> List[Issue]:
|
|
|
946
963
|
m = re.search(r"\bRefCell\s*<[^>]+>\s*([A-Za-z_]\w*)", s, re.IGNORECASE)
|
|
947
964
|
if m:
|
|
948
965
|
refcell_vars.add(m.group(1))
|
|
949
|
-
|
|
966
|
+
|
|
950
967
|
# 检测 borrow/borrow_mut 的使用
|
|
951
968
|
for idx, s in enumerate(lines, start=1):
|
|
952
969
|
for var in refcell_vars:
|
|
@@ -1043,6 +1060,7 @@ def _rule_uninit_zeroed(lines: Sequence[str], relpath: str) -> List[Issue]:
|
|
|
1043
1060
|
# 对外主入口
|
|
1044
1061
|
# ---------------------------
|
|
1045
1062
|
|
|
1063
|
+
|
|
1046
1064
|
def analyze_rust_text(relpath: str, text: str) -> List[Issue]:
|
|
1047
1065
|
"""
|
|
1048
1066
|
基于提供的文本进行 Rust 启发式分析。
|
|
@@ -1105,4 +1123,4 @@ def analyze_rust_files(base_path: str, relative_paths: List[str]) -> List[Issue]
|
|
|
1105
1123
|
p = Path(f)
|
|
1106
1124
|
if p.suffix.lower() == ".rs":
|
|
1107
1125
|
out.extend(analyze_rust_file(base, p))
|
|
1108
|
-
return out
|
|
1126
|
+
return out
|
jarvis/jarvis_sec/cli.py
CHANGED
|
@@ -20,10 +20,18 @@ from pathlib import Path
|
|
|
20
20
|
from typing import Optional
|
|
21
21
|
|
|
22
22
|
import typer
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
from jarvis.jarvis_sec.report import aggregate_issues
|
|
25
|
+
from jarvis.jarvis_sec.report import format_csv_report
|
|
26
|
+
from jarvis.jarvis_utils.output import PrettyOutput
|
|
27
|
+
|
|
24
28
|
# removed: set_config import(避免全局覆盖模型组配置)
|
|
25
|
-
from jarvis.jarvis_sec.workflow import
|
|
26
|
-
from jarvis.jarvis_sec.
|
|
29
|
+
from jarvis.jarvis_sec.workflow import direct_scan
|
|
30
|
+
from jarvis.jarvis_sec.workflow import (
|
|
31
|
+
format_markdown_report as format_markdown_report_workflow,
|
|
32
|
+
)
|
|
33
|
+
from jarvis.jarvis_sec.workflow import run_with_agent
|
|
34
|
+
from jarvis.jarvis_utils.utils import init_env
|
|
27
35
|
|
|
28
36
|
app = typer.Typer(
|
|
29
37
|
add_completion=False,
|
|
@@ -32,27 +40,38 @@ app = typer.Typer(
|
|
|
32
40
|
)
|
|
33
41
|
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
43
|
@app.command("agent", help="Agent模式(单Agent逐条子任务分析)")
|
|
38
44
|
def agent(
|
|
39
|
-
path: str = typer.Option(
|
|
40
|
-
|
|
45
|
+
path: str = typer.Option(
|
|
46
|
+
".", "--path", "-p", help="待分析的根目录(默认当前目录)"
|
|
47
|
+
),
|
|
41
48
|
llm_group: Optional[str] = typer.Option(
|
|
42
|
-
None,
|
|
49
|
+
None,
|
|
50
|
+
"--llm-group",
|
|
51
|
+
"-g",
|
|
52
|
+
help="使用的模型组(仅对本次运行生效,不修改全局配置)",
|
|
43
53
|
),
|
|
44
54
|
output: Optional[str] = typer.Option(
|
|
45
|
-
"report.md",
|
|
55
|
+
"report.md",
|
|
56
|
+
"--output",
|
|
57
|
+
"-o",
|
|
58
|
+
help="最终报告输出路径(默认 ./report.md)。如果后缀为 .csv,则输出 CSV 格式;否则输出 Markdown 格式",
|
|
46
59
|
),
|
|
47
|
-
|
|
48
60
|
cluster_limit: int = typer.Option(
|
|
49
|
-
50,
|
|
61
|
+
50,
|
|
62
|
+
"--cluster-limit",
|
|
63
|
+
"-c",
|
|
64
|
+
help="聚类每批最多处理的告警数(按文件分批聚类,默认50)",
|
|
50
65
|
),
|
|
51
66
|
enable_verification: bool = typer.Option(
|
|
52
|
-
True,
|
|
67
|
+
True,
|
|
68
|
+
"--enable-verification/--no-verification",
|
|
69
|
+
help="是否启用二次验证(默认开启)",
|
|
53
70
|
),
|
|
54
71
|
force_save_memory: bool = typer.Option(
|
|
55
|
-
False,
|
|
72
|
+
False,
|
|
73
|
+
"--force-save-memory/--no-force-save-memory",
|
|
74
|
+
help="强制使用记忆(默认关闭)",
|
|
56
75
|
),
|
|
57
76
|
) -> None:
|
|
58
77
|
# 初始化环境,确保平台/模型等全局配置就绪(避免 NoneType 平台)
|
|
@@ -64,7 +83,6 @@ def agent(
|
|
|
64
83
|
|
|
65
84
|
# 若指定了模型组:仅对本次运行生效,透传给 Agent;不修改全局配置(无需 set_config)
|
|
66
85
|
|
|
67
|
-
|
|
68
86
|
text: Optional[str] = None
|
|
69
87
|
try:
|
|
70
88
|
text = run_with_agent(
|
|
@@ -77,19 +95,23 @@ def agent(
|
|
|
77
95
|
)
|
|
78
96
|
except Exception as e:
|
|
79
97
|
try:
|
|
80
|
-
|
|
98
|
+
PrettyOutput.auto_print(
|
|
99
|
+
f"⚠️ [jarvis_sec] Agent 分析过程出错,将回退到直扫基线(fast):{e}"
|
|
100
|
+
)
|
|
81
101
|
except Exception:
|
|
82
102
|
pass
|
|
83
103
|
text = None
|
|
84
104
|
|
|
85
105
|
if not text or not str(text).strip():
|
|
86
106
|
try:
|
|
87
|
-
|
|
107
|
+
PrettyOutput.auto_print(
|
|
108
|
+
"⚠️ [jarvis_sec] Agent 无输出,回退到直扫基线(fast)。"
|
|
109
|
+
)
|
|
88
110
|
except Exception:
|
|
89
111
|
pass
|
|
90
112
|
result = direct_scan(path)
|
|
91
113
|
# 根据输出文件后缀选择格式
|
|
92
|
-
if output and output.lower().endswith(
|
|
114
|
+
if output and output.lower().endswith(".csv"):
|
|
93
115
|
# 使用 report.py 中的函数来格式化 CSV
|
|
94
116
|
report_json = aggregate_issues(
|
|
95
117
|
result.get("issues", []),
|
|
@@ -119,15 +141,15 @@ def agent(
|
|
|
119
141
|
p.parent.mkdir(parents=True, exist_ok=True)
|
|
120
142
|
p.write_text(md_text, encoding="utf-8")
|
|
121
143
|
try:
|
|
122
|
-
|
|
144
|
+
PrettyOutput.auto_print(f"✅ [jarvis_sec] Markdown 报告已写入: {p}")
|
|
123
145
|
except Exception:
|
|
124
146
|
pass
|
|
125
147
|
except Exception as e:
|
|
126
148
|
try:
|
|
127
|
-
|
|
149
|
+
PrettyOutput.auto_print(f"❌ [jarvis_sec] 写入Markdown报告失败: {e}")
|
|
128
150
|
except Exception:
|
|
129
151
|
pass
|
|
130
|
-
|
|
152
|
+
PrettyOutput.auto_print(text)
|
|
131
153
|
|
|
132
154
|
|
|
133
155
|
def main() -> int:
|
|
@@ -136,4 +158,4 @@ def main() -> int:
|
|
|
136
158
|
|
|
137
159
|
|
|
138
160
|
if __name__ == "__main__":
|
|
139
|
-
sys.exit(main())
|
|
161
|
+
sys.exit(main())
|