jarvis-ai-assistant 0.7.8__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.8.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.8.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -2,17 +2,23 @@
2
2
 
3
3
  import os
4
4
  import re
5
- from typing import List, Optional, Set
5
+ from typing import List
6
+ from typing import Optional
7
+ from typing import Set
8
+ from typing import cast
6
9
 
7
- from tree_sitter import Language, Node
10
+ from tree_sitter import Language
11
+ from tree_sitter import Node
8
12
 
9
13
  from ..base_language import BaseLanguageSupport
10
- from ..dependency_analyzer import Dependency, DependencyAnalyzer, DependencyGraph
14
+ from ..dependency_analyzer import Dependency
15
+ from ..dependency_analyzer import DependencyAnalyzer
16
+ from ..dependency_analyzer import DependencyGraph
11
17
  from ..file_ignore import filter_walk_dirs
12
- from ..symbol_extractor import Symbol, SymbolExtractor
18
+ from ..symbol_extractor import Symbol
19
+ from ..symbol_extractor import SymbolExtractor
13
20
  from ..tree_sitter_extractor import TreeSitterExtractor
14
21
 
15
-
16
22
  # --- Go Symbol Query ---
17
23
 
18
24
  GO_SYMBOL_QUERY = """
@@ -42,13 +48,17 @@ GO_SYMBOL_QUERY = """
42
48
 
43
49
  try:
44
50
  import tree_sitter_go
45
- GO_LANGUAGE: Optional[Language] = tree_sitter_go.language()
51
+
52
+ GO_LANGUAGE: Optional[Language] = cast(
53
+ Optional[Language], tree_sitter_go.language()
54
+ )
46
55
  except (ImportError, Exception):
47
56
  GO_LANGUAGE = None
48
57
 
49
58
 
50
59
  # --- Go Symbol Extractor ---
51
60
 
61
+
52
62
  class GoSymbolExtractor(TreeSitterExtractor):
53
63
  """Extracts symbols from Go code using tree-sitter."""
54
64
 
@@ -57,7 +67,9 @@ class GoSymbolExtractor(TreeSitterExtractor):
57
67
  raise RuntimeError("Go tree-sitter grammar not available.")
58
68
  super().__init__(GO_LANGUAGE, GO_SYMBOL_QUERY)
59
69
 
60
- def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
70
+ def _create_symbol_from_capture(
71
+ self, node: Node, name: str, file_path: str
72
+ ) -> Optional[Symbol]:
61
73
  """Maps a tree-sitter capture to a Symbol object."""
62
74
  kind_map = {
63
75
  "function.name": "function",
@@ -68,7 +80,7 @@ class GoSymbolExtractor(TreeSitterExtractor):
68
80
  "var": "var",
69
81
  "struct": "struct",
70
82
  }
71
-
83
+
72
84
  symbol_kind = kind_map.get(name)
73
85
  if not symbol_kind:
74
86
  return None
@@ -76,23 +88,27 @@ class GoSymbolExtractor(TreeSitterExtractor):
76
88
  # For const/var/struct, extract the first identifier as name
77
89
  if symbol_kind in ("const", "var", "struct"):
78
90
  # Try to find the first identifier in the declaration
79
- node_text = node.text.decode('utf8').strip()
91
+ if node.text is None:
92
+ return None
93
+ node_text = node.text.decode("utf8").strip()
80
94
  # Extract first identifier after const/var/struct keyword
81
95
  if symbol_kind == "const":
82
- match = re.search(r'const\s+(\w+)', node_text)
96
+ match = re.search(r"const\s+(\w+)", node_text)
83
97
  elif symbol_kind == "var":
84
- match = re.search(r'var\s+(\w+)', node_text)
98
+ match = re.search(r"var\s+(\w+)", node_text)
85
99
  else: # struct
86
100
  # For struct, try to find struct name or use a generic name
87
- match = re.search(r'struct\s+(\w+)', node_text)
88
-
101
+ match = re.search(r"struct\s+(\w+)", node_text)
102
+
89
103
  if match:
90
104
  symbol_name = match.group(1)
91
105
  else:
92
106
  # Fallback: use the kind as name
93
107
  symbol_name = symbol_kind
94
108
  else:
95
- symbol_name = node.text.decode('utf8')
109
+ if node.text is None:
110
+ return None
111
+ symbol_name = node.text.decode("utf8")
96
112
 
97
113
  return Symbol(
98
114
  name=symbol_name,
@@ -105,78 +121,98 @@ class GoSymbolExtractor(TreeSitterExtractor):
105
121
 
106
122
  # --- Go Dependency Analyzer ---
107
123
 
124
+
108
125
  class GoDependencyAnalyzer(DependencyAnalyzer):
109
126
  """Analyzes Go import dependencies."""
110
127
 
111
128
  def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
112
129
  """Analyzes Go import statements."""
113
130
  dependencies: List[Dependency] = []
114
-
131
+
115
132
  # Match import statements
116
133
  # Format: import "package" or import ( "package1" "package2" )
117
134
  # Also: import alias "package"
118
135
  re.compile(
119
136
  r'import\s+(?:\(([^)]+)\)|(?:"([^"]+)"|`([^`]+)`)|(\w+)\s+(?:"([^"]+)"|`([^`]+)`)))',
120
- re.MULTILINE
137
+ re.MULTILINE,
121
138
  )
122
-
139
+
123
140
  # Handle single import: import "package"
124
- single_import = re.compile(r'import\s+(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))')
125
-
141
+ single_import = re.compile(
142
+ r'import\s+(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))'
143
+ )
144
+
126
145
  # Handle block import: import ( ... )
127
- block_import = re.compile(r'import\s*\(([^)]+)\)', re.DOTALL)
128
-
146
+ block_import = re.compile(r"import\s*\(([^)]+)\)", re.DOTALL)
147
+
129
148
  # Try block import first
130
149
  block_match = block_import.search(content)
131
150
  if block_match:
132
151
  block_content = block_match.group(1)
133
- for line in block_content.split('\n'):
152
+ for line in block_content.split("\n"):
134
153
  line = line.strip()
135
- if not line or line.startswith('//'):
154
+ if not line or line.startswith("//"):
136
155
  continue
137
156
  # Extract package path
138
- pkg_match = re.search(r'(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))', line)
157
+ pkg_match = re.search(
158
+ r'(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))', line
159
+ )
139
160
  if pkg_match:
140
- pkg = pkg_match.group(1) or pkg_match.group(2) or pkg_match.group(4) or pkg_match.group(5)
161
+ pkg = (
162
+ pkg_match.group(1)
163
+ or pkg_match.group(2)
164
+ or pkg_match.group(4)
165
+ or pkg_match.group(5)
166
+ )
141
167
  alias = pkg_match.group(3)
142
- line_num = content[:block_match.start()].count('\n') + line.split('\n')[0].count('\n') + 1
143
- dependencies.append(Dependency(
144
- from_module=pkg,
145
- imported_symbol=alias,
146
- file_path=file_path,
147
- line=line_num,
148
- ))
168
+ line_num = (
169
+ content[: block_match.start()].count("\n")
170
+ + line.split("\n")[0].count("\n")
171
+ + 1
172
+ )
173
+ dependencies.append(
174
+ Dependency(
175
+ from_module=pkg,
176
+ imported_symbol=alias,
177
+ file_path=file_path,
178
+ line=line_num,
179
+ )
180
+ )
149
181
  else:
150
182
  # Try single import
151
183
  for match in single_import.finditer(content):
152
- pkg = match.group(1) or match.group(2) or match.group(4) or match.group(5)
184
+ pkg = (
185
+ match.group(1) or match.group(2) or match.group(4) or match.group(5)
186
+ )
153
187
  alias = match.group(3)
154
- line_num = content[:match.start()].count('\n') + 1
155
- dependencies.append(Dependency(
156
- from_module=pkg,
157
- imported_symbol=alias,
158
- file_path=file_path,
159
- line=line_num,
160
- ))
161
-
188
+ line_num = content[: match.start()].count("\n") + 1
189
+ dependencies.append(
190
+ Dependency(
191
+ from_module=pkg,
192
+ imported_symbol=alias,
193
+ file_path=file_path,
194
+ line=line_num,
195
+ )
196
+ )
197
+
162
198
  return dependencies
163
199
 
164
200
  def build_dependency_graph(self, project_root: str) -> DependencyGraph:
165
201
  """Builds a dependency graph for a Go project."""
166
202
  graph = DependencyGraph()
167
-
203
+
168
204
  for root, dirs, files in os.walk(project_root):
169
205
  dirs[:] = filter_walk_dirs(dirs)
170
-
206
+
171
207
  for file in files:
172
- if not file.endswith('.go'):
208
+ if not file.endswith(".go"):
173
209
  continue
174
-
210
+
175
211
  file_path = os.path.join(root, file)
176
212
  try:
177
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
213
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
178
214
  content = f.read()
179
-
215
+
180
216
  dependencies = self.analyze_imports(file_path, content)
181
217
  for dep in dependencies:
182
218
  # For Go, we can resolve to vendor or standard library
@@ -185,12 +221,12 @@ class GoDependencyAnalyzer(DependencyAnalyzer):
185
221
  pass
186
222
  except Exception:
187
223
  continue
188
-
224
+
189
225
  return graph
190
226
 
191
227
  def _is_source_file(self, file_path: str) -> bool:
192
228
  """Check if a file is a Go source file."""
193
- return file_path.endswith('.go')
229
+ return file_path.endswith(".go")
194
230
 
195
231
 
196
232
  class GoLanguageSupport(BaseLanguageSupport):
@@ -198,11 +234,11 @@ class GoLanguageSupport(BaseLanguageSupport):
198
234
 
199
235
  @property
200
236
  def language_name(self) -> str:
201
- return 'go'
237
+ return "go"
202
238
 
203
239
  @property
204
240
  def file_extensions(self) -> Set[str]:
205
- return {'.go'}
241
+ return {".go"}
206
242
 
207
243
  def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
208
244
  try:
@@ -212,4 +248,3 @@ class GoLanguageSupport(BaseLanguageSupport):
212
248
 
213
249
  def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
214
250
  return GoDependencyAnalyzer()
215
-
@@ -2,18 +2,28 @@
2
2
 
3
3
  import os
4
4
  import re
5
- from typing import List, Optional, Set
5
+ from typing import List
6
+ from typing import Optional
7
+ from typing import Set
8
+ from typing import cast
6
9
 
7
10
  from ..base_language import BaseLanguageSupport
8
- from ..dependency_analyzer import Dependency, DependencyAnalyzer, DependencyGraph
11
+ from ..dependency_analyzer import Dependency
12
+ from ..dependency_analyzer import DependencyAnalyzer
13
+ from ..dependency_analyzer import DependencyGraph
9
14
  from ..file_ignore import filter_walk_dirs
10
- from ..symbol_extractor import Symbol, SymbolExtractor
15
+ from ..symbol_extractor import Symbol
16
+ from ..symbol_extractor import SymbolExtractor
11
17
  from ..tree_sitter_extractor import TreeSitterExtractor
12
18
 
13
19
  try:
14
- from tree_sitter import Language, Node
15
20
  import tree_sitter_java
16
- JAVA_LANGUAGE: Optional[Language] = tree_sitter_java.language()
21
+ from tree_sitter import Language
22
+ from tree_sitter import Node
23
+
24
+ JAVA_LANGUAGE: Optional[Language] = cast(
25
+ Optional[Language], tree_sitter_java.language()
26
+ )
17
27
  except (ImportError, Exception):
18
28
  JAVA_LANGUAGE = None
19
29
 
@@ -52,13 +62,12 @@ class JavaSymbolExtractor(TreeSitterExtractor):
52
62
  if not JAVA_LANGUAGE:
53
63
  raise RuntimeError("Java tree-sitter grammar not available.")
54
64
  # 如果传入的是 PyCapsule,需要转换为 Language 对象
55
- if not isinstance(JAVA_LANGUAGE, Language):
56
- lang = Language(JAVA_LANGUAGE)
57
- else:
58
- lang = JAVA_LANGUAGE
65
+ lang = Language(JAVA_LANGUAGE)
59
66
  super().__init__(lang, JAVA_SYMBOL_QUERY)
60
67
 
61
- def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
68
+ def _create_symbol_from_capture(
69
+ self, node: Node, name: str, file_path: str
70
+ ) -> Optional[Symbol]:
62
71
  """Maps a tree-sitter capture to a Symbol object."""
63
72
  kind_map = {
64
73
  "method.name": "method",
@@ -69,13 +78,16 @@ class JavaSymbolExtractor(TreeSitterExtractor):
69
78
  "field.name": "field",
70
79
  "constructor.name": "constructor",
71
80
  }
72
-
81
+
73
82
  symbol_kind = kind_map.get(name)
74
83
  if not symbol_kind:
75
84
  return None
76
85
 
86
+ if node.text is None:
87
+ return None
88
+
77
89
  return Symbol(
78
- name=node.text.decode('utf8'),
90
+ name=node.text.decode("utf8"),
79
91
  kind=symbol_kind,
80
92
  file_path=file_path,
81
93
  line_start=node.start_point[0] + 1,
@@ -85,109 +97,131 @@ class JavaSymbolExtractor(TreeSitterExtractor):
85
97
 
86
98
  # --- Java Dependency Analyzer ---
87
99
 
100
+
88
101
  class JavaDependencyAnalyzer(DependencyAnalyzer):
89
102
  """Analyzes Java import dependencies."""
90
103
 
91
104
  def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
92
105
  """Analyzes Java import statements."""
93
106
  dependencies: List[Dependency] = []
94
-
107
+
95
108
  # Java import statements
96
109
  # import package.Class;
97
110
  # import package.*;
98
111
  # import static package.Class.method;
99
112
  import_pattern = re.compile(
100
- r'import\s+(?:static\s+)?([\w.]+)(?:\.\*)?\s*;',
101
- re.MULTILINE
113
+ r"import\s+(?:static\s+)?([\w.]+)(?:\.\*)?\s*;", re.MULTILINE
102
114
  )
103
-
104
- for line_num, line in enumerate(content.split('\n'), start=1):
115
+
116
+ for line_num, line in enumerate(content.split("\n"), start=1):
105
117
  import_match = import_pattern.search(line)
106
118
  if import_match:
107
119
  module_path = import_match.group(1)
108
120
  if module_path:
109
121
  # Extract class name if it's a specific import
110
- parts = module_path.split('.')
122
+ parts = module_path.split(".")
111
123
  imported_symbol = None
112
- if len(parts) > 1 and not line.strip().endswith('.*;'):
124
+ if len(parts) > 1 and not line.strip().endswith(".*;"):
113
125
  # Specific class import
114
126
  imported_symbol = parts[-1]
115
- module_path = '.'.join(parts[:-1])
116
-
117
- dependencies.append(Dependency(
118
- from_module=module_path,
119
- imported_symbol=imported_symbol,
120
- file_path=file_path,
121
- line=line_num,
122
- ))
123
-
127
+ module_path = ".".join(parts[:-1])
128
+
129
+ dependencies.append(
130
+ Dependency(
131
+ from_module=module_path,
132
+ imported_symbol=imported_symbol,
133
+ file_path=file_path,
134
+ line=line_num,
135
+ )
136
+ )
137
+
124
138
  return dependencies
125
139
 
126
140
  def build_dependency_graph(self, project_root: str) -> DependencyGraph:
127
141
  """Builds a dependency graph for a Java project."""
128
142
  graph = DependencyGraph()
129
-
143
+
130
144
  for root, dirs, files in os.walk(project_root):
131
145
  dirs[:] = filter_walk_dirs(dirs)
132
-
146
+
133
147
  for file in files:
134
- if not file.endswith('.java'):
148
+ if not file.endswith(".java"):
135
149
  continue
136
-
150
+
137
151
  file_path = os.path.join(root, file)
138
152
  try:
139
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
153
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
140
154
  content = f.read()
141
-
155
+
142
156
  dependencies = self.analyze_imports(file_path, content)
143
157
  for dep in dependencies:
144
158
  # Skip java.* and javax.* standard library packages
145
- if not dep.from_module.startswith(('java.', 'javax.')):
146
- dep_path = self._resolve_module_path(project_root, dep.from_module, dep.imported_symbol, file_path)
159
+ if not dep.from_module.startswith(("java.", "javax.")):
160
+ dep_path = self._resolve_module_path(
161
+ project_root,
162
+ dep.from_module,
163
+ dep.imported_symbol,
164
+ file_path,
165
+ )
147
166
  if dep_path and dep_path != file_path:
148
167
  graph.add_dependency(file_path, dep_path)
149
168
  except Exception:
150
169
  continue
151
-
170
+
152
171
  return graph
153
172
 
154
- def _resolve_module_path(self, project_root: str, package_name: str, class_name: Optional[str], from_file: str) -> Optional[str]:
173
+ def _resolve_module_path(
174
+ self,
175
+ project_root: str,
176
+ package_name: str,
177
+ class_name: Optional[str],
178
+ from_file: str,
179
+ ) -> Optional[str]:
155
180
  """Resolve a Java package name to a file path."""
156
181
  if not package_name:
157
182
  return None
158
-
183
+
159
184
  # Convert package name to directory path
160
- package_path = package_name.replace('.', os.sep)
161
-
185
+ package_path = package_name.replace(".", os.sep)
186
+
162
187
  # Try to find the class file
163
188
  if class_name:
164
189
  # Specific class import
165
- class_file = class_name + '.java'
166
- resolved = os.path.normpath(os.path.join(project_root, 'src', 'main', 'java', package_path, class_file))
190
+ class_file = class_name + ".java"
191
+ resolved = os.path.normpath(
192
+ os.path.join(
193
+ project_root, "src", "main", "java", package_path, class_file
194
+ )
195
+ )
167
196
  if os.path.exists(resolved) and os.path.isfile(resolved):
168
197
  return resolved
169
-
198
+
170
199
  # Try alternative source directories
171
- for src_dir in ['src', 'source', 'java']:
172
- resolved = os.path.normpath(os.path.join(project_root, src_dir, package_path, class_file))
200
+ for src_dir in ["src", "source", "java"]:
201
+ resolved = os.path.normpath(
202
+ os.path.join(project_root, src_dir, package_path, class_file)
203
+ )
173
204
  if os.path.exists(resolved) and os.path.isfile(resolved):
174
205
  return resolved
175
206
  else:
176
207
  # Wildcard import - try to find package-info.java or any class in the package
177
- package_dir = os.path.normpath(os.path.join(project_root, 'src', 'main', 'java', package_path))
208
+ package_dir = os.path.normpath(
209
+ os.path.join(project_root, "src", "main", "java", package_path)
210
+ )
178
211
  if os.path.exists(package_dir) and os.path.isdir(package_dir):
179
212
  # Return the first .java file found (or package-info.java if exists)
180
213
  for file in os.listdir(package_dir):
181
- if file.endswith('.java'):
214
+ if file.endswith(".java"):
182
215
  resolved = os.path.join(package_dir, file)
183
216
  if os.path.isfile(resolved):
184
217
  return resolved
185
-
218
+
186
219
  return None
187
220
 
188
221
 
189
222
  # --- Java Language Support ---
190
223
 
224
+
191
225
  class JavaLanguageSupport(BaseLanguageSupport):
192
226
  """Java语言支持。"""
193
227
 
@@ -197,7 +231,7 @@ class JavaLanguageSupport(BaseLanguageSupport):
197
231
 
198
232
  @property
199
233
  def file_extensions(self) -> Set[str]:
200
- return {'.java'}
234
+ return {".java"}
201
235
 
202
236
  def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
203
237
  if not JAVA_LANGUAGE:
@@ -209,4 +243,3 @@ class JavaLanguageSupport(BaseLanguageSupport):
209
243
 
210
244
  def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
211
245
  return JavaDependencyAnalyzer()
212
-