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.
Files changed (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {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, Sequence, Tuple
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(r"\bunsafe\s+impl\s+(?:Send|Sync)\b|\bimpl\s+unsafe\s+(?:Send|Sync)\b", re.IGNORECASE)
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(r"\.ok\s*\(\s*\)|\.ok\?\s*;|\._?\s*=\s*.+\.err\(\s*\)", re.IGNORECASE) # 粗略
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(lines: Sequence[str], center: int, before: int = 3, after: int = 3) -> List[Tuple[int, str]]:
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 # r"..." 或 r#"..."#
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(lines: Sequence[str], line_no: int, radius: int = 5) -> bool:
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 (RE_COPY_NONOVERLAPPING.search(s) or RE_COPY.search(s) or RE_WRITE.search(s) or RE_READ.search(s)):
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
- from jarvis.jarvis_utils.utils import init_env
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 run_with_agent, direct_scan, format_markdown_report as format_markdown_report_workflow
26
- from jarvis.jarvis_sec.report import format_csv_report, aggregate_issues
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(".", "--path", "-p", help="待分析的根目录(默认当前目录)"),
40
-
45
+ path: str = typer.Option(
46
+ ".", "--path", "-p", help="待分析的根目录(默认当前目录)"
47
+ ),
41
48
  llm_group: Optional[str] = typer.Option(
42
- None, "--llm-group", "-g", help="使用的模型组(仅对本次运行生效,不修改全局配置)"
49
+ None,
50
+ "--llm-group",
51
+ "-g",
52
+ help="使用的模型组(仅对本次运行生效,不修改全局配置)",
43
53
  ),
44
54
  output: Optional[str] = typer.Option(
45
- "report.md", "--output", "-o", help="最终报告输出路径(默认 ./report.md)。如果后缀为 .csv,则输出 CSV 格式;否则输出 Markdown 格式"
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, "--cluster-limit", "-c", help="聚类每批最多处理的告警数(按文件分批聚类,默认50)"
61
+ 50,
62
+ "--cluster-limit",
63
+ "-c",
64
+ help="聚类每批最多处理的告警数(按文件分批聚类,默认50)",
50
65
  ),
51
66
  enable_verification: bool = typer.Option(
52
- True, "--enable-verification/--no-verification", help="是否启用二次验证(默认开启)"
67
+ True,
68
+ "--enable-verification/--no-verification",
69
+ help="是否启用二次验证(默认开启)",
53
70
  ),
54
71
  force_save_memory: bool = typer.Option(
55
- False, "--force-save-memory/--no-force-save-memory", help="强制使用记忆(默认关闭)"
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
- typer.secho(f"[jarvis_sec] Agent 分析过程出错,将回退到直扫基线(fast):{e}", fg=typer.colors.YELLOW, err=True)
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
- typer.secho("[jarvis_sec] Agent 无输出,回退到直扫基线(fast)。", fg=typer.colors.YELLOW, err=True)
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('.csv'):
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
- typer.secho(f"[jarvis_sec] Markdown 报告已写入: {p}", fg=typer.colors.GREEN)
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
- typer.secho(f"[jarvis_sec] 写入Markdown报告失败: {e}", fg=typer.colors.RED, err=True)
149
+ PrettyOutput.auto_print(f"[jarvis_sec] 写入Markdown报告失败: {e}")
128
150
  except Exception:
129
151
  pass
130
- typer.echo(text)
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())