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,17 +1,27 @@
1
1
  import os
2
2
  import re
3
- from dataclasses import dataclass, field
4
- from typing import Any, List, Optional, Set
3
+ from dataclasses import dataclass
4
+ from dataclasses import field
5
+ from typing import Any
6
+ from typing import Dict
7
+ from typing import List
8
+ from typing import Optional
9
+ from typing import Set
10
+ from typing import Tuple
5
11
 
6
12
  from .dependency_analyzer import DependencyGraph
7
13
  from .file_ignore import filter_walk_dirs
8
- from .symbol_extractor import Symbol, SymbolTable
9
- from .language_support import detect_language, get_symbol_extractor, get_dependency_analyzer
14
+ from .language_support import detect_language
15
+ from .language_support import get_dependency_analyzer
16
+ from .language_support import get_symbol_extractor
17
+ from .symbol_extractor import Symbol
18
+ from .symbol_extractor import SymbolTable
10
19
 
11
20
 
12
21
  @dataclass
13
22
  class EditContext:
14
23
  """Provides contextual information for a specific code location."""
24
+
15
25
  file_path: str
16
26
  line_start: int
17
27
  line_end: int
@@ -25,6 +35,7 @@ class EditContext:
25
35
  @dataclass
26
36
  class Reference:
27
37
  """Represents a reference to a symbol."""
38
+
28
39
  symbol: Symbol
29
40
  file_path: str
30
41
  line: int
@@ -42,10 +53,12 @@ class ContextManager:
42
53
  self.dependency_graph = DependencyGraph()
43
54
  self._file_cache: dict[str, str] = {} # Cache file contents
44
55
 
45
- def get_edit_context(self, file_path: str, line_start: int, line_end: int) -> EditContext:
56
+ def get_edit_context(
57
+ self, file_path: str, line_start: int, line_end: int
58
+ ) -> EditContext:
46
59
  """
47
60
  Gets contextual information for a given edit location.
48
-
61
+
49
62
  Returns:
50
63
  EditContext with information about the current scope, used symbols,
51
64
  imported symbols, and relevant files.
@@ -53,25 +66,27 @@ class ContextManager:
53
66
  # Get file content
54
67
  content = self._get_file_content(file_path)
55
68
  if not content:
56
- return EditContext(file_path=file_path, line_start=line_start, line_end=line_end)
57
-
69
+ return EditContext(
70
+ file_path=file_path, line_start=line_start, line_end=line_end
71
+ )
72
+
58
73
  # Find current scope (function or class)
59
74
  current_scope = self._find_current_scope(file_path, line_start)
60
-
75
+
61
76
  # Find symbols used in the edit region
62
77
  used_symbols = self._find_used_symbols(file_path, content, line_start, line_end)
63
-
78
+
64
79
  # Find imported symbols
65
80
  imported_symbols = self._find_imported_symbols(file_path)
66
-
81
+
67
82
  # Find relevant files (dependencies and dependents)
68
83
  relevant_files = self._find_relevant_files(file_path)
69
-
84
+
70
85
  # Build context summary
71
86
  context_summary = self._build_context_summary(
72
87
  current_scope, used_symbols, imported_symbols, relevant_files
73
88
  )
74
-
89
+
75
90
  return EditContext(
76
91
  file_path=file_path,
77
92
  line_start=line_start,
@@ -83,95 +98,104 @@ class ContextManager:
83
98
  context_summary=context_summary,
84
99
  )
85
100
 
86
- def find_references(self, symbol_name: str, file_path: Optional[str] = None) -> List[Reference]:
101
+ def find_references(
102
+ self, symbol_name: str, file_path: Optional[str] = None
103
+ ) -> List[Reference]:
87
104
  """
88
105
  Finds all references to a symbol.
89
-
106
+
90
107
  Args:
91
108
  symbol_name: Name of the symbol to find references for
92
109
  file_path: Optional file path to limit search scope
93
-
110
+
94
111
  Returns:
95
112
  List of Reference objects pointing to where the symbol is used
96
113
  """
97
114
  references: List[Reference] = []
98
-
115
+
99
116
  # Check if file is stale and update if needed
100
117
  if file_path and self.symbol_table.is_file_stale(file_path):
101
118
  self._refresh_file_symbols(file_path)
102
-
119
+
103
120
  # Find symbol definitions
104
121
  symbols = self.symbol_table.find_symbol(symbol_name, file_path)
105
122
  if not symbols:
106
123
  return references
107
-
124
+
108
125
  # Search in files that might reference this symbol
109
126
  search_files: Set[str] = set()
110
-
127
+
111
128
  # Add files that depend on the symbol's file
112
129
  for symbol in symbols:
113
130
  search_files.add(symbol.file_path)
114
131
  dependents = self.dependency_graph.get_dependents(symbol.file_path)
115
132
  search_files.update(dependents)
116
-
133
+
117
134
  # If file_path is specified, limit search to that file
118
135
  if file_path:
119
136
  search_files = {f for f in search_files if f == file_path}
120
-
137
+
121
138
  # Search for references in each file
122
139
  for file_path_to_search in search_files:
123
140
  # Check if file is stale and update if needed
124
141
  if self.symbol_table.is_file_stale(file_path_to_search):
125
142
  self._refresh_file_symbols(file_path_to_search)
126
-
143
+
127
144
  content = self._get_file_content(file_path_to_search)
128
145
  if not content:
129
146
  continue
130
-
147
+
131
148
  # Simple pattern matching for symbol references
132
149
  # This is a basic implementation; could be enhanced with AST analysis
133
- pattern = r'\b' + re.escape(symbol_name) + r'\b'
150
+ pattern = r"\b" + re.escape(symbol_name) + r"\b"
134
151
  for match in re.finditer(pattern, content):
135
- line_num = content[:match.start()].count('\n') + 1
136
- col_num = match.start() - content.rfind('\n', 0, match.start()) - 1
137
-
152
+ line_num = content[: match.start()].count("\n") + 1
153
+ col_num = match.start() - content.rfind("\n", 0, match.start()) - 1
154
+
138
155
  # Check if this is not a definition (basic check)
139
- line_start = content.rfind('\n', 0, match.start()) + 1
140
- line_end = content.find('\n', match.end())
156
+ line_start = content.rfind("\n", 0, match.start()) + 1
157
+ line_end = content.find("\n", match.end())
141
158
  if line_end == -1:
142
159
  line_end = len(content)
143
160
  line_content = content[line_start:line_end]
144
-
161
+
145
162
  # Skip if it's a definition (contains 'def', 'class', etc.)
146
- if any(keyword in line_content for keyword in ['def ', 'class ', 'import ', 'from ']):
163
+ if any(
164
+ keyword in line_content
165
+ for keyword in ["def ", "class ", "import ", "from "]
166
+ ):
147
167
  continue
148
-
168
+
149
169
  # Use the first matching symbol definition
150
170
  if symbols:
151
- references.append(Reference(
152
- symbol=symbols[0],
153
- file_path=file_path_to_search,
154
- line=line_num,
155
- column=col_num,
156
- ))
157
-
171
+ references.append(
172
+ Reference(
173
+ symbol=symbols[0],
174
+ file_path=file_path_to_search,
175
+ line=line_num,
176
+ column=col_num,
177
+ )
178
+ )
179
+
158
180
  return references
159
181
 
160
- def find_definition(self, symbol_name: str, file_path: Optional[str] = None) -> Optional[Symbol]:
182
+ def find_definition(
183
+ self, symbol_name: str, file_path: Optional[str] = None
184
+ ) -> Optional[Symbol]:
161
185
  """
162
186
  Finds the definition of a symbol.
163
-
187
+
164
188
  Args:
165
189
  symbol_name: Name of the symbol to find
166
190
  file_path: Optional file path to limit search scope
167
-
191
+
168
192
  Returns:
169
193
  Symbol object if found, None otherwise
170
194
  """
171
195
  # Check if file is stale and update if needed
172
196
  if file_path and self.symbol_table.is_file_stale(file_path):
173
197
  self._refresh_file_symbols(file_path)
174
-
198
+
175
199
  symbols = self.symbol_table.find_symbol(symbol_name, file_path)
176
200
  if symbols:
177
201
  # Return the first definition (could be enhanced to find the most relevant one)
@@ -200,11 +224,13 @@ class ContextManager:
200
224
  symbols = extractor.extract_symbols(file_path, content)
201
225
  for symbol in symbols:
202
226
  self.symbol_table.add_symbol(symbol)
203
-
227
+
204
228
  # Update file modification time after extracting symbols
205
229
  if os.path.exists(file_path):
206
230
  try:
207
- self.symbol_table._file_mtimes[file_path] = os.path.getmtime(file_path)
231
+ self.symbol_table._file_mtimes[file_path] = os.path.getmtime(
232
+ file_path
233
+ )
208
234
  except Exception:
209
235
  pass
210
236
 
@@ -217,21 +243,21 @@ class ContextManager:
217
243
  dep_path = self._resolve_dependency_path(file_path, dep.from_module)
218
244
  if dep_path:
219
245
  self.dependency_graph.add_dependency(file_path, dep_path)
220
-
246
+
221
247
  # 6. Save updated symbols to cache
222
248
  self.symbol_table.save_cache()
223
-
249
+
224
250
  def _refresh_file_symbols(self, file_path: str):
225
251
  """Refresh symbols for a file that has been modified externally.
226
-
252
+
227
253
  This method is called when a file is detected to be stale (modified
228
254
  outside of Jarvis's control).
229
255
  """
230
256
  if not os.path.exists(file_path):
231
257
  return
232
-
258
+
233
259
  try:
234
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
260
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
235
261
  content = f.read()
236
262
  self.update_context_for_file(file_path, content)
237
263
  except Exception:
@@ -242,12 +268,12 @@ class ContextManager:
242
268
  """Get file content, using cache if available."""
243
269
  if file_path in self._file_cache:
244
270
  return self._file_cache[file_path]
245
-
271
+
246
272
  if not os.path.exists(file_path):
247
273
  return None
248
-
274
+
249
275
  try:
250
- with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
276
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
251
277
  content = f.read()
252
278
  self._file_cache[file_path] = content
253
279
  return content
@@ -260,110 +286,113 @@ class ContextManager:
260
286
  if self.symbol_table.is_file_stale(file_path):
261
287
  self._refresh_file_symbols(file_path)
262
288
  symbols = self.symbol_table.get_file_symbols(file_path)
263
-
289
+
264
290
  # Find the innermost scope containing the line
265
291
  current_scope = None
266
292
  for symbol in symbols:
267
- if symbol.kind in ('function', 'class', 'method'):
293
+ if symbol.kind in ("function", "class", "method"):
268
294
  if symbol.line_start <= line_num <= symbol.line_end:
269
295
  # Choose the most nested scope
270
296
  if current_scope is None or (
271
- symbol.line_start >= current_scope.line_start and
272
- symbol.line_end <= current_scope.line_end
297
+ symbol.line_start >= current_scope.line_start
298
+ and symbol.line_end <= current_scope.line_end
273
299
  ):
274
300
  current_scope = symbol
275
-
301
+
276
302
  return current_scope
277
303
 
278
- def _find_used_symbols(self, file_path: str, content: str, line_start: int, line_end: int) -> List[Symbol]:
304
+ def _find_used_symbols(
305
+ self, file_path: str, content: str, line_start: int, line_end: int
306
+ ) -> List[Symbol]:
279
307
  """Find symbols used in the specified line range.
280
-
308
+
281
309
  改进版本:
282
310
  1. 区分定义和调用:检查符号是否在当前行范围内定义
283
- 2. 获取定义位置:优先使用 LSP,如果不支持则使用 tree-sitter
311
+ 2. 获取定义位置:使用 tree-sitter 符号提取器
284
312
  3. 为每个使用的符号添加定义位置信息
285
313
  """
286
314
  # Check if file is stale and update if needed
287
315
  if self.symbol_table.is_file_stale(file_path):
288
316
  self._refresh_file_symbols(file_path)
289
-
317
+
290
318
  # Extract the code in the range
291
- lines = content.split('\n')
292
- region_content = '\n'.join(lines[line_start-1:line_end])
293
-
319
+ lines = content.split("\n")
320
+ region_content = "\n".join(lines[line_start - 1 : line_end])
321
+
294
322
  used_symbols: List[Symbol] = []
295
323
  all_symbols = self.symbol_table.get_file_symbols(file_path)
296
-
297
- # 尝试获取 LSP 客户端(优先使用)
298
- lsp_client = None
299
- try:
300
- from jarvis.jarvis_tools.lsp_client import LSPClientTool
301
- lsp_client = LSPClientTool.get_client_for_file(file_path, self.project_root)
302
- except Exception:
303
- pass
304
-
305
- # 尝试获取 tree-sitter 提取器(作为后备)
324
+
325
+ # 尝试获取 tree-sitter 提取器
306
326
  treesitter_extractor = None
307
327
  try:
308
328
  from jarvis.jarvis_code_agent.code_analyzer.language_support import (
309
329
  detect_language,
330
+ )
331
+ from jarvis.jarvis_code_agent.code_analyzer.language_support import (
310
332
  get_symbol_extractor,
311
333
  )
334
+
312
335
  language = detect_language(file_path)
313
336
  if language:
314
337
  treesitter_extractor = get_symbol_extractor(language)
315
338
  except Exception:
316
339
  pass
317
-
340
+
318
341
  # 用于跟踪已处理的符号,避免重复
319
- processed_symbols = {} # {symbol_name: (symbol, is_definition, definition_location)}
320
-
342
+ processed_symbols: Dict[
343
+ str, Tuple[Symbol, bool, Optional[Symbol]]
344
+ ] = {} # {symbol_name: (symbol, is_definition, definition_location)}
345
+
321
346
  # Simple pattern matching to find symbol usage
322
347
  for symbol in all_symbols:
323
- if symbol.kind == 'import':
348
+ if symbol.kind == "import":
324
349
  continue
325
-
326
- pattern = r'\b' + re.escape(symbol.name) + r'\b'
350
+
351
+ pattern = r"\b" + re.escape(symbol.name) + r"\b"
327
352
  matches = list(re.finditer(pattern, region_content))
328
353
  if not matches:
329
354
  continue
330
-
355
+
331
356
  # 检查符号是否在当前行范围内定义
332
357
  is_definition_in_range = (
333
- symbol.file_path == file_path and
334
- symbol.line_start >= line_start and
335
- symbol.line_start <= line_end
358
+ symbol.file_path == file_path
359
+ and symbol.line_start >= line_start
360
+ and symbol.line_start <= line_end
336
361
  )
337
-
362
+
338
363
  # 检查是否有调用(不在定义行的使用)
339
364
  has_calls = False
340
365
  call_line = None
341
366
  call_column = None
342
367
  for match in matches:
343
368
  match_start = match.start()
344
- match_line_in_region = region_content[:match_start].count('\n') + 1
369
+ match_line_in_region = region_content[:match_start].count("\n") + 1
345
370
  match_line = line_start + match_line_in_region - 1
346
-
371
+
347
372
  # 如果使用位置不在定义行,则认为是调用
348
373
  if not is_definition_in_range or match_line != symbol.line_start:
349
374
  has_calls = True
350
375
  call_line = match_line
351
376
  # 计算列号
352
- line_start_pos = region_content[:match_start].rfind('\n') + 1
377
+ line_start_pos = region_content[:match_start].rfind("\n") + 1
353
378
  call_column = match_start - line_start_pos
354
379
  break
355
-
380
+
356
381
  # 处理定义
357
382
  if is_definition_in_range:
358
383
  symbol.is_definition = True
359
384
  if symbol.name not in processed_symbols:
360
385
  processed_symbols[symbol.name] = (symbol, True, None)
361
-
386
+
362
387
  # 处理调用
363
388
  if has_calls or not is_definition_in_range:
364
389
  # 创建或更新引用符号
365
390
  if symbol.name in processed_symbols:
366
- existing_symbol, existing_is_def, existing_def_loc = processed_symbols[symbol.name]
391
+ (
392
+ existing_symbol,
393
+ existing_is_def,
394
+ existing_def_loc,
395
+ ) = processed_symbols[symbol.name]
367
396
  # 如果已有定义,跳过;否则更新定义位置
368
397
  if not existing_is_def and not existing_def_loc:
369
398
  # 尝试获取定义位置
@@ -372,16 +401,21 @@ class ContextManager:
372
401
  file_path,
373
402
  call_line or line_start,
374
403
  call_column or 0,
375
- lsp_client,
376
404
  treesitter_extractor,
377
405
  content,
378
406
  )
379
-
407
+
380
408
  if definition_location:
381
- processed_symbols[symbol.name] = (existing_symbol, False, definition_location)
409
+ processed_symbols[symbol.name] = (
410
+ existing_symbol,
411
+ False,
412
+ definition_location,
413
+ )
382
414
  else:
383
415
  # 从符号表中查找
384
- definition_symbols = self.symbol_table.find_symbol(symbol.name)
416
+ definition_symbols = self.symbol_table.find_symbol(
417
+ symbol.name
418
+ )
385
419
  if definition_symbols:
386
420
  def_symbol = definition_symbols[0]
387
421
  definition_location = Symbol(
@@ -392,7 +426,11 @@ class ContextManager:
392
426
  line_end=def_symbol.line_end,
393
427
  signature=def_symbol.signature,
394
428
  )
395
- processed_symbols[symbol.name] = (existing_symbol, False, definition_location)
429
+ processed_symbols[symbol.name] = (
430
+ existing_symbol,
431
+ False,
432
+ definition_location,
433
+ )
396
434
  else:
397
435
  # 创建新的引用符号
398
436
  reference_symbol = Symbol(
@@ -406,18 +444,17 @@ class ContextManager:
406
444
  parent=symbol.parent,
407
445
  is_definition=False,
408
446
  )
409
-
447
+
410
448
  # 尝试获取定义位置
411
449
  definition_location = self._find_definition_location(
412
450
  symbol.name,
413
451
  file_path,
414
452
  call_line or line_start,
415
453
  call_column or 0,
416
- lsp_client,
417
454
  treesitter_extractor,
418
455
  content,
419
456
  )
420
-
457
+
421
458
  if definition_location:
422
459
  reference_symbol.definition_location = definition_location
423
460
  else:
@@ -433,9 +470,13 @@ class ContextManager:
433
470
  line_end=def_symbol.line_end,
434
471
  signature=def_symbol.signature,
435
472
  )
436
-
437
- processed_symbols[symbol.name] = (reference_symbol, False, reference_symbol.definition_location)
438
-
473
+
474
+ processed_symbols[symbol.name] = (
475
+ reference_symbol,
476
+ False,
477
+ reference_symbol.definition_location,
478
+ )
479
+
439
480
  # 将处理后的符号添加到结果列表
440
481
  for symbol, is_def, def_loc in processed_symbols.values():
441
482
  if is_def:
@@ -443,75 +484,34 @@ class ContextManager:
443
484
  if def_loc:
444
485
  symbol.definition_location = def_loc
445
486
  used_symbols.append(symbol)
446
-
487
+
447
488
  return used_symbols
448
-
489
+
449
490
  def _find_definition_location(
450
491
  self,
451
492
  symbol_name: str,
452
493
  file_path: str,
453
494
  line: int,
454
495
  column: int,
455
- lsp_client: Optional[Any],
456
496
  treesitter_extractor: Optional[Any],
457
497
  content: str,
458
498
  ) -> Optional[Symbol]:
459
499
  """查找符号的定义位置。
460
-
461
- 优先使用 LSP,如果不支持则使用 tree-sitter
462
-
500
+
501
+ 使用 tree-sitter 符号提取器。
502
+
463
503
  Args:
464
504
  symbol_name: 符号名称
465
505
  file_path: 文件路径
466
506
  line: 行号(1-based)
467
507
  column: 列号(0-based)
468
- lsp_client: LSP 客户端(可选)
469
508
  treesitter_extractor: tree-sitter 提取器(可选)
470
509
  content: 文件内容
471
-
510
+
472
511
  Returns:
473
512
  定义位置的 Symbol 对象,如果找不到则返回 None
474
513
  """
475
- # 优先使用 LSP
476
- if lsp_client:
477
- try:
478
- # LSP 使用 0-based 行号
479
- definition = lsp_client.get_definition(file_path, line - 1, column)
480
- if definition:
481
- # 处理 LSP 返回的定义(可能是单个对象或列表)
482
- if isinstance(definition, list):
483
- if definition:
484
- definition = definition[0]
485
- else:
486
- return None
487
-
488
- # 解析 LSP 返回的定义位置
489
- uri = definition.get("uri", "")
490
- if uri.startswith("file://"):
491
- def_file_path = uri[7:] # 移除 "file://" 前缀
492
- else:
493
- def_file_path = uri
494
-
495
- range_info = definition.get("range", {})
496
- start = range_info.get("start", {})
497
- end = range_info.get("end", {})
498
-
499
- # LSP 使用 0-based 行号,转换为 1-based
500
- def_line_start = start.get("line", 0) + 1
501
- def_line_end = end.get("line", 0) + 1
502
-
503
- return Symbol(
504
- name=symbol_name,
505
- kind="", # LSP 可能不提供类型信息
506
- file_path=def_file_path,
507
- line_start=def_line_start,
508
- line_end=def_line_end,
509
- )
510
- except Exception:
511
- # LSP 失败,继续尝试 tree-sitter
512
- pass
513
-
514
- # 后备:使用 tree-sitter
514
+ # 使用 tree-sitter
515
515
  if treesitter_extractor:
516
516
  try:
517
517
  # 从符号表中查找定义(tree-sitter 已经提取了符号)
@@ -529,7 +529,7 @@ class ContextManager:
529
529
  )
530
530
  except Exception:
531
531
  pass
532
-
532
+
533
533
  return None
534
534
 
535
535
  def _find_imported_symbols(self, file_path: str) -> List[Symbol]:
@@ -537,78 +537,80 @@ class ContextManager:
537
537
  # Check if file is stale and update if needed
538
538
  if self.symbol_table.is_file_stale(file_path):
539
539
  self._refresh_file_symbols(file_path)
540
-
540
+
541
541
  symbols = self.symbol_table.get_file_symbols(file_path)
542
- return [s for s in symbols if s.kind == 'import']
542
+ return [s for s in symbols if s.kind == "import"]
543
543
 
544
544
  def _find_relevant_files(self, file_path: str) -> List[str]:
545
545
  """Find relevant files (dependencies and dependents)."""
546
546
  relevant = set()
547
-
547
+
548
548
  # Add dependencies
549
549
  deps = self.dependency_graph.get_dependencies(file_path)
550
550
  relevant.update(deps)
551
-
551
+
552
552
  # Add dependents
553
553
  dependents = self.dependency_graph.get_dependents(file_path)
554
554
  relevant.update(dependents)
555
-
555
+
556
556
  return list(relevant)
557
557
 
558
- def _resolve_dependency_path(self, file_path: str, module_name: str) -> Optional[str]:
558
+ def _resolve_dependency_path(
559
+ self, file_path: str, module_name: str
560
+ ) -> Optional[str]:
559
561
  """Resolve a module name to a file path."""
560
562
  # Handle relative imports
561
- if module_name.startswith('.'):
563
+ if module_name.startswith("."):
562
564
  # Relative import
563
565
  base_dir = os.path.dirname(file_path)
564
- parts = module_name.split('.')
565
- depth = len([p for p in parts if p == ''])
566
+ parts = module_name.split(".")
567
+ depth = len([p for p in parts if p == ""])
566
568
  module_parts = [p for p in parts if p]
567
-
569
+
568
570
  # Navigate up directories
569
571
  current_dir = base_dir
570
572
  for _ in range(depth - 1):
571
573
  current_dir = os.path.dirname(current_dir)
572
-
574
+
573
575
  # Try to find the module file
574
576
  if module_parts:
575
577
  module_path = os.path.join(current_dir, *module_parts)
576
578
  else:
577
579
  module_path = current_dir
578
-
580
+
579
581
  # Try common extensions
580
- for ext in ['.py', '.rs', '.go', '.js', '.ts']:
582
+ for ext in [".py", ".rs", ".go", ".js", ".ts"]:
581
583
  full_path = module_path + ext
582
584
  if os.path.exists(full_path):
583
585
  return full_path
584
-
586
+
585
587
  # Try __init__.py for Python packages
586
- if ext == '.py':
587
- init_path = os.path.join(module_path, '__init__.py')
588
+ if ext == ".py":
589
+ init_path = os.path.join(module_path, "__init__.py")
588
590
  if os.path.exists(init_path):
589
591
  return init_path
590
592
  else:
591
593
  # Absolute import - search in project
592
- parts = module_name.split('.')
594
+ parts = module_name.split(".")
593
595
  for root, dirs, files in os.walk(self.project_root):
594
596
  # Skip hidden directories and common ignore patterns
595
597
  dirs[:] = filter_walk_dirs(dirs)
596
-
598
+
597
599
  if parts[0] in dirs or f"{parts[0]}.py" in files:
598
600
  module_path = os.path.join(root, *parts)
599
-
601
+
600
602
  # Try common extensions
601
- for ext in ['.py', '.rs', '.go', '.js', '.ts']:
603
+ for ext in [".py", ".rs", ".go", ".js", ".ts"]:
602
604
  full_path = module_path + ext
603
605
  if os.path.exists(full_path):
604
606
  return full_path
605
-
607
+
606
608
  # Try __init__.py for Python packages
607
- if ext == '.py':
608
- init_path = os.path.join(module_path, '__init__.py')
609
+ if ext == ".py":
610
+ init_path = os.path.join(module_path, "__init__.py")
609
611
  if os.path.exists(init_path):
610
612
  return init_path
611
-
613
+
612
614
  return None
613
615
 
614
616
  def _build_context_summary(
@@ -620,29 +622,29 @@ class ContextManager:
620
622
  ) -> str:
621
623
  """Build a human-readable context summary."""
622
624
  parts = []
623
-
625
+
624
626
  if current_scope:
625
627
  parts.append(f"Current scope: {current_scope.kind} {current_scope.name}")
626
628
  if current_scope.signature:
627
629
  parts.append(f" Signature: {current_scope.signature}")
628
-
630
+
629
631
  if used_symbols:
630
632
  symbol_names = [s.name for s in used_symbols[:5]]
631
633
  parts.append(f"Used symbols: {', '.join(symbol_names)}")
632
634
  if len(used_symbols) > 5:
633
635
  parts.append(f" ... and {len(used_symbols) - 5} more")
634
-
636
+
635
637
  if imported_symbols:
636
638
  import_names = [s.name for s in imported_symbols[:5]]
637
639
  parts.append(f"Imported symbols: {', '.join(import_names)}")
638
640
  if len(imported_symbols) > 5:
639
641
  parts.append(f" ... and {len(imported_symbols) - 5} more")
640
-
642
+
641
643
  if relevant_files:
642
644
  parts.append(f"Relevant files: {len(relevant_files)} files")
643
645
  for f in relevant_files[:3]:
644
646
  parts.append(f" - {os.path.relpath(f, self.project_root)}")
645
647
  if len(relevant_files) > 3:
646
648
  parts.append(f" ... and {len(relevant_files) - 3} more")
647
-
648
- return '\n'.join(parts) if parts else "No context available"
649
+
650
+ return "\n".join(parts) if parts else "No context available"