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
  # --- Rust Symbol Query ---
17
23
 
18
24
  RUST_SYMBOL_QUERY = """
@@ -49,8 +55,6 @@ RUST_SYMBOL_QUERY = """
49
55
  (type_item
50
56
  name: (type_identifier) @type.name)
51
57
 
52
- (extern_block) @extern
53
-
54
58
  (attribute_item) @attribute
55
59
  """
56
60
 
@@ -58,13 +62,17 @@ RUST_SYMBOL_QUERY = """
58
62
 
59
63
  try:
60
64
  import tree_sitter_rust
61
- RUST_LANGUAGE: Optional[Language] = tree_sitter_rust.language()
65
+
66
+ RUST_LANGUAGE: Optional[Language] = cast(
67
+ Optional[Language], tree_sitter_rust.language()
68
+ )
62
69
  except (ImportError, Exception):
63
70
  RUST_LANGUAGE = None
64
71
 
65
72
 
66
73
  # --- Rust Symbol Extractor ---
67
74
 
75
+
68
76
  class RustSymbolExtractor(TreeSitterExtractor):
69
77
  """Extracts symbols from Rust code using tree-sitter."""
70
78
 
@@ -73,7 +81,9 @@ class RustSymbolExtractor(TreeSitterExtractor):
73
81
  raise RuntimeError("Rust tree-sitter grammar not available.")
74
82
  super().__init__(RUST_LANGUAGE, RUST_SYMBOL_QUERY)
75
83
 
76
- def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
84
+ def _create_symbol_from_capture(
85
+ self, node: Node, name: str, file_path: str
86
+ ) -> Optional[Symbol]:
77
87
  """Maps a tree-sitter capture to a Symbol object."""
78
88
  kind_map = {
79
89
  "function.name": "function",
@@ -90,7 +100,7 @@ class RustSymbolExtractor(TreeSitterExtractor):
90
100
  "extern": "extern",
91
101
  "attribute": "attribute",
92
102
  }
93
-
103
+
94
104
  symbol_kind = kind_map.get(name)
95
105
  if not symbol_kind:
96
106
  return None
@@ -98,44 +108,56 @@ class RustSymbolExtractor(TreeSitterExtractor):
98
108
  # 对于 attribute,提取属性内容作为名称
99
109
  if symbol_kind == "attribute":
100
110
  # 提取属性文本
101
- attr_text = node.text.decode('utf8').strip()
111
+ if node.text is None:
112
+ return None
113
+ attr_text = node.text.decode("utf8").strip()
102
114
  # 移除开头的 # 或 #!
103
- if attr_text.startswith('#!'):
115
+ if attr_text.startswith("#!"):
104
116
  attr_text = attr_text[2:].strip()
105
- elif attr_text.startswith('#'):
117
+ elif attr_text.startswith("#"):
106
118
  attr_text = attr_text[1:].strip()
107
119
  # 移除外层的 []
108
- if attr_text.startswith('[') and attr_text.endswith(']'):
120
+ if attr_text.startswith("[") and attr_text.endswith("]"):
109
121
  attr_text = attr_text[1:-1].strip()
110
-
122
+
111
123
  # 提取属性名称(可能是 test, derive(Debug), cfg(test) 等)
112
124
  # 对于简单属性如 #[test],直接使用 test
113
125
  # 对于复杂属性如 #[derive(Debug)],使用 derive
114
126
  # 对于路径属性如 #[cfg(test)],使用 cfg
115
- attr_name = attr_text.split('(')[0].split('[')[0].split('=')[0].split(',')[0].strip()
116
-
127
+ attr_name = (
128
+ attr_text.split("(")[0]
129
+ .split("[")[0]
130
+ .split("=")[0]
131
+ .split(",")[0]
132
+ .strip()
133
+ )
134
+
117
135
  # 如果属性名称为空或只包含空白,使用整个属性文本(去掉括号)
118
- if not attr_name or attr_name == '':
136
+ if not attr_name or attr_name == "":
119
137
  symbol_name = attr_text if attr_text else "attribute"
120
138
  else:
121
139
  # 使用属性名称,但保留完整文本用于显示
122
140
  symbol_name = attr_name
123
141
  elif symbol_kind == "extern":
124
142
  # 对于 extern 块,提取 extern 关键字后的内容作为名称
125
- extern_text = node.text.decode('utf8').strip()
143
+ if node.text is None:
144
+ return None
145
+ extern_text = node.text.decode("utf8").strip()
126
146
  # 提取 extern "C" 或 extern "Rust" 等
127
147
  if '"' in extern_text:
128
148
  # 提取引号中的内容
129
149
  start = extern_text.find('"')
130
150
  end = extern_text.find('"', start + 1)
131
151
  if end > start:
132
- symbol_name = f"extern_{extern_text[start+1:end]}"
152
+ symbol_name = f"extern_{extern_text[start + 1 : end]}"
133
153
  else:
134
154
  symbol_name = "extern"
135
155
  else:
136
156
  symbol_name = "extern"
137
157
  else:
138
- symbol_name = node.text.decode('utf8')
158
+ if node.text is None:
159
+ return None
160
+ symbol_name = node.text.decode("utf8")
139
161
 
140
162
  return Symbol(
141
163
  name=symbol_name,
@@ -148,101 +170,114 @@ class RustSymbolExtractor(TreeSitterExtractor):
148
170
 
149
171
  # --- Rust Dependency Analyzer ---
150
172
 
173
+
151
174
  class RustDependencyAnalyzer(DependencyAnalyzer):
152
175
  """Analyzes Rust use and mod dependencies."""
153
176
 
154
177
  def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
155
178
  """Analyzes Rust use and mod statements."""
156
179
  dependencies: List[Dependency] = []
157
-
180
+
158
181
  # Match use statements: use crate::module or use std::collections
159
- use_pattern = re.compile(r'use\s+([^;]+);')
160
-
182
+ use_pattern = re.compile(r"use\s+([^;]+);")
183
+
161
184
  # Match mod declarations: mod module_name;
162
- mod_pattern = re.compile(r'mod\s+(\w+)\s*;')
163
-
164
- for line_num, line in enumerate(content.split('\n'), start=1):
185
+ mod_pattern = re.compile(r"mod\s+(\w+)\s*;")
186
+
187
+ for line_num, line in enumerate(content.split("\n"), start=1):
165
188
  # Check for use statements
166
189
  use_match = use_pattern.search(line)
167
190
  if use_match:
168
191
  use_path = use_match.group(1).strip()
169
192
  # Extract the crate/module name
170
- parts = use_path.split('::')
193
+ parts = use_path.split("::")
171
194
  if parts:
172
195
  crate_name = parts[0]
173
- symbol = '::'.join(parts[1:]) if len(parts) > 1 else None
174
- dependencies.append(Dependency(
175
- from_module=crate_name,
176
- imported_symbol=symbol,
177
- file_path=file_path,
178
- line=line_num,
179
- ))
180
-
196
+ symbol = "::".join(parts[1:]) if len(parts) > 1 else None
197
+ dependencies.append(
198
+ Dependency(
199
+ from_module=crate_name,
200
+ imported_symbol=symbol,
201
+ file_path=file_path,
202
+ line=line_num,
203
+ )
204
+ )
205
+
181
206
  # Check for mod declarations
182
207
  mod_match = mod_pattern.search(line)
183
208
  if mod_match:
184
209
  mod_name = mod_match.group(1)
185
- dependencies.append(Dependency(
186
- from_module=mod_name,
187
- imported_symbol=None,
188
- file_path=file_path,
189
- line=line_num,
190
- ))
191
-
210
+ dependencies.append(
211
+ Dependency(
212
+ from_module=mod_name,
213
+ imported_symbol=None,
214
+ file_path=file_path,
215
+ line=line_num,
216
+ )
217
+ )
218
+
192
219
  return dependencies
193
220
 
194
221
  def build_dependency_graph(self, project_root: str) -> DependencyGraph:
195
222
  """Builds a dependency graph for a Rust project."""
196
223
  graph = DependencyGraph()
197
-
224
+
198
225
  for root, dirs, files in os.walk(project_root):
199
226
  dirs[:] = filter_walk_dirs(dirs)
200
-
227
+
201
228
  for file in files:
202
- if not file.endswith('.rs'):
229
+ if not file.endswith(".rs"):
203
230
  continue
204
-
231
+
205
232
  file_path = os.path.join(root, file)
206
233
  try:
207
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
234
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
208
235
  content = f.read()
209
-
236
+
210
237
  dependencies = self.analyze_imports(file_path, content)
211
238
  for dep in dependencies:
212
239
  # For Rust, resolve mod declarations to file paths
213
- if not dep.from_module.startswith(('std', 'core', 'alloc', 'proc_macro')):
240
+ if not dep.from_module.startswith(
241
+ ("std", "core", "alloc", "proc_macro")
242
+ ):
214
243
  # Try to resolve local modules
215
- dep_path = self._resolve_module_path(project_root, dep.from_module, file_path)
244
+ dep_path = self._resolve_module_path(
245
+ project_root, dep.from_module, file_path
246
+ )
216
247
  if dep_path and dep_path != file_path:
217
248
  graph.add_dependency(file_path, dep_path)
218
249
  except Exception:
219
250
  continue
220
-
251
+
221
252
  return graph
222
253
 
223
- def _resolve_module_path(self, project_root: str, module_name: str, from_file: str) -> Optional[str]:
254
+ def _resolve_module_path(
255
+ self, project_root: str, module_name: str, from_file: str
256
+ ) -> Optional[str]:
224
257
  """Resolve a Rust module name to a file path."""
225
258
  # Rust modules can be:
226
259
  # 1. mod.rs in a directory
227
260
  # 2. module_name.rs in the same directory
228
261
  # 3. module_name/mod.rs
229
-
262
+
230
263
  base_dir = os.path.dirname(from_file)
231
-
264
+
232
265
  # Try module_name.rs in same directory
233
266
  module_file = os.path.join(base_dir, f"{module_name}.rs")
234
267
  if os.path.exists(module_file):
235
268
  return module_file
236
-
269
+
237
270
  # Try module_name/mod.rs
238
271
  module_dir = os.path.join(base_dir, module_name)
239
272
  mod_rs = os.path.join(module_dir, "mod.rs")
240
273
  if os.path.exists(mod_rs):
241
274
  return mod_rs
242
-
275
+
243
276
  # Try in parent directories (for nested modules)
244
277
  current_dir = base_dir
245
- while current_dir != project_root and current_dir != os.path.dirname(current_dir):
278
+ while current_dir != project_root and current_dir != os.path.dirname(
279
+ current_dir
280
+ ):
246
281
  module_file = os.path.join(current_dir, f"{module_name}.rs")
247
282
  if os.path.exists(module_file):
248
283
  return module_file
@@ -251,12 +286,12 @@ class RustDependencyAnalyzer(DependencyAnalyzer):
251
286
  if os.path.exists(mod_rs):
252
287
  return mod_rs
253
288
  current_dir = os.path.dirname(current_dir)
254
-
289
+
255
290
  return None
256
291
 
257
292
  def _is_source_file(self, file_path: str) -> bool:
258
293
  """Check if a file is a Rust source file."""
259
- return file_path.endswith('.rs')
294
+ return file_path.endswith(".rs")
260
295
 
261
296
 
262
297
  class RustLanguageSupport(BaseLanguageSupport):
@@ -264,11 +299,11 @@ class RustLanguageSupport(BaseLanguageSupport):
264
299
 
265
300
  @property
266
301
  def language_name(self) -> str:
267
- return 'rust'
302
+ return "rust"
268
303
 
269
304
  @property
270
305
  def file_extensions(self) -> Set[str]:
271
- return {'.rs'}
306
+ return {".rs"}
272
307
 
273
308
  def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
274
309
  try:
@@ -278,4 +313,3 @@ class RustLanguageSupport(BaseLanguageSupport):
278
313
 
279
314
  def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
280
315
  return RustDependencyAnalyzer()
281
-
@@ -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_typescript
16
- TS_LANGUAGE: Optional[Language] = tree_sitter_typescript.language_typescript()
21
+ from tree_sitter import Language
22
+ from tree_sitter import Node
23
+
24
+ TS_LANGUAGE: Optional[Language] = cast(
25
+ Optional[Language], tree_sitter_typescript.language_typescript()
26
+ )
17
27
  except (ImportError, Exception):
18
28
  TS_LANGUAGE = None
19
29
 
@@ -71,13 +81,12 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
71
81
  if not TS_LANGUAGE:
72
82
  raise RuntimeError("TypeScript tree-sitter grammar not available.")
73
83
  # 如果传入的是 PyCapsule,需要转换为 Language 对象
74
- if not isinstance(TS_LANGUAGE, Language):
75
- lang = Language(TS_LANGUAGE)
76
- else:
77
- lang = TS_LANGUAGE
84
+ lang = Language(TS_LANGUAGE)
78
85
  super().__init__(lang, TS_SYMBOL_QUERY)
79
86
 
80
- def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
87
+ def _create_symbol_from_capture(
88
+ self, node: Node, name: str, file_path: str
89
+ ) -> Optional[Symbol]:
81
90
  """Maps a tree-sitter capture to a Symbol object."""
82
91
  kind_map = {
83
92
  "function.name": "function",
@@ -92,7 +101,7 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
92
101
  "variable.name": "variable",
93
102
  "decorator": "decorator",
94
103
  }
95
-
104
+
96
105
  symbol_kind = kind_map.get(name)
97
106
  if not symbol_kind:
98
107
  return None
@@ -102,16 +111,22 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
102
111
  symbol_name = "<anonymous_arrow_function>"
103
112
  elif name == "decorator":
104
113
  # Extract decorator name (e.g., @Component -> Component)
105
- decorator_text = node.text.decode('utf8').strip()
106
- if decorator_text.startswith('@'):
107
- symbol_name = decorator_text[1:].split('(')[0].strip()
114
+ if node.text is None:
115
+ return None
116
+ decorator_text = node.text.decode("utf8").strip()
117
+ if decorator_text.startswith("@"):
118
+ symbol_name = decorator_text[1:].split("(")[0].strip()
108
119
  else:
109
- symbol_name = decorator_text.split('(')[0].strip()
120
+ symbol_name = decorator_text.split("(")[0].strip()
110
121
  elif name == "generator.name":
111
- symbol_name = node.text.decode('utf8')
122
+ if node.text is None:
123
+ return None
124
+ symbol_name = node.text.decode("utf8")
112
125
  else:
113
- symbol_name = node.text.decode('utf8')
114
-
126
+ if node.text is None:
127
+ return None
128
+ symbol_name = node.text.decode("utf8")
129
+
115
130
  if not symbol_name:
116
131
  return None
117
132
 
@@ -126,13 +141,14 @@ class TypeScriptSymbolExtractor(TreeSitterExtractor):
126
141
 
127
142
  # --- TypeScript Dependency Analyzer ---
128
143
 
144
+
129
145
  class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
130
146
  """Analyzes TypeScript import dependencies."""
131
147
 
132
148
  def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
133
149
  """Analyzes TypeScript import statements."""
134
150
  dependencies: List[Dependency] = []
135
-
151
+
136
152
  # ES6 import statements (same as JavaScript)
137
153
  # import module from 'path'
138
154
  # import { symbol } from 'path'
@@ -140,16 +156,16 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
140
156
  # import type { Type } from 'path'
141
157
  import_pattern = re.compile(
142
158
  r'import\s+(?:type\s+)?(?:(?:\*\s+as\s+(\w+)|(\{[^}]*\})|(\w+))\s+from\s+)?["\']([^"\']+)["\']',
143
- re.MULTILINE
159
+ re.MULTILINE,
144
160
  )
145
-
161
+
146
162
  # CommonJS require statements
147
163
  require_pattern = re.compile(
148
164
  r'(?:const|let|var)\s+\w+\s*=\s*require\(["\']([^"\']+)["\']\)|require\(["\']([^"\']+)["\']\)',
149
- re.MULTILINE
165
+ re.MULTILINE,
150
166
  )
151
-
152
- for line_num, line in enumerate(content.split('\n'), start=1):
167
+
168
+ for line_num, line in enumerate(content.split("\n"), start=1):
153
169
  # Check for ES6 imports
154
170
  import_match = import_pattern.search(line)
155
171
  if import_match:
@@ -158,97 +174,115 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
158
174
  # Extract imported symbols if any
159
175
  symbols_group = import_match.group(2) or import_match.group(1)
160
176
  imported_symbol = None
161
- if symbols_group and symbols_group.startswith('{'):
177
+ if symbols_group and symbols_group.startswith("{"):
162
178
  # Extract first symbol from { symbol1, symbol2 }
163
- symbol_match = re.search(r'\{([^}]+)\}', symbols_group)
179
+ symbol_match = re.search(r"\{([^}]+)\}", symbols_group)
164
180
  if symbol_match:
165
- first_symbol = symbol_match.group(1).split(',')[0].strip()
166
- imported_symbol = first_symbol.split(' as ')[0].strip()
167
-
168
- dependencies.append(Dependency(
169
- from_module=module_path,
170
- imported_symbol=imported_symbol,
171
- file_path=file_path,
172
- line=line_num,
173
- ))
174
-
181
+ first_symbol = symbol_match.group(1).split(",")[0].strip()
182
+ imported_symbol = first_symbol.split(" as ")[0].strip()
183
+
184
+ dependencies.append(
185
+ Dependency(
186
+ from_module=module_path,
187
+ imported_symbol=imported_symbol,
188
+ file_path=file_path,
189
+ line=line_num,
190
+ )
191
+ )
192
+
175
193
  # Check for require statements
176
194
  require_match = require_pattern.search(line)
177
195
  if require_match:
178
196
  module_path = require_match.group(1) or require_match.group(2)
179
197
  if module_path:
180
- dependencies.append(Dependency(
181
- from_module=module_path,
182
- imported_symbol=None,
183
- file_path=file_path,
184
- line=line_num,
185
- ))
186
-
198
+ dependencies.append(
199
+ Dependency(
200
+ from_module=module_path,
201
+ imported_symbol=None,
202
+ file_path=file_path,
203
+ line=line_num,
204
+ )
205
+ )
206
+
187
207
  return dependencies
188
208
 
189
209
  def build_dependency_graph(self, project_root: str) -> DependencyGraph:
190
210
  """Builds a dependency graph for a TypeScript project."""
191
211
  graph = DependencyGraph()
192
-
212
+
193
213
  for root, dirs, files in os.walk(project_root):
194
214
  dirs[:] = filter_walk_dirs(dirs)
195
-
215
+
196
216
  for file in files:
197
- if not file.endswith(('.ts', '.tsx', '.cts', '.mts')):
217
+ if not file.endswith((".ts", ".tsx", ".cts", ".mts")):
198
218
  continue
199
-
219
+
200
220
  file_path = os.path.join(root, file)
201
221
  try:
202
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
222
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
203
223
  content = f.read()
204
-
224
+
205
225
  dependencies = self.analyze_imports(file_path, content)
206
226
  for dep in dependencies:
207
227
  # Skip node_modules and external packages
208
- if dep.from_module.startswith(('.', '/')) or not dep.from_module.startswith('http'):
209
- dep_path = self._resolve_module_path(project_root, dep.from_module, file_path)
228
+ if dep.from_module.startswith(
229
+ (".", "/")
230
+ ) or not dep.from_module.startswith("http"):
231
+ dep_path = self._resolve_module_path(
232
+ project_root, dep.from_module, file_path
233
+ )
210
234
  if dep_path and dep_path != file_path:
211
235
  graph.add_dependency(file_path, dep_path)
212
236
  except Exception:
213
237
  continue
214
-
238
+
215
239
  return graph
216
240
 
217
- def _resolve_module_path(self, project_root: str, module_name: str, from_file: str) -> Optional[str]:
241
+ def _resolve_module_path(
242
+ self, project_root: str, module_name: str, from_file: str
243
+ ) -> Optional[str]:
218
244
  """Resolve a TypeScript module name to a file path."""
219
245
  if not module_name:
220
246
  return None
221
-
247
+
222
248
  # Handle relative imports
223
- if module_name.startswith('.'):
249
+ if module_name.startswith("."):
224
250
  base_dir = os.path.dirname(from_file)
225
251
  # Resolve relative path
226
- if module_name.endswith(('.ts', '.tsx')):
252
+ if module_name.endswith((".ts", ".tsx")):
227
253
  # Direct file reference
228
254
  resolved = os.path.normpath(os.path.join(base_dir, module_name))
229
255
  else:
230
256
  # Try with .ts extension
231
- resolved = os.path.normpath(os.path.join(base_dir, module_name + '.ts'))
257
+ resolved = os.path.normpath(os.path.join(base_dir, module_name + ".ts"))
232
258
  if not os.path.exists(resolved):
233
259
  # Try with .tsx extension
234
- resolved = os.path.normpath(os.path.join(base_dir, module_name + '.tsx'))
260
+ resolved = os.path.normpath(
261
+ os.path.join(base_dir, module_name + ".tsx")
262
+ )
235
263
  if not os.path.exists(resolved):
236
264
  # Try index.ts
237
- resolved = os.path.normpath(os.path.join(base_dir, module_name, 'index.ts'))
265
+ resolved = os.path.normpath(
266
+ os.path.join(base_dir, module_name, "index.ts")
267
+ )
238
268
  if not os.path.exists(resolved):
239
- resolved = os.path.normpath(os.path.join(base_dir, module_name, 'index.tsx'))
240
-
269
+ resolved = os.path.normpath(
270
+ os.path.join(base_dir, module_name, "index.tsx")
271
+ )
272
+
241
273
  if os.path.exists(resolved) and os.path.isfile(resolved):
242
274
  return resolved
243
-
275
+
244
276
  # Handle absolute imports (from project root)
245
- if module_name.startswith('/'):
246
- resolved = os.path.normpath(os.path.join(project_root, module_name.lstrip('/')))
247
- if not resolved.endswith(('.ts', '.tsx')):
248
- resolved += '.ts'
277
+ if module_name.startswith("/"):
278
+ resolved = os.path.normpath(
279
+ os.path.join(project_root, module_name.lstrip("/"))
280
+ )
281
+ if not resolved.endswith((".ts", ".tsx")):
282
+ resolved += ".ts"
249
283
  if os.path.exists(resolved) and os.path.isfile(resolved):
250
284
  return resolved
251
-
285
+
252
286
  # For node_modules and external packages, we can't resolve without package.json
253
287
  # Return None to skip them
254
288
  return None
@@ -256,6 +290,7 @@ class TypeScriptDependencyAnalyzer(DependencyAnalyzer):
256
290
 
257
291
  # --- TypeScript Language Support ---
258
292
 
293
+
259
294
  class TypeScriptLanguageSupport(BaseLanguageSupport):
260
295
  """TypeScript语言支持。"""
261
296
 
@@ -265,7 +300,7 @@ class TypeScriptLanguageSupport(BaseLanguageSupport):
265
300
 
266
301
  @property
267
302
  def file_extensions(self) -> Set[str]:
268
- return {'.ts', '.tsx', '.cts', '.mts'}
303
+ return {".ts", ".tsx", ".cts", ".mts"}
269
304
 
270
305
  def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
271
306
  if not TS_LANGUAGE:
@@ -277,4 +312,3 @@ class TypeScriptLanguageSupport(BaseLanguageSupport):
277
312
 
278
313
  def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
279
314
  return TypeScriptDependencyAnalyzer()
280
-