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,12 +1,15 @@
1
1
  import json
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Dict, List, Optional
4
+ from typing import Dict
5
+ from typing import List
6
+ from typing import Optional
5
7
 
6
8
 
7
9
  @dataclass
8
10
  class Symbol:
9
11
  """表示代码中的单个符号。"""
12
+
10
13
  name: str
11
14
  kind: str # 例如:'function'(函数)、'class'(类)、'variable'(变量)、'import'(导入)
12
15
  file_path: str
@@ -17,7 +20,7 @@ class Symbol:
17
20
  # 根据需要添加更多字段,例如父作用域
18
21
  parent: Optional[str] = None
19
22
  # 定义位置(对于引用/调用,指向符号定义的位置)
20
- definition_location: Optional['Symbol'] = None # 指向定义Symbol的引用
23
+ definition_location: Optional["Symbol"] = None # 指向定义Symbol的引用
21
24
  is_definition: bool = False # 如果此符号是定义则为True,如果是引用/调用则为False
22
25
 
23
26
 
@@ -46,13 +49,17 @@ class SymbolTable:
46
49
  cache_file = self._get_cache_file()
47
50
  if os.path.exists(cache_file):
48
51
  try:
49
- with open(cache_file, 'r', encoding='utf-8') as f:
52
+ with open(cache_file, "r", encoding="utf-8") as f:
50
53
  data = json.load(f)
51
54
  # 将JSON数据转换回Symbol对象
52
- self.symbols_by_name = self._deserialize_symbols(data.get('symbols_by_name', {}))
53
- self.symbols_by_file = self._deserialize_symbols(data.get('symbols_by_file', {}))
55
+ self.symbols_by_name = self._deserialize_symbols(
56
+ data.get("symbols_by_name", {})
57
+ )
58
+ self.symbols_by_file = self._deserialize_symbols(
59
+ data.get("symbols_by_file", {})
60
+ )
54
61
  # 加载文件修改时间
55
- self._file_mtimes = data.get('file_mtimes', {})
62
+ self._file_mtimes = data.get("file_mtimes", {})
56
63
  except Exception:
57
64
  # 如果缓存加载失败,则从空表开始
58
65
  pass
@@ -63,88 +70,94 @@ class SymbolTable:
63
70
  # 确保缓存目录存在
64
71
  os.makedirs(self.cache_dir, exist_ok=True)
65
72
  cache_file = self._get_cache_file()
66
-
73
+
67
74
  # 保存前更新文件修改时间
68
75
  self._update_file_mtimes()
69
-
76
+
70
77
  # 序列化符号以便JSON存储
71
78
  data = {
72
- 'symbols_by_name': self._serialize_symbols(self.symbols_by_name),
73
- 'symbols_by_file': self._serialize_symbols(self.symbols_by_file),
74
- 'file_mtimes': self._file_mtimes
79
+ "symbols_by_name": self._serialize_symbols(self.symbols_by_name),
80
+ "symbols_by_file": self._serialize_symbols(self.symbols_by_file),
81
+ "file_mtimes": self._file_mtimes,
75
82
  }
76
-
77
- with open(cache_file, 'w', encoding='utf-8') as f:
83
+
84
+ with open(cache_file, "w", encoding="utf-8") as f:
78
85
  json.dump(data, f, indent=2, ensure_ascii=False)
79
86
  except Exception:
80
87
  # 如果缓存保存失败,则继续而不缓存
81
88
  pass
82
89
 
83
- def _serialize_symbols(self, symbol_dict: Dict[str, List[Symbol]]) -> Dict[str, List[dict]]:
90
+ def _serialize_symbols(
91
+ self, symbol_dict: Dict[str, List[Symbol]]
92
+ ) -> Dict[str, List[dict]]:
84
93
  """将Symbol对象转换为可序列化的字典。"""
85
94
  serialized = {}
86
95
  for key, symbols in symbol_dict.items():
87
96
  serialized[key] = [self._symbol_to_dict(symbol) for symbol in symbols]
88
97
  return serialized
89
98
 
90
- def _deserialize_symbols(self, symbol_dict: Dict[str, List[dict]]) -> Dict[str, List[Symbol]]:
99
+ def _deserialize_symbols(
100
+ self, symbol_dict: Dict[str, List[dict]]
101
+ ) -> Dict[str, List[Symbol]]:
91
102
  """将序列化的字典转换回Symbol对象。"""
92
103
  deserialized = {}
93
104
  for key, symbol_data_list in symbol_dict.items():
94
- deserialized[key] = [self._dict_to_symbol(data) for data in symbol_data_list]
105
+ deserialized[key] = [
106
+ self._dict_to_symbol(data) for data in symbol_data_list
107
+ ]
95
108
  return deserialized
96
109
 
97
110
  def _symbol_to_dict(self, symbol: Symbol) -> dict:
98
111
  """将Symbol对象转换为字典。"""
99
112
  result = {
100
- 'name': symbol.name,
101
- 'kind': symbol.kind,
102
- 'file_path': symbol.file_path,
103
- 'line_start': symbol.line_start,
104
- 'line_end': symbol.line_end,
105
- 'signature': symbol.signature,
106
- 'docstring': symbol.docstring,
107
- 'parent': symbol.parent,
108
- 'is_definition': getattr(symbol, 'is_definition', False),
113
+ "name": symbol.name,
114
+ "kind": symbol.kind,
115
+ "file_path": symbol.file_path,
116
+ "line_start": symbol.line_start,
117
+ "line_end": symbol.line_end,
118
+ "signature": symbol.signature,
119
+ "docstring": symbol.docstring,
120
+ "parent": symbol.parent,
121
+ "is_definition": getattr(symbol, "is_definition", False),
109
122
  }
110
123
  # 序列化定义位置(只保存基本信息,避免循环引用)
111
- if hasattr(symbol, 'definition_location') and symbol.definition_location:
112
- result['definition_location'] = {
113
- 'file_path': symbol.definition_location.file_path,
114
- 'line_start': symbol.definition_location.line_start,
115
- 'line_end': symbol.definition_location.line_end,
116
- 'name': symbol.definition_location.name,
124
+ if hasattr(symbol, "definition_location") and symbol.definition_location:
125
+ result["definition_location"] = {
126
+ "file_path": symbol.definition_location.file_path,
127
+ "line_start": symbol.definition_location.line_start,
128
+ "line_end": symbol.definition_location.line_end,
129
+ "name": symbol.definition_location.name,
117
130
  }
118
131
  return result
119
132
 
120
133
  def _dict_to_symbol(self, data: dict) -> Symbol:
121
134
  """将字典转换回Symbol对象。"""
122
135
  symbol = Symbol(
123
- name=data['name'],
124
- kind=data['kind'],
125
- file_path=data['file_path'],
126
- line_start=data['line_start'],
127
- line_end=data['line_end'],
128
- signature=data.get('signature'),
129
- docstring=data.get('docstring'),
130
- parent=data.get('parent'),
131
- is_definition=data.get('is_definition', False),
136
+ name=data["name"],
137
+ kind=data["kind"],
138
+ file_path=data["file_path"],
139
+ line_start=data["line_start"],
140
+ line_end=data["line_end"],
141
+ signature=data.get("signature"),
142
+ docstring=data.get("docstring"),
143
+ parent=data.get("parent"),
144
+ is_definition=data.get("is_definition", False),
132
145
  )
133
146
  # 恢复定义位置(创建临时 Symbol 对象)
134
- if 'definition_location' in data and data['definition_location']:
135
- def_loc = data['definition_location']
147
+ if "definition_location" in data and data["definition_location"]:
148
+ def_loc = data["definition_location"]
136
149
  symbol.definition_location = Symbol(
137
- name=def_loc['name'],
138
- kind='', # 未知类型
139
- file_path=def_loc['file_path'],
140
- line_start=def_loc['line_start'],
141
- line_end=def_loc['line_end'],
150
+ name=def_loc["name"],
151
+ kind="", # 未知类型
152
+ file_path=def_loc["file_path"],
153
+ line_start=def_loc["line_start"],
154
+ line_end=def_loc["line_end"],
142
155
  )
143
156
  return symbol
144
157
 
145
158
  def add_symbol(self, symbol: Symbol, save_to_cache: bool = False):
146
159
  """向表中添加符号。
147
-
160
+
148
161
  参数:
149
162
  symbol: 要添加的符号
150
163
  save_to_cache: 如果为True,立即保存到缓存。默认为False以提高性能。
@@ -157,11 +170,11 @@ class SymbolTable:
157
170
  if symbol.file_path not in self.symbols_by_file:
158
171
  self.symbols_by_file[symbol.file_path] = []
159
172
  self.symbols_by_file[symbol.file_path].append(symbol)
160
-
173
+
161
174
  # 仅在明确请求时保存到缓存(出于性能考虑)
162
175
  if save_to_cache:
163
176
  self._save_to_cache()
164
-
177
+
165
178
  def save_cache(self):
166
179
  """将整个符号表保存到缓存。批量操作后调用此方法。"""
167
180
  self._save_to_cache()
@@ -172,9 +185,7 @@ class SymbolTable:
172
185
  如果提供了file_path,则搜索仅限于该文件。
173
186
  """
174
187
  if file_path:
175
- return [
176
- s for s in self.get_file_symbols(file_path) if s.name == name
177
- ]
188
+ return [s for s in self.get_file_symbols(file_path) if s.name == name]
178
189
  return self.symbols_by_name.get(name, [])
179
190
 
180
191
  def get_file_symbols(self, file_path: str) -> List[Symbol]:
@@ -188,19 +199,20 @@ class SymbolTable:
188
199
  for symbol in symbols_to_remove:
189
200
  if symbol.name in self.symbols_by_name:
190
201
  self.symbols_by_name[symbol.name] = [
191
- s for s in self.symbols_by_name[symbol.name]
202
+ s
203
+ for s in self.symbols_by_name[symbol.name]
192
204
  if s.file_path != file_path
193
205
  ]
194
206
  if not self.symbols_by_name[symbol.name]:
195
207
  del self.symbols_by_name[symbol.name]
196
-
208
+
197
209
  # 移除文件修改时间跟踪
198
210
  if file_path in self._file_mtimes:
199
211
  del self._file_mtimes[file_path]
200
-
212
+
201
213
  # 清除后保存到缓存
202
214
  self._save_to_cache()
203
-
215
+
204
216
  def _update_file_mtimes(self):
205
217
  """更新所有跟踪文件的修改时间。"""
206
218
  for file_path in list(self.symbols_by_file.keys()):
@@ -210,28 +222,28 @@ class SymbolTable:
210
222
  except Exception:
211
223
  # 如果无法获取修改时间,则从跟踪中移除
212
224
  self._file_mtimes.pop(file_path, None)
213
-
225
+
214
226
  def is_file_stale(self, file_path: str) -> bool:
215
227
  """检查文件自缓存后是否已被修改。
216
-
228
+
217
229
  参数:
218
230
  file_path: 要检查的文件路径
219
-
231
+
220
232
  返回:
221
233
  如果文件比缓存新则为True,否则为False
222
234
  """
223
235
  if file_path not in self.symbols_by_file:
224
236
  # 文件不在缓存中,视为已过期(需要加载)
225
237
  return True
226
-
238
+
227
239
  if file_path not in self._file_mtimes:
228
240
  # 没有记录修改时间,视为已过期
229
241
  return True
230
-
242
+
231
243
  if not os.path.exists(file_path):
232
244
  # 文件不存在,不算过期(将由clear_file_symbols处理)
233
245
  return False
234
-
246
+
235
247
  try:
236
248
  current_mtime = os.path.getmtime(file_path)
237
249
  cached_mtime = self._file_mtimes.get(file_path, 0)
@@ -249,4 +261,4 @@ class SymbolExtractor:
249
261
  从代码中提取符号(函数、类、变量等)。
250
262
  此方法应由特定语言的子类实现。
251
263
  """
252
- raise NotImplementedError("Subclasses must implement this method.")
264
+ raise NotImplementedError("Subclasses must implement this method.")
@@ -1,9 +1,17 @@
1
1
  from abc import abstractmethod
2
- from typing import List, Optional
2
+ from typing import List
3
+ from typing import Optional
3
4
 
4
- from tree_sitter import Language, Parser, Node, Query, QueryCursor
5
+ from tree_sitter import Language
6
+ from tree_sitter import Node
7
+ from tree_sitter import Parser
8
+ from tree_sitter import Query
9
+ from tree_sitter import QueryCursor
5
10
 
6
- from .symbol_extractor import Symbol, SymbolExtractor
11
+ from jarvis.jarvis_utils.output import PrettyOutput
12
+
13
+ from .symbol_extractor import Symbol
14
+ from .symbol_extractor import SymbolExtractor
7
15
 
8
16
 
9
17
  class TreeSitterExtractor(SymbolExtractor):
@@ -14,45 +22,110 @@ class TreeSitterExtractor(SymbolExtractor):
14
22
  """
15
23
 
16
24
  def __init__(self, language: Language, symbol_query: str):
17
- # 如果传入的是 PyCapsule,需要转换为 Language 对象
18
- if not isinstance(language, Language):
19
- language = Language(language)
20
25
  self.language = language
21
26
  self.parser = Parser()
22
- # 使用 language 属性而不是 set_language 方法
23
- self.parser.language = self.language
27
+ # 设置language(tree-sitter的Parser需要Language对象)
28
+ try:
29
+ # 尝试使用set_language方法(如果可用)
30
+ if hasattr(self.parser, "set_language"):
31
+ self.parser.set_language(self.language)
32
+ else:
33
+ # 否则直接赋值language属性
34
+ self.parser.language = self.language
35
+ except (AttributeError, TypeError):
36
+ # 如果都失败,尝试创建Language对象
37
+ try:
38
+ from tree_sitter import Language as LangClass
39
+
40
+ try:
41
+ lang_obj = LangClass(language)
42
+ self.parser.language = lang_obj
43
+ self.language = lang_obj
44
+ except Exception:
45
+ self.parser.language = language
46
+ except Exception:
47
+ # 最后的fallback:直接赋值
48
+ self.parser.language = language
24
49
  self.symbol_query = symbol_query
25
50
 
26
51
  def extract_symbols(self, file_path: str, content: str) -> List[Symbol]:
27
52
  """
28
53
  Parses the code with tree-sitter and extracts symbols based on the query.
29
54
  """
55
+ # 检查内容是否为空或只包含空白
56
+ if not content or not content.strip():
57
+ return []
58
+
59
+ symbols = []
60
+
30
61
  try:
62
+ # 解析代码(即使有语法错误,tree-sitter也能部分解析)
31
63
  tree = self.parser.parse(bytes(content, "utf8"))
32
- # 使用 Query 构造函数(新 API)
33
- query = Query(self.language, self.symbol_query)
64
+
65
+ # 检查解析是否成功(tree.root_node 应该存在)
66
+ if tree is None or tree.root_node is None:
67
+ return []
68
+
69
+ # 尝试构造查询
70
+ query = None
71
+ try:
72
+ query = Query(self.language, self.symbol_query)
73
+ except Exception as query_error:
74
+ # Query 构造失败(可能是查询语法问题),静默返回空列表
75
+ import os
76
+
77
+ if os.getenv("DEBUG_TREE_SITTER", "").lower() in ("1", "true", "yes"):
78
+ PrettyOutput.auto_print(
79
+ f"Error creating query for {file_path}: {query_error}"
80
+ )
81
+ return []
82
+
34
83
  # 使用 QueryCursor 执行查询
84
+ # 即使有语法错误,tree-sitter也能部分解析,所以可以提取部分符号
35
85
  cursor = QueryCursor(query)
36
86
  matches = cursor.matches(tree.root_node)
37
-
38
- symbols = []
87
+
39
88
  # matches 返回格式: [(pattern_index, {capture_name: [nodes]})]
40
89
  for pattern_index, captures_dict in matches:
41
90
  for capture_name, nodes in captures_dict.items():
42
91
  for node in nodes:
43
- symbol = self._create_symbol_from_capture(node, capture_name, file_path)
44
- if symbol:
45
- symbols.append(symbol)
92
+ try:
93
+ # 跳过错误节点(tree-sitter会用ERROR节点标记语法错误)
94
+ # 错误节点通常没有有效的文本内容或位置信息
95
+ if node.type == "ERROR":
96
+ continue
97
+
98
+ symbol = self._create_symbol_from_capture(
99
+ node, capture_name, file_path
100
+ )
101
+ if symbol:
102
+ symbols.append(symbol)
103
+ except Exception:
104
+ # 单个符号提取失败,继续处理其他符号
105
+ # 这样可以确保即使部分符号提取失败,也能返回已成功提取的符号
106
+ continue
107
+
108
+ # 即使有语法错误,也返回已成功提取的符号
46
109
  return symbols
47
110
  except Exception as e:
48
- print(f"Error extracting symbols from {file_path} with tree-sitter: {e}")
49
- return []
111
+ # 如果解析完全失败(不是语法错误,而是其他严重错误),返回空列表
112
+ # 只在调试模式下打印错误信息
113
+ import os
114
+
115
+ if os.getenv("DEBUG_TREE_SITTER", "").lower() in ("1", "true", "yes"):
116
+ PrettyOutput.auto_print(
117
+ f"Error extracting symbols from {file_path} with tree-sitter: {e}"
118
+ )
119
+ # 即使解析失败,也返回已提取的符号(如果有的话)
120
+ return symbols
50
121
 
51
122
  @abstractmethod
52
- def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
123
+ def _create_symbol_from_capture(
124
+ self, node: Node, name: str, file_path: str
125
+ ) -> Optional[Symbol]:
53
126
  """
54
127
  Creates a Symbol object from a tree-sitter query capture.
55
128
  This method must be implemented by subclasses to map capture names
56
129
  (e.g., "function.name") to Symbol attributes.
57
130
  """
58
- raise NotImplementedError
131
+ raise NotImplementedError