jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +243 -139
- jarvis/jarvis_agent/agent_manager.py +5 -10
- jarvis/jarvis_agent/builtin_input_handler.py +2 -6
- jarvis/jarvis_agent/config_editor.py +2 -7
- jarvis/jarvis_agent/event_bus.py +82 -12
- jarvis/jarvis_agent/file_context_handler.py +265 -15
- jarvis/jarvis_agent/file_methodology_manager.py +3 -4
- jarvis/jarvis_agent/jarvis.py +113 -98
- jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
- jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
- jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
- jarvis/jarvis_agent/language_support_info.py +486 -0
- jarvis/jarvis_agent/main.py +6 -12
- jarvis/jarvis_agent/memory_manager.py +7 -16
- jarvis/jarvis_agent/methodology_share_manager.py +10 -16
- jarvis/jarvis_agent/prompt_manager.py +1 -1
- jarvis/jarvis_agent/prompts.py +193 -171
- jarvis/jarvis_agent/protocols.py +8 -12
- jarvis/jarvis_agent/run_loop.py +77 -14
- jarvis/jarvis_agent/session_manager.py +2 -3
- jarvis/jarvis_agent/share_manager.py +12 -21
- jarvis/jarvis_agent/shell_input_handler.py +1 -2
- jarvis/jarvis_agent/task_analyzer.py +26 -4
- jarvis/jarvis_agent/task_manager.py +11 -27
- jarvis/jarvis_agent/tool_executor.py +2 -3
- jarvis/jarvis_agent/tool_share_manager.py +12 -24
- jarvis/jarvis_agent/web_server.py +55 -20
- jarvis/jarvis_c2rust/__init__.py +5 -5
- jarvis/jarvis_c2rust/cli.py +461 -499
- jarvis/jarvis_c2rust/collector.py +45 -53
- jarvis/jarvis_c2rust/constants.py +26 -0
- jarvis/jarvis_c2rust/library_replacer.py +264 -132
- jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
- jarvis/jarvis_c2rust/loaders.py +207 -0
- jarvis/jarvis_c2rust/models.py +28 -0
- jarvis/jarvis_c2rust/optimizer.py +1592 -395
- jarvis/jarvis_c2rust/transpiler.py +1722 -1064
- jarvis/jarvis_c2rust/utils.py +385 -0
- jarvis/jarvis_code_agent/build_validation_config.py +2 -3
- jarvis/jarvis_code_agent/code_agent.py +394 -320
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
- jarvis/jarvis_code_agent/lint.py +258 -27
- jarvis/jarvis_code_agent/utils.py +0 -1
- jarvis/jarvis_code_analysis/code_review.py +19 -24
- jarvis/jarvis_data/config_schema.json +53 -26
- jarvis/jarvis_git_squash/main.py +4 -5
- jarvis/jarvis_git_utils/git_commiter.py +44 -49
- jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
- jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
- jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
- jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
- jarvis/jarvis_methodology/main.py +32 -48
- jarvis/jarvis_multi_agent/__init__.py +79 -61
- jarvis/jarvis_multi_agent/main.py +3 -7
- jarvis/jarvis_platform/base.py +469 -199
- jarvis/jarvis_platform/human.py +7 -8
- jarvis/jarvis_platform/kimi.py +30 -36
- jarvis/jarvis_platform/openai.py +65 -27
- jarvis/jarvis_platform/registry.py +26 -10
- jarvis/jarvis_platform/tongyi.py +24 -25
- jarvis/jarvis_platform/yuanbao.py +31 -42
- jarvis/jarvis_platform_manager/main.py +66 -77
- jarvis/jarvis_platform_manager/service.py +8 -13
- jarvis/jarvis_rag/cli.py +49 -51
- jarvis/jarvis_rag/embedding_manager.py +13 -18
- jarvis/jarvis_rag/llm_interface.py +8 -9
- jarvis/jarvis_rag/query_rewriter.py +10 -21
- jarvis/jarvis_rag/rag_pipeline.py +24 -27
- jarvis/jarvis_rag/reranker.py +4 -5
- jarvis/jarvis_rag/retriever.py +28 -30
- jarvis/jarvis_sec/__init__.py +220 -3520
- jarvis/jarvis_sec/agents.py +143 -0
- jarvis/jarvis_sec/analysis.py +276 -0
- jarvis/jarvis_sec/cli.py +29 -6
- jarvis/jarvis_sec/clustering.py +1439 -0
- jarvis/jarvis_sec/file_manager.py +427 -0
- jarvis/jarvis_sec/parsers.py +73 -0
- jarvis/jarvis_sec/prompts.py +268 -0
- jarvis/jarvis_sec/report.py +83 -4
- jarvis/jarvis_sec/review.py +453 -0
- jarvis/jarvis_sec/utils.py +499 -0
- jarvis/jarvis_sec/verification.py +848 -0
- jarvis/jarvis_sec/workflow.py +7 -0
- jarvis/jarvis_smart_shell/main.py +38 -87
- jarvis/jarvis_stats/cli.py +1 -1
- jarvis/jarvis_stats/stats.py +7 -7
- jarvis/jarvis_stats/storage.py +15 -21
- jarvis/jarvis_tools/clear_memory.py +3 -20
- jarvis/jarvis_tools/cli/main.py +20 -23
- jarvis/jarvis_tools/edit_file.py +1066 -0
- jarvis/jarvis_tools/execute_script.py +42 -21
- jarvis/jarvis_tools/file_analyzer.py +6 -9
- jarvis/jarvis_tools/generate_new_tool.py +11 -20
- jarvis/jarvis_tools/lsp_client.py +1552 -0
- jarvis/jarvis_tools/methodology.py +2 -3
- jarvis/jarvis_tools/read_code.py +1525 -87
- jarvis/jarvis_tools/read_symbols.py +2 -3
- jarvis/jarvis_tools/read_webpage.py +7 -10
- jarvis/jarvis_tools/registry.py +370 -181
- jarvis/jarvis_tools/retrieve_memory.py +20 -19
- jarvis/jarvis_tools/rewrite_file.py +105 -0
- jarvis/jarvis_tools/save_memory.py +3 -15
- jarvis/jarvis_tools/search_web.py +3 -7
- jarvis/jarvis_tools/sub_agent.py +17 -6
- jarvis/jarvis_tools/sub_code_agent.py +14 -16
- jarvis/jarvis_tools/virtual_tty.py +54 -32
- jarvis/jarvis_utils/clipboard.py +7 -10
- jarvis/jarvis_utils/config.py +98 -63
- jarvis/jarvis_utils/embedding.py +5 -5
- jarvis/jarvis_utils/fzf.py +8 -8
- jarvis/jarvis_utils/git_utils.py +81 -67
- jarvis/jarvis_utils/input.py +24 -49
- jarvis/jarvis_utils/jsonnet_compat.py +465 -0
- jarvis/jarvis_utils/methodology.py +33 -35
- jarvis/jarvis_utils/utils.py +245 -202
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
- jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
- jarvis/jarvis_agent/edit_file_handler.py +0 -584
- jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
- jarvis/jarvis_agent/task_planner.py +0 -496
- jarvis/jarvis_platform/ai8.py +0 -332
- jarvis/jarvis_tools/ask_user.py +0 -54
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -1,34 +1,155 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
1
3
|
from dataclasses import dataclass
|
|
2
|
-
|
|
3
4
|
from typing import Dict, List, Optional
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
@dataclass
|
|
7
8
|
class Symbol:
|
|
8
|
-
"""
|
|
9
|
+
"""表示代码中的单个符号。"""
|
|
9
10
|
name: str
|
|
10
|
-
kind: str #
|
|
11
|
+
kind: str # 例如:'function'(函数)、'class'(类)、'variable'(变量)、'import'(导入)
|
|
11
12
|
file_path: str
|
|
12
13
|
line_start: int
|
|
13
14
|
line_end: int
|
|
14
15
|
signature: Optional[str] = None
|
|
15
16
|
docstring: Optional[str] = None
|
|
16
|
-
#
|
|
17
|
+
# 根据需要添加更多字段,例如父作用域
|
|
17
18
|
parent: Optional[str] = None
|
|
19
|
+
# 定义位置(对于引用/调用,指向符号定义的位置)
|
|
20
|
+
definition_location: Optional['Symbol'] = None # 指向定义Symbol的引用
|
|
21
|
+
is_definition: bool = False # 如果此符号是定义则为True,如果是引用/调用则为False
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
class SymbolTable:
|
|
21
|
-
"""
|
|
25
|
+
"""存储并提供对项目中符号的访问。"""
|
|
22
26
|
|
|
23
|
-
def __init__(self):
|
|
24
|
-
#
|
|
25
|
-
#
|
|
27
|
+
def __init__(self, cache_dir: Optional[str] = None):
|
|
28
|
+
# 按名称存储符号的字典,用于快速查找
|
|
29
|
+
# 一个符号名可能出现在多个文件中,因此使用列表存储
|
|
26
30
|
self.symbols_by_name: Dict[str, List[Symbol]] = {}
|
|
27
|
-
#
|
|
31
|
+
# 按文件存储符号的字典
|
|
28
32
|
self.symbols_by_file: Dict[str, List[Symbol]] = {}
|
|
33
|
+
# 跟踪文件修改时间用于缓存失效
|
|
34
|
+
self._file_mtimes: Dict[str, float] = {}
|
|
35
|
+
# 持久化存储的缓存目录
|
|
36
|
+
self.cache_dir = cache_dir or ".jarvis/symbol_cache"
|
|
37
|
+
# 如果可用则加载缓存数据
|
|
38
|
+
self._load_from_cache()
|
|
39
|
+
|
|
40
|
+
def _get_cache_file(self) -> str:
|
|
41
|
+
"""获取缓存文件路径。"""
|
|
42
|
+
return os.path.join(self.cache_dir, "symbol_table.json")
|
|
43
|
+
|
|
44
|
+
def _load_from_cache(self):
|
|
45
|
+
"""从缓存文件加载符号表数据。"""
|
|
46
|
+
cache_file = self._get_cache_file()
|
|
47
|
+
if os.path.exists(cache_file):
|
|
48
|
+
try:
|
|
49
|
+
with open(cache_file, 'r', encoding='utf-8') as f:
|
|
50
|
+
data = json.load(f)
|
|
51
|
+
# 将JSON数据转换回Symbol对象
|
|
52
|
+
self.symbols_by_name = self._deserialize_symbols(data.get('symbols_by_name', {}))
|
|
53
|
+
self.symbols_by_file = self._deserialize_symbols(data.get('symbols_by_file', {}))
|
|
54
|
+
# 加载文件修改时间
|
|
55
|
+
self._file_mtimes = data.get('file_mtimes', {})
|
|
56
|
+
except Exception:
|
|
57
|
+
# 如果缓存加载失败,则从空表开始
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
def _save_to_cache(self):
|
|
61
|
+
"""将符号表数据保存到缓存文件。"""
|
|
62
|
+
try:
|
|
63
|
+
# 确保缓存目录存在
|
|
64
|
+
os.makedirs(self.cache_dir, exist_ok=True)
|
|
65
|
+
cache_file = self._get_cache_file()
|
|
66
|
+
|
|
67
|
+
# 保存前更新文件修改时间
|
|
68
|
+
self._update_file_mtimes()
|
|
69
|
+
|
|
70
|
+
# 序列化符号以便JSON存储
|
|
71
|
+
data = {
|
|
72
|
+
'symbols_by_name': self._serialize_symbols(self.symbols_by_name),
|
|
73
|
+
'symbols_by_file': self._serialize_symbols(self.symbols_by_file),
|
|
74
|
+
'file_mtimes': self._file_mtimes
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
with open(cache_file, 'w', encoding='utf-8') as f:
|
|
78
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
79
|
+
except Exception:
|
|
80
|
+
# 如果缓存保存失败,则继续而不缓存
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
def _serialize_symbols(self, symbol_dict: Dict[str, List[Symbol]]) -> Dict[str, List[dict]]:
|
|
84
|
+
"""将Symbol对象转换为可序列化的字典。"""
|
|
85
|
+
serialized = {}
|
|
86
|
+
for key, symbols in symbol_dict.items():
|
|
87
|
+
serialized[key] = [self._symbol_to_dict(symbol) for symbol in symbols]
|
|
88
|
+
return serialized
|
|
29
89
|
|
|
30
|
-
def
|
|
31
|
-
"""
|
|
90
|
+
def _deserialize_symbols(self, symbol_dict: Dict[str, List[dict]]) -> Dict[str, List[Symbol]]:
|
|
91
|
+
"""将序列化的字典转换回Symbol对象。"""
|
|
92
|
+
deserialized = {}
|
|
93
|
+
for key, symbol_data_list in symbol_dict.items():
|
|
94
|
+
deserialized[key] = [self._dict_to_symbol(data) for data in symbol_data_list]
|
|
95
|
+
return deserialized
|
|
96
|
+
|
|
97
|
+
def _symbol_to_dict(self, symbol: Symbol) -> dict:
|
|
98
|
+
"""将Symbol对象转换为字典。"""
|
|
99
|
+
result = {
|
|
100
|
+
'name': symbol.name,
|
|
101
|
+
'kind': symbol.kind,
|
|
102
|
+
'file_path': symbol.file_path,
|
|
103
|
+
'line_start': symbol.line_start,
|
|
104
|
+
'line_end': symbol.line_end,
|
|
105
|
+
'signature': symbol.signature,
|
|
106
|
+
'docstring': symbol.docstring,
|
|
107
|
+
'parent': symbol.parent,
|
|
108
|
+
'is_definition': getattr(symbol, 'is_definition', False),
|
|
109
|
+
}
|
|
110
|
+
# 序列化定义位置(只保存基本信息,避免循环引用)
|
|
111
|
+
if hasattr(symbol, 'definition_location') and symbol.definition_location:
|
|
112
|
+
result['definition_location'] = {
|
|
113
|
+
'file_path': symbol.definition_location.file_path,
|
|
114
|
+
'line_start': symbol.definition_location.line_start,
|
|
115
|
+
'line_end': symbol.definition_location.line_end,
|
|
116
|
+
'name': symbol.definition_location.name,
|
|
117
|
+
}
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
def _dict_to_symbol(self, data: dict) -> Symbol:
|
|
121
|
+
"""将字典转换回Symbol对象。"""
|
|
122
|
+
symbol = Symbol(
|
|
123
|
+
name=data['name'],
|
|
124
|
+
kind=data['kind'],
|
|
125
|
+
file_path=data['file_path'],
|
|
126
|
+
line_start=data['line_start'],
|
|
127
|
+
line_end=data['line_end'],
|
|
128
|
+
signature=data.get('signature'),
|
|
129
|
+
docstring=data.get('docstring'),
|
|
130
|
+
parent=data.get('parent'),
|
|
131
|
+
is_definition=data.get('is_definition', False),
|
|
132
|
+
)
|
|
133
|
+
# 恢复定义位置(创建临时 Symbol 对象)
|
|
134
|
+
if 'definition_location' in data and data['definition_location']:
|
|
135
|
+
def_loc = data['definition_location']
|
|
136
|
+
symbol.definition_location = Symbol(
|
|
137
|
+
name=def_loc['name'],
|
|
138
|
+
kind='', # 未知类型
|
|
139
|
+
file_path=def_loc['file_path'],
|
|
140
|
+
line_start=def_loc['line_start'],
|
|
141
|
+
line_end=def_loc['line_end'],
|
|
142
|
+
)
|
|
143
|
+
return symbol
|
|
144
|
+
|
|
145
|
+
def add_symbol(self, symbol: Symbol, save_to_cache: bool = False):
|
|
146
|
+
"""向表中添加符号。
|
|
147
|
+
|
|
148
|
+
参数:
|
|
149
|
+
symbol: 要添加的符号
|
|
150
|
+
save_to_cache: 如果为True,立即保存到缓存。默认为False以提高性能。
|
|
151
|
+
批量操作后使用save_cache()一次性保存所有符号。
|
|
152
|
+
"""
|
|
32
153
|
if symbol.name not in self.symbols_by_name:
|
|
33
154
|
self.symbols_by_name[symbol.name] = []
|
|
34
155
|
self.symbols_by_name[symbol.name].append(symbol)
|
|
@@ -36,11 +157,19 @@ class SymbolTable:
|
|
|
36
157
|
if symbol.file_path not in self.symbols_by_file:
|
|
37
158
|
self.symbols_by_file[symbol.file_path] = []
|
|
38
159
|
self.symbols_by_file[symbol.file_path].append(symbol)
|
|
160
|
+
|
|
161
|
+
# 仅在明确请求时保存到缓存(出于性能考虑)
|
|
162
|
+
if save_to_cache:
|
|
163
|
+
self._save_to_cache()
|
|
164
|
+
|
|
165
|
+
def save_cache(self):
|
|
166
|
+
"""将整个符号表保存到缓存。批量操作后调用此方法。"""
|
|
167
|
+
self._save_to_cache()
|
|
39
168
|
|
|
40
169
|
def find_symbol(self, name: str, file_path: Optional[str] = None) -> List[Symbol]:
|
|
41
170
|
"""
|
|
42
|
-
|
|
43
|
-
|
|
171
|
+
通过名称查找符号。
|
|
172
|
+
如果提供了file_path,则搜索仅限于该文件。
|
|
44
173
|
"""
|
|
45
174
|
if file_path:
|
|
46
175
|
return [
|
|
@@ -49,11 +178,11 @@ class SymbolTable:
|
|
|
49
178
|
return self.symbols_by_name.get(name, [])
|
|
50
179
|
|
|
51
180
|
def get_file_symbols(self, file_path: str) -> List[Symbol]:
|
|
52
|
-
"""
|
|
181
|
+
"""获取特定文件中的所有符号。"""
|
|
53
182
|
return self.symbols_by_file.get(file_path, [])
|
|
54
183
|
|
|
55
184
|
def clear_file_symbols(self, file_path: str):
|
|
56
|
-
"""
|
|
185
|
+
"""移除与特定文件关联的所有符号。"""
|
|
57
186
|
if file_path in self.symbols_by_file:
|
|
58
187
|
symbols_to_remove = self.symbols_by_file.pop(file_path)
|
|
59
188
|
for symbol in symbols_to_remove:
|
|
@@ -64,14 +193,60 @@ class SymbolTable:
|
|
|
64
193
|
]
|
|
65
194
|
if not self.symbols_by_name[symbol.name]:
|
|
66
195
|
del self.symbols_by_name[symbol.name]
|
|
196
|
+
|
|
197
|
+
# 移除文件修改时间跟踪
|
|
198
|
+
if file_path in self._file_mtimes:
|
|
199
|
+
del self._file_mtimes[file_path]
|
|
200
|
+
|
|
201
|
+
# 清除后保存到缓存
|
|
202
|
+
self._save_to_cache()
|
|
203
|
+
|
|
204
|
+
def _update_file_mtimes(self):
|
|
205
|
+
"""更新所有跟踪文件的修改时间。"""
|
|
206
|
+
for file_path in list(self.symbols_by_file.keys()):
|
|
207
|
+
if os.path.exists(file_path):
|
|
208
|
+
try:
|
|
209
|
+
self._file_mtimes[file_path] = os.path.getmtime(file_path)
|
|
210
|
+
except Exception:
|
|
211
|
+
# 如果无法获取修改时间,则从跟踪中移除
|
|
212
|
+
self._file_mtimes.pop(file_path, None)
|
|
213
|
+
|
|
214
|
+
def is_file_stale(self, file_path: str) -> bool:
|
|
215
|
+
"""检查文件自缓存后是否已被修改。
|
|
216
|
+
|
|
217
|
+
参数:
|
|
218
|
+
file_path: 要检查的文件路径
|
|
219
|
+
|
|
220
|
+
返回:
|
|
221
|
+
如果文件比缓存新则为True,否则为False
|
|
222
|
+
"""
|
|
223
|
+
if file_path not in self.symbols_by_file:
|
|
224
|
+
# 文件不在缓存中,视为已过期(需要加载)
|
|
225
|
+
return True
|
|
226
|
+
|
|
227
|
+
if file_path not in self._file_mtimes:
|
|
228
|
+
# 没有记录修改时间,视为已过期
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
if not os.path.exists(file_path):
|
|
232
|
+
# 文件不存在,不算过期(将由clear_file_symbols处理)
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
current_mtime = os.path.getmtime(file_path)
|
|
237
|
+
cached_mtime = self._file_mtimes.get(file_path, 0)
|
|
238
|
+
return current_mtime > cached_mtime
|
|
239
|
+
except Exception:
|
|
240
|
+
# 如果无法获取修改时间,则假定未过期
|
|
241
|
+
return False
|
|
67
242
|
|
|
68
243
|
|
|
69
244
|
class SymbolExtractor:
|
|
70
|
-
"""
|
|
245
|
+
"""从源代码文件中提取符号。"""
|
|
71
246
|
|
|
72
247
|
def extract_symbols(self, file_path: str, content: str) -> List[Symbol]:
|
|
73
248
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
249
|
+
从代码中提取符号(函数、类、变量等)。
|
|
250
|
+
此方法应由特定语言的子类实现。
|
|
76
251
|
"""
|
|
77
252
|
raise NotImplementedError("Subclasses must implement this method.")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
from typing import List, Optional
|
|
3
3
|
|
|
4
|
-
from tree_sitter import Language, Parser, Node
|
|
4
|
+
from tree_sitter import Language, Parser, Node, Query, QueryCursor
|
|
5
5
|
|
|
6
6
|
from .symbol_extractor import Symbol, SymbolExtractor
|
|
7
7
|
|
|
@@ -14,9 +14,13 @@ class TreeSitterExtractor(SymbolExtractor):
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
def __init__(self, language: Language, symbol_query: str):
|
|
17
|
+
# 如果传入的是 PyCapsule,需要转换为 Language 对象
|
|
18
|
+
if not isinstance(language, Language):
|
|
19
|
+
language = Language(language)
|
|
17
20
|
self.language = language
|
|
18
21
|
self.parser = Parser()
|
|
19
|
-
|
|
22
|
+
# 使用 language 属性而不是 set_language 方法
|
|
23
|
+
self.parser.language = self.language
|
|
20
24
|
self.symbol_query = symbol_query
|
|
21
25
|
|
|
22
26
|
def extract_symbols(self, file_path: str, content: str) -> List[Symbol]:
|
|
@@ -25,14 +29,20 @@ class TreeSitterExtractor(SymbolExtractor):
|
|
|
25
29
|
"""
|
|
26
30
|
try:
|
|
27
31
|
tree = self.parser.parse(bytes(content, "utf8"))
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
# 使用 Query 构造函数(新 API)
|
|
33
|
+
query = Query(self.language, self.symbol_query)
|
|
34
|
+
# 使用 QueryCursor 执行查询
|
|
35
|
+
cursor = QueryCursor(query)
|
|
36
|
+
matches = cursor.matches(tree.root_node)
|
|
30
37
|
|
|
31
38
|
symbols = []
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
# matches 返回格式: [(pattern_index, {capture_name: [nodes]})]
|
|
40
|
+
for pattern_index, captures_dict in matches:
|
|
41
|
+
for capture_name, nodes in captures_dict.items():
|
|
42
|
+
for node in nodes:
|
|
43
|
+
symbol = self._create_symbol_from_capture(node, capture_name, file_path)
|
|
44
|
+
if symbol:
|
|
45
|
+
symbols.append(symbol)
|
|
36
46
|
return symbols
|
|
37
47
|
except Exception as e:
|
|
38
48
|
print(f"Error extracting symbols from {file_path} with tree-sitter: {e}")
|