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
@@ -1,18 +1,27 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """复核相关模块"""
3
3
 
4
- from typing import Dict, List, Optional
5
- import typer
4
+ from typing import Dict
5
+ from typing import List
6
+ from typing import Optional
6
7
 
7
- from jarvis.jarvis_sec.prompts import get_review_system_prompt, get_review_summary_prompt, build_verification_summary_prompt
8
+ from jarvis.jarvis_utils.output import PrettyOutput
9
+
10
+ from jarvis.jarvis_sec.agents import create_review_agent
11
+ from jarvis.jarvis_sec.agents import subscribe_summary_event
8
12
  from jarvis.jarvis_sec.parsers import try_parse_summary_report
9
- from jarvis.jarvis_sec.agents import create_review_agent, subscribe_summary_event
13
+ from jarvis.jarvis_sec.prompts import build_verification_summary_prompt
14
+ from jarvis.jarvis_sec.prompts import get_review_summary_prompt
15
+ from jarvis.jarvis_sec.prompts import get_review_system_prompt
10
16
  from jarvis.jarvis_sec.utils import git_restore_if_dirty
11
17
 
12
18
 
13
- def build_review_task(review_batch: List[Dict], entry_path: str, langs: List[str]) -> str:
19
+ def build_review_task(
20
+ review_batch: List[Dict], entry_path: str, langs: List[str]
21
+ ) -> str:
14
22
  """构建复核任务上下文"""
15
23
  import json as _json_review
24
+
16
25
  return f"""
17
26
  # 复核无效聚类任务
18
27
  上下文参数:
@@ -56,9 +65,6 @@ def build_gid_to_review_mapping(review_results: List[Dict]) -> Dict[int, Dict]:
56
65
  """构建gid到复核结果的映射(支持 gid 和 gids 两种格式)"""
57
66
  gid_to_review: Dict[int, Dict] = {}
58
67
  for rr in review_results:
59
- if not isinstance(rr, dict):
60
- continue
61
-
62
68
  # 支持 gid 和 gids 两种格式
63
69
  gids_to_process: List[int] = []
64
70
  if "gids" in rr and isinstance(rr.get("gids"), list):
@@ -78,14 +84,14 @@ def build_gid_to_review_mapping(review_results: List[Dict]) -> Dict[int, Dict]:
78
84
  gids_to_process.append(gid_int)
79
85
  except Exception:
80
86
  pass
81
-
87
+
82
88
  # 为每个 gid 创建复核结果映射
83
89
  is_reason_sufficient = rr.get("is_reason_sufficient")
84
90
  review_notes = str(rr.get("review_notes", "")).strip()
85
91
  for gid in gids_to_process:
86
92
  gid_to_review[gid] = {
87
93
  "is_reason_sufficient": is_reason_sufficient,
88
- "review_notes": review_notes
94
+ "review_notes": review_notes,
89
95
  }
90
96
  return gid_to_review
91
97
 
@@ -101,12 +107,12 @@ def process_review_batch(
101
107
  if review_results:
102
108
  # 构建gid到复核结果的映射
103
109
  gid_to_review = build_gid_to_review_mapping(review_results)
104
-
110
+
105
111
  # 处理每个无效聚类
106
112
  for invalid_cluster in review_batch:
107
113
  cluster_gids = invalid_cluster.get("gids", [])
108
114
  cluster_members = invalid_cluster.get("members", [])
109
-
115
+
110
116
  # 检查该聚类中的所有gid的复核结果
111
117
  all_sufficient = True
112
118
  any_reviewed = False
@@ -120,41 +126,56 @@ def process_review_batch(
120
126
  if not insufficient_review_result:
121
127
  insufficient_review_result = review_result
122
128
  break
123
-
129
+
124
130
  if any_reviewed and not all_sufficient:
125
131
  # 理由不充分,重新加入验证流程
126
- typer.secho(f"[jarvis-sec] 复核结果:无效聚类(gids={cluster_gids})理由不充分,重新加入验证流程", fg=typer.colors.BLUE)
132
+ PrettyOutput.auto_print(
133
+ f"🔵 [jarvis-sec] 复核结果:无效聚类(gids={cluster_gids})理由不充分,重新加入验证流程"
134
+ )
127
135
  for member in cluster_members:
128
136
  reinstated_candidates.append(member)
129
- reviewed_clusters.append({
130
- **invalid_cluster,
131
- "review_result": "reinstated",
132
- "review_notes": insufficient_review_result.get("review_notes", "") if insufficient_review_result else "",
133
- })
137
+ reviewed_clusters.append(
138
+ {
139
+ **invalid_cluster,
140
+ "review_result": "reinstated",
141
+ "review_notes": insufficient_review_result.get(
142
+ "review_notes", ""
143
+ )
144
+ if insufficient_review_result
145
+ else "",
146
+ }
147
+ )
134
148
  else:
135
149
  # 理由充分,确认无效
136
150
  review_notes = ""
137
151
  if cluster_gids and gid_to_review.get(cluster_gids[0]):
138
- review_notes = gid_to_review[cluster_gids[0]].get("review_notes", "")
139
- typer.secho(f"[jarvis-sec] 复核结果:无效聚类(gids={cluster_gids})理由充分,确认为无效", fg=typer.colors.GREEN)
140
- reviewed_clusters.append({
141
- **invalid_cluster,
142
- "review_result": "confirmed_invalid",
143
- "review_notes": review_notes,
144
- })
145
-
152
+ review_notes = gid_to_review[cluster_gids[0]].get(
153
+ "review_notes", ""
154
+ )
155
+ PrettyOutput.auto_print(
156
+ f" [jarvis-sec] 复核结果:无效聚类(gids={cluster_gids})理由充分,确认为无效"
157
+ )
158
+ reviewed_clusters.append(
159
+ {
160
+ **invalid_cluster,
161
+ "review_result": "confirmed_invalid",
162
+ "review_notes": review_notes,
163
+ }
164
+ )
165
+
146
166
  # 将确认无效的gids保存到analysis.jsonl的false_positive_gids中,以便断点恢复时能正确识别已复核的无效聚类
147
167
  if sec_dir:
148
168
  try:
169
+ from datetime import datetime
149
170
  from pathlib import Path
171
+
150
172
  from jarvis.jarvis_sec.file_manager import save_analysis_result
151
- from datetime import datetime
152
-
173
+
153
174
  # 构建cluster_id
154
175
  file_name = invalid_cluster.get("file", "")
155
176
  batch_index = invalid_cluster.get("batch_index", 1)
156
177
  cluster_id = f"{file_name}|{batch_index}|review"
157
-
178
+
158
179
  # 将gids转换为整数列表
159
180
  false_positive_gids = []
160
181
  for gid_val in cluster_gids:
@@ -164,7 +185,7 @@ def process_review_batch(
164
185
  false_positive_gids.append(gid_int)
165
186
  except Exception:
166
187
  pass
167
-
188
+
168
189
  # 保存分析结果
169
190
  if false_positive_gids:
170
191
  analysis_result = {
@@ -181,21 +202,27 @@ def process_review_batch(
181
202
  except Exception as e:
182
203
  # 保存失败不影响主流程,只记录警告
183
204
  try:
184
- typer.secho(f"[jarvis-sec] 警告:保存复核结果到analysis.jsonl失败: {str(e)}", fg=typer.colors.YELLOW)
205
+ PrettyOutput.auto_print(
206
+ f"⚠️ [jarvis-sec] 警告:保存复核结果到analysis.jsonl失败: {str(e)}"
207
+ )
185
208
  except Exception:
186
209
  pass
187
210
  else:
188
211
  # 复核结果解析失败,保守策略:重新加入验证流程
189
- typer.secho("[jarvis-sec] 警告:复核结果解析失败,保守策略:将批次中的所有候选重新加入验证流程", fg=typer.colors.YELLOW)
212
+ PrettyOutput.auto_print(
213
+ "⚠️ [jarvis-sec] 警告:复核结果解析失败,保守策略:将批次中的所有候选重新加入验证流程"
214
+ )
190
215
  for invalid_cluster in review_batch:
191
216
  cluster_members = invalid_cluster.get("members", [])
192
217
  for member in cluster_members:
193
218
  reinstated_candidates.append(member)
194
- reviewed_clusters.append({
195
- **invalid_cluster,
196
- "review_result": "reinstated",
197
- "review_notes": "复核结果解析失败,保守策略重新加入验证",
198
- })
219
+ reviewed_clusters.append(
220
+ {
221
+ **invalid_cluster,
222
+ "review_result": "reinstated",
223
+ "review_notes": "复核结果解析失败,保守策略重新加入验证",
224
+ }
225
+ )
199
226
 
200
227
 
201
228
  def process_review_batch_items(
@@ -222,27 +249,31 @@ def reinstated_candidates_to_cluster_batches(
222
249
  ) -> None:
223
250
  """将重新加入的候选添加到cluster_batches"""
224
251
  from collections import defaultdict as _dd2
225
-
252
+
226
253
  if not reinstated_candidates:
227
254
  return
228
-
229
- typer.secho(f"[jarvis-sec] 复核完成:{len(reinstated_candidates)} 个候选重新加入验证流程", fg=typer.colors.GREEN)
255
+
256
+ PrettyOutput.auto_print(
257
+ f"🔄 [jarvis-sec] 复核完成:{len(reinstated_candidates)} 个候选重新加入验证流程"
258
+ )
230
259
  # 按文件分组重新加入的候选
231
260
  reinstated_by_file: Dict[str, List[Dict]] = _dd2(list)
232
261
  for cand in reinstated_candidates:
233
262
  file_key = str(cand.get("file") or "")
234
263
  reinstated_by_file[file_key].append(cand)
235
-
264
+
236
265
  # 为每个文件的重新加入候选创建批次
237
266
  for file_key, cands in reinstated_by_file.items():
238
267
  if cands:
239
268
  cluster_batches.append(cands)
240
- _progress_append({
241
- "event": "review_reinstated",
242
- "file": file_key,
243
- "gids": [c.get("gid") for c in cands],
244
- "count": len(cands),
245
- })
269
+ _progress_append(
270
+ {
271
+ "event": "review_reinstated",
272
+ "file": file_key,
273
+ "gids": [c.get("gid") for c in cands],
274
+ "count": len(cands),
275
+ }
276
+ )
246
277
 
247
278
 
248
279
  def run_review_agent_with_retry(
@@ -256,70 +287,93 @@ def run_review_agent_with_retry(
256
287
  use_direct_model_review = False
257
288
  prev_parse_error_review: Optional[str] = None
258
289
  review_attempt = 0
259
-
290
+
260
291
  while True:
261
292
  review_attempt += 1
262
293
  review_summary_container["text"] = ""
263
-
294
+
264
295
  if use_direct_model_review:
265
296
  # 格式校验失败后,直接调用模型接口
266
297
  review_summary_prompt_text = build_verification_summary_prompt()
267
298
  error_guidance = ""
268
299
  if prev_parse_error_review:
269
300
  error_guidance = f"\n\n**格式错误详情(请根据以下错误修复输出格式):**\n- JSON解析失败: {prev_parse_error_review}\n\n请确保输出的JSON格式正确,包括正确的引号、逗号、大括号等。仅输出一个 <REPORT> 块,块内直接包含 JSON 数组(不需要额外的标签)。支持jsonnet语法(如尾随逗号、注释、||| 或 ``` 分隔符多行字符串等)。"
270
-
271
- full_review_prompt = f"{review_task}{error_guidance}\n\n{review_summary_prompt_text}"
301
+
302
+ full_review_prompt = (
303
+ f"{review_task}{error_guidance}\n\n{review_summary_prompt_text}"
304
+ )
272
305
  try:
273
- review_response = review_agent.model.chat_until_success(full_review_prompt) # type: ignore
306
+ review_response = review_agent.model.chat_until_success(
307
+ full_review_prompt
308
+ )
274
309
  review_summary_container["text"] = review_response
275
310
  except Exception as e:
276
311
  try:
277
- typer.secho(f"[jarvis-sec] 复核阶段直接模型调用失败: {e},回退到 run()", fg=typer.colors.YELLOW)
312
+ PrettyOutput.auto_print(
313
+ f"✨ [jarvis-sec] 复核阶段直接模型调用失败: {e},回退到 run()",
314
+ timestamp=True,
315
+ )
278
316
  except Exception:
279
317
  pass
280
318
  review_agent.run(review_task)
281
319
  else:
282
320
  review_agent.run(review_task)
283
-
321
+
284
322
  # 工作区保护
285
323
  try:
286
324
  _changed_review = git_restore_if_dirty(entry_path)
287
325
  if _changed_review:
288
326
  try:
289
- typer.secho(f"[jarvis-sec] 复核 Agent 工作区已恢复 ({_changed_review} 个文件)", fg=typer.colors.BLUE)
327
+ PrettyOutput.auto_print(
328
+ f"✨ [jarvis-sec] 复核 Agent 工作区已恢复 ({_changed_review} 个文件)",
329
+ timestamp=True,
330
+ )
290
331
  except Exception:
291
332
  pass
292
333
  except Exception:
293
334
  pass
294
-
335
+
295
336
  # 解析复核结果
296
337
  review_summary_text = review_summary_container.get("text", "")
297
338
  parse_error_review = None
298
339
  if review_summary_text:
299
- review_parsed, parse_error_review = try_parse_summary_report(review_summary_text)
340
+ review_parsed, parse_error_review = try_parse_summary_report(
341
+ review_summary_text
342
+ )
300
343
  if parse_error_review:
301
344
  prev_parse_error_review = parse_error_review
302
345
  try:
303
- typer.secho(f"[jarvis-sec] 复核结果JSON解析失败: {parse_error_review}", fg=typer.colors.YELLOW)
346
+ PrettyOutput.auto_print(
347
+ f"✨ [jarvis-sec] 复核结果JSON解析失败: {parse_error_review}",
348
+ timestamp=True,
349
+ )
304
350
  except Exception:
305
351
  pass
306
352
  else:
307
353
  prev_parse_error_review = None
308
354
  if isinstance(review_parsed, list):
309
355
  # 验证复核结果格式
310
- if review_parsed and all(is_valid_review_item(item) for item in review_parsed):
356
+ if review_parsed and all(
357
+ is_valid_review_item(item) for item in review_parsed
358
+ ):
311
359
  return review_parsed, None
312
-
360
+
313
361
  # 格式校验失败,后续重试使用直接模型调用
314
362
  use_direct_model_review = True
315
363
  if parse_error_review:
316
364
  try:
317
- typer.secho(f"[jarvis-sec] 复核结果JSON解析失败 -> 重试第 {review_attempt} 次 (使用直接模型调用,将反馈解析错误)", fg=typer.colors.YELLOW)
365
+ PrettyOutput.auto_print(
366
+ f"✨ [jarvis-sec] 复核结果JSON解析失败 -> 重试第 {review_attempt} 次 (使用直接模型调用,将反馈解析错误)",
367
+ timestamp=True,
368
+ )
318
369
  except Exception:
319
370
  pass
320
371
  else:
321
372
  try:
322
- typer.secho(f"[jarvis-sec] 复核结果格式无效 -> 重试第 {review_attempt} 次 (使用直接模型调用)", fg=typer.colors.YELLOW)
373
+ PrettyOutput.auto_print(
374
+ f"✨ [jarvis-sec] 复核结果格式无效 -> 重试第 {review_attempt} 次 (使用直接模型调用)",
375
+ timestamp=True,
376
+ )
323
377
  except Exception:
324
378
  pass
325
379
 
@@ -336,49 +390,59 @@ def process_review_phase(
336
390
  ) -> List[List[Dict]]:
337
391
  """
338
392
  处理复核阶段:验证所有标记为无效的聚类。
339
-
393
+
340
394
  返回: 更新后的 cluster_batches(包含重新加入验证的候选)
341
395
  """
342
396
  if not invalid_clusters_for_review:
343
- typer.secho("[jarvis-sec] 无无效聚类需要复核", fg=typer.colors.BLUE)
397
+ PrettyOutput.auto_print("🔵 [jarvis-sec] 无无效聚类需要复核")
344
398
  return cluster_batches
345
-
346
- typer.secho(f"\n[jarvis-sec] 开始复核 {len(invalid_clusters_for_review)} 个无效聚类...", fg=typer.colors.MAGENTA)
399
+
400
+ PrettyOutput.auto_print(
401
+ f"✨ \n[jarvis-sec] 开始复核 {len(invalid_clusters_for_review)} 个无效聚类...",
402
+ timestamp=True,
403
+ )
347
404
  status_mgr.update_review(
348
405
  current_review=0,
349
406
  total_reviews=len(invalid_clusters_for_review),
350
- message="开始复核无效聚类..."
407
+ message="开始复核无效聚类...",
351
408
  )
352
-
409
+
353
410
  # 按批次复核(每批最多10个无效聚类,避免上下文过长)
354
411
  review_batch_size = 10
355
412
  reviewed_clusters: List[Dict] = []
356
413
  reinstated_candidates: List[Dict] = [] # 重新加入验证的候选
357
-
414
+
358
415
  get_review_system_prompt()
359
416
  review_summary_prompt = get_review_summary_prompt()
360
-
417
+
361
418
  for review_idx in range(0, len(invalid_clusters_for_review), review_batch_size):
362
- review_batch = invalid_clusters_for_review[review_idx:review_idx + review_batch_size]
419
+ review_batch = invalid_clusters_for_review[
420
+ review_idx : review_idx + review_batch_size
421
+ ]
363
422
  current_review_num = review_idx // review_batch_size + 1
364
- total_review_batches = (len(invalid_clusters_for_review) + review_batch_size - 1) // review_batch_size
365
-
366
- typer.secho(f"[jarvis-sec] 复核批次 {current_review_num}/{total_review_batches}: {len(review_batch)} 个无效聚类", fg=typer.colors.CYAN)
423
+ total_review_batches = (
424
+ len(invalid_clusters_for_review) + review_batch_size - 1
425
+ ) // review_batch_size
426
+
427
+ PrettyOutput.auto_print(
428
+ f"✨ [jarvis-sec] 复核批次 {current_review_num}/{total_review_batches}: {len(review_batch)} 个无效聚类",
429
+ timestamp=True,
430
+ )
367
431
  status_mgr.update_review(
368
432
  current_review=current_review_num,
369
433
  total_reviews=total_review_batches,
370
- message=f"正在复核批次 {current_review_num}/{total_review_batches}"
434
+ message=f"正在复核批次 {current_review_num}/{total_review_batches}",
371
435
  )
372
-
436
+
373
437
  # 构建复核任务
374
438
  review_task = build_review_task(review_batch, entry_path, langs)
375
-
439
+
376
440
  # 创建复核Agent
377
441
  review_agent = create_review_agent(current_review_num, llm_group)
378
-
442
+
379
443
  # 订阅复核Agent的摘要
380
444
  review_summary_container = subscribe_summary_event(review_agent)
381
-
445
+
382
446
  # 运行复核Agent(永久重试直到格式正确)
383
447
  review_results, parse_error = run_review_agent_with_retry(
384
448
  review_agent,
@@ -387,7 +451,7 @@ def process_review_phase(
387
451
  entry_path,
388
452
  review_summary_container,
389
453
  )
390
-
454
+
391
455
  # 处理复核结果
392
456
  process_review_batch_items(
393
457
  review_batch,
@@ -396,36 +460,43 @@ def process_review_phase(
396
460
  reinstated_candidates,
397
461
  sec_dir,
398
462
  )
399
-
463
+
400
464
  # 记录每个已复核的无效聚类的 gids(包括确认无效的和重新加入验证的)
401
465
  for invalid_cluster in review_batch:
402
466
  cluster_gids = invalid_cluster.get("gids", [])
403
467
  if cluster_gids:
404
- _progress_append({
405
- "event": "review_invalid_cluster",
406
- "gids": cluster_gids,
407
- "file": invalid_cluster.get("file"),
408
- "batch_index": invalid_cluster.get("batch_index"),
409
- })
410
-
468
+ _progress_append(
469
+ {
470
+ "event": "review_invalid_cluster",
471
+ "gids": cluster_gids,
472
+ "file": invalid_cluster.get("file"),
473
+ "batch_index": invalid_cluster.get("batch_index"),
474
+ }
475
+ )
476
+
411
477
  # 将重新加入验证的候选添加到cluster_batches
412
478
  reinstated_candidates_to_cluster_batches(
413
479
  reinstated_candidates,
414
480
  cluster_batches,
415
481
  _progress_append,
416
482
  )
417
-
483
+
418
484
  if not reinstated_candidates:
419
- typer.secho("[jarvis-sec] 复核完成:所有无效聚类理由充分,确认为无效", fg=typer.colors.GREEN)
420
-
485
+ PrettyOutput.auto_print(
486
+ "✨ [jarvis-sec] 复核完成:所有无效聚类理由充分,确认为无效", timestamp=True
487
+ )
488
+
421
489
  # 记录复核结果(汇总)
422
- _progress_append({
423
- "event": "review_completed",
424
- "total_reviewed": len(invalid_clusters_for_review),
425
- "reinstated": len(reinstated_candidates),
426
- "confirmed_invalid": len(invalid_clusters_for_review) - len(reinstated_candidates),
427
- })
428
-
490
+ _progress_append(
491
+ {
492
+ "event": "review_completed",
493
+ "total_reviewed": len(invalid_clusters_for_review),
494
+ "reinstated": len(reinstated_candidates),
495
+ "confirmed_invalid": len(invalid_clusters_for_review)
496
+ - len(reinstated_candidates),
497
+ }
498
+ )
499
+
429
500
  # 记录所有已复核的无效聚类的 gids(用于断点恢复时跳过已复核的聚类)
430
501
  all_reviewed_gids = set()
431
502
  for invalid_cluster in invalid_clusters_for_review:
@@ -437,17 +508,19 @@ def process_review_phase(
437
508
  all_reviewed_gids.add(gid_int)
438
509
  except Exception:
439
510
  pass
440
-
511
+
441
512
  if all_reviewed_gids:
442
- _progress_append({
443
- "event": "review_all_gids",
444
- "gids": sorted(list(all_reviewed_gids)),
445
- "total": len(all_reviewed_gids),
446
- })
513
+ _progress_append(
514
+ {
515
+ "event": "review_all_gids",
516
+ "gids": sorted(list(all_reviewed_gids)),
517
+ "total": len(all_reviewed_gids),
518
+ }
519
+ )
447
520
  status_mgr.update_review(
448
521
  current_review=len(invalid_clusters_for_review),
449
522
  total_reviews=len(invalid_clusters_for_review),
450
- message=f"复核完成:{len(reinstated_candidates)} 个候选重新加入验证"
523
+ message=f"复核完成:{len(reinstated_candidates)} 个候选重新加入验证",
451
524
  )
452
-
525
+
453
526
  return cluster_batches