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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +567 -222
- jarvis/jarvis_agent/agent_manager.py +19 -12
- jarvis/jarvis_agent/builtin_input_handler.py +79 -11
- jarvis/jarvis_agent/config_editor.py +7 -2
- jarvis/jarvis_agent/event_bus.py +24 -13
- jarvis/jarvis_agent/events.py +19 -1
- jarvis/jarvis_agent/file_context_handler.py +67 -64
- jarvis/jarvis_agent/file_methodology_manager.py +38 -24
- jarvis/jarvis_agent/jarvis.py +186 -114
- jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
- jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
- jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
- jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
- jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
- jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
- jarvis/jarvis_agent/language_support_info.py +250 -219
- jarvis/jarvis_agent/main.py +19 -23
- jarvis/jarvis_agent/memory_manager.py +9 -6
- jarvis/jarvis_agent/methodology_share_manager.py +21 -15
- jarvis/jarvis_agent/output_handler.py +4 -2
- jarvis/jarvis_agent/prompt_builder.py +7 -6
- jarvis/jarvis_agent/prompt_manager.py +113 -8
- jarvis/jarvis_agent/prompts.py +317 -85
- jarvis/jarvis_agent/protocols.py +5 -2
- jarvis/jarvis_agent/run_loop.py +192 -32
- jarvis/jarvis_agent/session_manager.py +7 -3
- jarvis/jarvis_agent/share_manager.py +23 -13
- jarvis/jarvis_agent/shell_input_handler.py +12 -8
- jarvis/jarvis_agent/stdio_redirect.py +25 -26
- jarvis/jarvis_agent/task_analyzer.py +29 -23
- jarvis/jarvis_agent/task_list.py +869 -0
- jarvis/jarvis_agent/task_manager.py +26 -23
- jarvis/jarvis_agent/tool_executor.py +6 -5
- jarvis/jarvis_agent/tool_share_manager.py +24 -14
- jarvis/jarvis_agent/user_interaction.py +3 -3
- jarvis/jarvis_agent/utils.py +9 -1
- jarvis/jarvis_agent/web_bridge.py +37 -17
- jarvis/jarvis_agent/web_output_sink.py +5 -2
- jarvis/jarvis_agent/web_server.py +165 -36
- jarvis/jarvis_c2rust/__init__.py +1 -1
- jarvis/jarvis_c2rust/cli.py +260 -141
- jarvis/jarvis_c2rust/collector.py +37 -18
- jarvis/jarvis_c2rust/constants.py +60 -0
- jarvis/jarvis_c2rust/library_replacer.py +242 -1010
- jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
- jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
- jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
- jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
- jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
- jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
- jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
- jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
- jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
- jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
- jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
- jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
- jarvis/jarvis_c2rust/loaders.py +28 -10
- jarvis/jarvis_c2rust/models.py +5 -2
- jarvis/jarvis_c2rust/optimizer.py +192 -1974
- jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
- jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
- jarvis/jarvis_c2rust/optimizer_config.py +49 -0
- jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
- jarvis/jarvis_c2rust/optimizer_options.py +48 -0
- jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
- jarvis/jarvis_c2rust/optimizer_report.py +52 -0
- jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
- jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
- jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
- jarvis/jarvis_c2rust/scanner.py +229 -166
- jarvis/jarvis_c2rust/transpiler.py +531 -2732
- jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
- jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
- jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
- jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
- jarvis/jarvis_c2rust/transpiler_config.py +178 -0
- jarvis/jarvis_c2rust/transpiler_context.py +122 -0
- jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
- jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
- jarvis/jarvis_c2rust/transpiler_git.py +163 -0
- jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
- jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
- jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
- jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
- jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
- jarvis/jarvis_c2rust/utils.py +269 -79
- jarvis/jarvis_code_agent/after_change.py +233 -0
- jarvis/jarvis_code_agent/build_validation_config.py +37 -30
- jarvis/jarvis_code_agent/builtin_rules.py +68 -0
- jarvis/jarvis_code_agent/code_agent.py +976 -1517
- jarvis/jarvis_code_agent/code_agent_build.py +227 -0
- jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
- jarvis/jarvis_code_agent/code_agent_git.py +525 -0
- jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
- jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
- jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
- jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
- jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
- jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
- jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
- jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
- jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
- jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
- jarvis/jarvis_code_agent/lint.py +223 -524
- jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
- jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
- jarvis/jarvis_code_agent/rules/code_review.md +115 -0
- jarvis/jarvis_code_agent/rules/documentation.md +165 -0
- jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
- jarvis/jarvis_code_agent/rules/performance.md +158 -0
- jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
- jarvis/jarvis_code_agent/rules/security.md +160 -0
- jarvis/jarvis_code_agent/rules/tdd.md +78 -0
- jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
- jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
- jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
- jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
- jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
- jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
- jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
- jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
- jarvis/jarvis_code_agent/utils.py +36 -26
- jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
- jarvis/jarvis_code_analysis/code_review.py +64 -33
- jarvis/jarvis_data/config_schema.json +285 -192
- jarvis/jarvis_git_squash/main.py +8 -6
- jarvis/jarvis_git_utils/git_commiter.py +53 -76
- jarvis/jarvis_mcp/__init__.py +5 -2
- jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
- jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
- jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
- jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
- jarvis/jarvis_methodology/main.py +48 -39
- jarvis/jarvis_multi_agent/__init__.py +56 -23
- jarvis/jarvis_multi_agent/main.py +15 -18
- jarvis/jarvis_platform/base.py +179 -111
- jarvis/jarvis_platform/human.py +27 -16
- jarvis/jarvis_platform/kimi.py +52 -45
- jarvis/jarvis_platform/openai.py +101 -40
- jarvis/jarvis_platform/registry.py +51 -33
- jarvis/jarvis_platform/tongyi.py +68 -38
- jarvis/jarvis_platform/yuanbao.py +59 -43
- jarvis/jarvis_platform_manager/main.py +68 -76
- jarvis/jarvis_platform_manager/service.py +24 -14
- jarvis/jarvis_rag/README_CONFIG.md +314 -0
- jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
- jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
- jarvis/jarvis_rag/__init__.py +57 -4
- jarvis/jarvis_rag/cache.py +3 -1
- jarvis/jarvis_rag/cli.py +48 -68
- jarvis/jarvis_rag/embedding_interface.py +39 -0
- jarvis/jarvis_rag/embedding_manager.py +7 -230
- jarvis/jarvis_rag/embeddings/__init__.py +41 -0
- jarvis/jarvis_rag/embeddings/base.py +114 -0
- jarvis/jarvis_rag/embeddings/cohere.py +66 -0
- jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
- jarvis/jarvis_rag/embeddings/local.py +260 -0
- jarvis/jarvis_rag/embeddings/openai.py +62 -0
- jarvis/jarvis_rag/embeddings/registry.py +293 -0
- jarvis/jarvis_rag/llm_interface.py +8 -6
- jarvis/jarvis_rag/query_rewriter.py +8 -9
- jarvis/jarvis_rag/rag_pipeline.py +61 -52
- jarvis/jarvis_rag/reranker.py +7 -75
- jarvis/jarvis_rag/reranker_interface.py +32 -0
- jarvis/jarvis_rag/rerankers/__init__.py +41 -0
- jarvis/jarvis_rag/rerankers/base.py +109 -0
- jarvis/jarvis_rag/rerankers/cohere.py +67 -0
- jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
- jarvis/jarvis_rag/rerankers/jina.py +79 -0
- jarvis/jarvis_rag/rerankers/local.py +89 -0
- jarvis/jarvis_rag/rerankers/registry.py +293 -0
- jarvis/jarvis_rag/retriever.py +58 -43
- jarvis/jarvis_sec/__init__.py +66 -141
- jarvis/jarvis_sec/agents.py +21 -17
- jarvis/jarvis_sec/analysis.py +80 -33
- jarvis/jarvis_sec/checkers/__init__.py +7 -13
- jarvis/jarvis_sec/checkers/c_checker.py +356 -164
- jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
- jarvis/jarvis_sec/cli.py +43 -21
- jarvis/jarvis_sec/clustering.py +430 -272
- jarvis/jarvis_sec/file_manager.py +99 -55
- jarvis/jarvis_sec/parsers.py +9 -6
- jarvis/jarvis_sec/prompts.py +4 -3
- jarvis/jarvis_sec/report.py +44 -22
- jarvis/jarvis_sec/review.py +180 -107
- jarvis/jarvis_sec/status.py +50 -41
- jarvis/jarvis_sec/types.py +3 -0
- jarvis/jarvis_sec/utils.py +160 -83
- jarvis/jarvis_sec/verification.py +411 -181
- jarvis/jarvis_sec/workflow.py +132 -21
- jarvis/jarvis_smart_shell/main.py +28 -41
- jarvis/jarvis_stats/cli.py +14 -12
- jarvis/jarvis_stats/stats.py +28 -19
- jarvis/jarvis_stats/storage.py +14 -8
- jarvis/jarvis_stats/visualizer.py +12 -7
- jarvis/jarvis_tools/base.py +5 -2
- jarvis/jarvis_tools/clear_memory.py +13 -9
- jarvis/jarvis_tools/cli/main.py +23 -18
- jarvis/jarvis_tools/edit_file.py +572 -873
- jarvis/jarvis_tools/execute_script.py +10 -7
- jarvis/jarvis_tools/file_analyzer.py +7 -8
- jarvis/jarvis_tools/meta_agent.py +287 -0
- jarvis/jarvis_tools/methodology.py +5 -3
- jarvis/jarvis_tools/read_code.py +305 -1438
- jarvis/jarvis_tools/read_symbols.py +50 -17
- jarvis/jarvis_tools/read_webpage.py +19 -18
- jarvis/jarvis_tools/registry.py +435 -156
- jarvis/jarvis_tools/retrieve_memory.py +16 -11
- jarvis/jarvis_tools/save_memory.py +8 -6
- jarvis/jarvis_tools/search_web.py +31 -31
- jarvis/jarvis_tools/sub_agent.py +32 -28
- jarvis/jarvis_tools/sub_code_agent.py +44 -60
- jarvis/jarvis_tools/task_list_manager.py +1811 -0
- jarvis/jarvis_tools/virtual_tty.py +29 -19
- jarvis/jarvis_utils/__init__.py +4 -0
- jarvis/jarvis_utils/builtin_replace_map.py +2 -1
- jarvis/jarvis_utils/clipboard.py +9 -8
- jarvis/jarvis_utils/collections.py +331 -0
- jarvis/jarvis_utils/config.py +699 -194
- jarvis/jarvis_utils/dialogue_recorder.py +294 -0
- jarvis/jarvis_utils/embedding.py +6 -3
- jarvis/jarvis_utils/file_processors.py +7 -1
- jarvis/jarvis_utils/fzf.py +9 -3
- jarvis/jarvis_utils/git_utils.py +71 -42
- jarvis/jarvis_utils/globals.py +116 -32
- jarvis/jarvis_utils/http.py +6 -2
- jarvis/jarvis_utils/input.py +318 -83
- jarvis/jarvis_utils/jsonnet_compat.py +119 -104
- jarvis/jarvis_utils/methodology.py +37 -28
- jarvis/jarvis_utils/output.py +201 -44
- jarvis/jarvis_utils/utils.py +986 -628
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
- jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
- jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
- jarvis/jarvis_tools/generate_new_tool.py +0 -205
- jarvis/jarvis_tools/lsp_client.py +0 -1552
- jarvis/jarvis_tools/rewrite_file.py +0 -105
- jarvis_ai_assistant-0.7.8.dist-info/RECORD +0 -218
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.7.8.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {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
|
|
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
|
|
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
|
|
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
|
|
18
|
+
from ..symbol_extractor import Symbol
|
|
19
|
+
from ..symbol_extractor import SymbolExtractor
|
|
13
20
|
from ..tree_sitter_extractor import TreeSitterExtractor
|
|
14
21
|
|
|
15
|
-
|
|
16
22
|
# --- Go Symbol Query ---
|
|
17
23
|
|
|
18
24
|
GO_SYMBOL_QUERY = """
|
|
@@ -42,13 +48,17 @@ GO_SYMBOL_QUERY = """
|
|
|
42
48
|
|
|
43
49
|
try:
|
|
44
50
|
import tree_sitter_go
|
|
45
|
-
|
|
51
|
+
|
|
52
|
+
GO_LANGUAGE: Optional[Language] = cast(
|
|
53
|
+
Optional[Language], tree_sitter_go.language()
|
|
54
|
+
)
|
|
46
55
|
except (ImportError, Exception):
|
|
47
56
|
GO_LANGUAGE = None
|
|
48
57
|
|
|
49
58
|
|
|
50
59
|
# --- Go Symbol Extractor ---
|
|
51
60
|
|
|
61
|
+
|
|
52
62
|
class GoSymbolExtractor(TreeSitterExtractor):
|
|
53
63
|
"""Extracts symbols from Go code using tree-sitter."""
|
|
54
64
|
|
|
@@ -57,7 +67,9 @@ class GoSymbolExtractor(TreeSitterExtractor):
|
|
|
57
67
|
raise RuntimeError("Go tree-sitter grammar not available.")
|
|
58
68
|
super().__init__(GO_LANGUAGE, GO_SYMBOL_QUERY)
|
|
59
69
|
|
|
60
|
-
def _create_symbol_from_capture(
|
|
70
|
+
def _create_symbol_from_capture(
|
|
71
|
+
self, node: Node, name: str, file_path: str
|
|
72
|
+
) -> Optional[Symbol]:
|
|
61
73
|
"""Maps a tree-sitter capture to a Symbol object."""
|
|
62
74
|
kind_map = {
|
|
63
75
|
"function.name": "function",
|
|
@@ -68,7 +80,7 @@ class GoSymbolExtractor(TreeSitterExtractor):
|
|
|
68
80
|
"var": "var",
|
|
69
81
|
"struct": "struct",
|
|
70
82
|
}
|
|
71
|
-
|
|
83
|
+
|
|
72
84
|
symbol_kind = kind_map.get(name)
|
|
73
85
|
if not symbol_kind:
|
|
74
86
|
return None
|
|
@@ -76,23 +88,27 @@ class GoSymbolExtractor(TreeSitterExtractor):
|
|
|
76
88
|
# For const/var/struct, extract the first identifier as name
|
|
77
89
|
if symbol_kind in ("const", "var", "struct"):
|
|
78
90
|
# Try to find the first identifier in the declaration
|
|
79
|
-
|
|
91
|
+
if node.text is None:
|
|
92
|
+
return None
|
|
93
|
+
node_text = node.text.decode("utf8").strip()
|
|
80
94
|
# Extract first identifier after const/var/struct keyword
|
|
81
95
|
if symbol_kind == "const":
|
|
82
|
-
match = re.search(r
|
|
96
|
+
match = re.search(r"const\s+(\w+)", node_text)
|
|
83
97
|
elif symbol_kind == "var":
|
|
84
|
-
match = re.search(r
|
|
98
|
+
match = re.search(r"var\s+(\w+)", node_text)
|
|
85
99
|
else: # struct
|
|
86
100
|
# For struct, try to find struct name or use a generic name
|
|
87
|
-
match = re.search(r
|
|
88
|
-
|
|
101
|
+
match = re.search(r"struct\s+(\w+)", node_text)
|
|
102
|
+
|
|
89
103
|
if match:
|
|
90
104
|
symbol_name = match.group(1)
|
|
91
105
|
else:
|
|
92
106
|
# Fallback: use the kind as name
|
|
93
107
|
symbol_name = symbol_kind
|
|
94
108
|
else:
|
|
95
|
-
|
|
109
|
+
if node.text is None:
|
|
110
|
+
return None
|
|
111
|
+
symbol_name = node.text.decode("utf8")
|
|
96
112
|
|
|
97
113
|
return Symbol(
|
|
98
114
|
name=symbol_name,
|
|
@@ -105,78 +121,98 @@ class GoSymbolExtractor(TreeSitterExtractor):
|
|
|
105
121
|
|
|
106
122
|
# --- Go Dependency Analyzer ---
|
|
107
123
|
|
|
124
|
+
|
|
108
125
|
class GoDependencyAnalyzer(DependencyAnalyzer):
|
|
109
126
|
"""Analyzes Go import dependencies."""
|
|
110
127
|
|
|
111
128
|
def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
|
|
112
129
|
"""Analyzes Go import statements."""
|
|
113
130
|
dependencies: List[Dependency] = []
|
|
114
|
-
|
|
131
|
+
|
|
115
132
|
# Match import statements
|
|
116
133
|
# Format: import "package" or import ( "package1" "package2" )
|
|
117
134
|
# Also: import alias "package"
|
|
118
135
|
re.compile(
|
|
119
136
|
r'import\s+(?:\(([^)]+)\)|(?:"([^"]+)"|`([^`]+)`)|(\w+)\s+(?:"([^"]+)"|`([^`]+)`)))',
|
|
120
|
-
re.MULTILINE
|
|
137
|
+
re.MULTILINE,
|
|
121
138
|
)
|
|
122
|
-
|
|
139
|
+
|
|
123
140
|
# Handle single import: import "package"
|
|
124
|
-
single_import = re.compile(
|
|
125
|
-
|
|
141
|
+
single_import = re.compile(
|
|
142
|
+
r'import\s+(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))'
|
|
143
|
+
)
|
|
144
|
+
|
|
126
145
|
# Handle block import: import ( ... )
|
|
127
|
-
block_import = re.compile(r
|
|
128
|
-
|
|
146
|
+
block_import = re.compile(r"import\s*\(([^)]+)\)", re.DOTALL)
|
|
147
|
+
|
|
129
148
|
# Try block import first
|
|
130
149
|
block_match = block_import.search(content)
|
|
131
150
|
if block_match:
|
|
132
151
|
block_content = block_match.group(1)
|
|
133
|
-
for line in block_content.split(
|
|
152
|
+
for line in block_content.split("\n"):
|
|
134
153
|
line = line.strip()
|
|
135
|
-
if not line or line.startswith(
|
|
154
|
+
if not line or line.startswith("//"):
|
|
136
155
|
continue
|
|
137
156
|
# Extract package path
|
|
138
|
-
pkg_match = re.search(
|
|
157
|
+
pkg_match = re.search(
|
|
158
|
+
r'(?:"([^"]+)"|`([^`]+)`|(\w+)\s+(?:"([^"]+)"|`([^`]+)`))', line
|
|
159
|
+
)
|
|
139
160
|
if pkg_match:
|
|
140
|
-
pkg =
|
|
161
|
+
pkg = (
|
|
162
|
+
pkg_match.group(1)
|
|
163
|
+
or pkg_match.group(2)
|
|
164
|
+
or pkg_match.group(4)
|
|
165
|
+
or pkg_match.group(5)
|
|
166
|
+
)
|
|
141
167
|
alias = pkg_match.group(3)
|
|
142
|
-
line_num =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
168
|
+
line_num = (
|
|
169
|
+
content[: block_match.start()].count("\n")
|
|
170
|
+
+ line.split("\n")[0].count("\n")
|
|
171
|
+
+ 1
|
|
172
|
+
)
|
|
173
|
+
dependencies.append(
|
|
174
|
+
Dependency(
|
|
175
|
+
from_module=pkg,
|
|
176
|
+
imported_symbol=alias,
|
|
177
|
+
file_path=file_path,
|
|
178
|
+
line=line_num,
|
|
179
|
+
)
|
|
180
|
+
)
|
|
149
181
|
else:
|
|
150
182
|
# Try single import
|
|
151
183
|
for match in single_import.finditer(content):
|
|
152
|
-
pkg =
|
|
184
|
+
pkg = (
|
|
185
|
+
match.group(1) or match.group(2) or match.group(4) or match.group(5)
|
|
186
|
+
)
|
|
153
187
|
alias = match.group(3)
|
|
154
|
-
line_num = content[:match.start()].count(
|
|
155
|
-
dependencies.append(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
188
|
+
line_num = content[: match.start()].count("\n") + 1
|
|
189
|
+
dependencies.append(
|
|
190
|
+
Dependency(
|
|
191
|
+
from_module=pkg,
|
|
192
|
+
imported_symbol=alias,
|
|
193
|
+
file_path=file_path,
|
|
194
|
+
line=line_num,
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
|
|
162
198
|
return dependencies
|
|
163
199
|
|
|
164
200
|
def build_dependency_graph(self, project_root: str) -> DependencyGraph:
|
|
165
201
|
"""Builds a dependency graph for a Go project."""
|
|
166
202
|
graph = DependencyGraph()
|
|
167
|
-
|
|
203
|
+
|
|
168
204
|
for root, dirs, files in os.walk(project_root):
|
|
169
205
|
dirs[:] = filter_walk_dirs(dirs)
|
|
170
|
-
|
|
206
|
+
|
|
171
207
|
for file in files:
|
|
172
|
-
if not file.endswith(
|
|
208
|
+
if not file.endswith(".go"):
|
|
173
209
|
continue
|
|
174
|
-
|
|
210
|
+
|
|
175
211
|
file_path = os.path.join(root, file)
|
|
176
212
|
try:
|
|
177
|
-
with open(file_path,
|
|
213
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
178
214
|
content = f.read()
|
|
179
|
-
|
|
215
|
+
|
|
180
216
|
dependencies = self.analyze_imports(file_path, content)
|
|
181
217
|
for dep in dependencies:
|
|
182
218
|
# For Go, we can resolve to vendor or standard library
|
|
@@ -185,12 +221,12 @@ class GoDependencyAnalyzer(DependencyAnalyzer):
|
|
|
185
221
|
pass
|
|
186
222
|
except Exception:
|
|
187
223
|
continue
|
|
188
|
-
|
|
224
|
+
|
|
189
225
|
return graph
|
|
190
226
|
|
|
191
227
|
def _is_source_file(self, file_path: str) -> bool:
|
|
192
228
|
"""Check if a file is a Go source file."""
|
|
193
|
-
return file_path.endswith(
|
|
229
|
+
return file_path.endswith(".go")
|
|
194
230
|
|
|
195
231
|
|
|
196
232
|
class GoLanguageSupport(BaseLanguageSupport):
|
|
@@ -198,11 +234,11 @@ class GoLanguageSupport(BaseLanguageSupport):
|
|
|
198
234
|
|
|
199
235
|
@property
|
|
200
236
|
def language_name(self) -> str:
|
|
201
|
-
return
|
|
237
|
+
return "go"
|
|
202
238
|
|
|
203
239
|
@property
|
|
204
240
|
def file_extensions(self) -> Set[str]:
|
|
205
|
-
return {
|
|
241
|
+
return {".go"}
|
|
206
242
|
|
|
207
243
|
def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
|
|
208
244
|
try:
|
|
@@ -212,4 +248,3 @@ class GoLanguageSupport(BaseLanguageSupport):
|
|
|
212
248
|
|
|
213
249
|
def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
|
|
214
250
|
return GoDependencyAnalyzer()
|
|
215
|
-
|
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import re
|
|
5
|
-
from typing import List
|
|
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
|
|
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
|
|
15
|
+
from ..symbol_extractor import Symbol
|
|
16
|
+
from ..symbol_extractor import SymbolExtractor
|
|
11
17
|
from ..tree_sitter_extractor import TreeSitterExtractor
|
|
12
18
|
|
|
13
19
|
try:
|
|
14
|
-
from tree_sitter import Language, Node
|
|
15
20
|
import tree_sitter_java
|
|
16
|
-
|
|
21
|
+
from tree_sitter import Language
|
|
22
|
+
from tree_sitter import Node
|
|
23
|
+
|
|
24
|
+
JAVA_LANGUAGE: Optional[Language] = cast(
|
|
25
|
+
Optional[Language], tree_sitter_java.language()
|
|
26
|
+
)
|
|
17
27
|
except (ImportError, Exception):
|
|
18
28
|
JAVA_LANGUAGE = None
|
|
19
29
|
|
|
@@ -52,13 +62,12 @@ class JavaSymbolExtractor(TreeSitterExtractor):
|
|
|
52
62
|
if not JAVA_LANGUAGE:
|
|
53
63
|
raise RuntimeError("Java tree-sitter grammar not available.")
|
|
54
64
|
# 如果传入的是 PyCapsule,需要转换为 Language 对象
|
|
55
|
-
|
|
56
|
-
lang = Language(JAVA_LANGUAGE)
|
|
57
|
-
else:
|
|
58
|
-
lang = JAVA_LANGUAGE
|
|
65
|
+
lang = Language(JAVA_LANGUAGE)
|
|
59
66
|
super().__init__(lang, JAVA_SYMBOL_QUERY)
|
|
60
67
|
|
|
61
|
-
def _create_symbol_from_capture(
|
|
68
|
+
def _create_symbol_from_capture(
|
|
69
|
+
self, node: Node, name: str, file_path: str
|
|
70
|
+
) -> Optional[Symbol]:
|
|
62
71
|
"""Maps a tree-sitter capture to a Symbol object."""
|
|
63
72
|
kind_map = {
|
|
64
73
|
"method.name": "method",
|
|
@@ -69,13 +78,16 @@ class JavaSymbolExtractor(TreeSitterExtractor):
|
|
|
69
78
|
"field.name": "field",
|
|
70
79
|
"constructor.name": "constructor",
|
|
71
80
|
}
|
|
72
|
-
|
|
81
|
+
|
|
73
82
|
symbol_kind = kind_map.get(name)
|
|
74
83
|
if not symbol_kind:
|
|
75
84
|
return None
|
|
76
85
|
|
|
86
|
+
if node.text is None:
|
|
87
|
+
return None
|
|
88
|
+
|
|
77
89
|
return Symbol(
|
|
78
|
-
name=node.text.decode(
|
|
90
|
+
name=node.text.decode("utf8"),
|
|
79
91
|
kind=symbol_kind,
|
|
80
92
|
file_path=file_path,
|
|
81
93
|
line_start=node.start_point[0] + 1,
|
|
@@ -85,109 +97,131 @@ class JavaSymbolExtractor(TreeSitterExtractor):
|
|
|
85
97
|
|
|
86
98
|
# --- Java Dependency Analyzer ---
|
|
87
99
|
|
|
100
|
+
|
|
88
101
|
class JavaDependencyAnalyzer(DependencyAnalyzer):
|
|
89
102
|
"""Analyzes Java import dependencies."""
|
|
90
103
|
|
|
91
104
|
def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
|
|
92
105
|
"""Analyzes Java import statements."""
|
|
93
106
|
dependencies: List[Dependency] = []
|
|
94
|
-
|
|
107
|
+
|
|
95
108
|
# Java import statements
|
|
96
109
|
# import package.Class;
|
|
97
110
|
# import package.*;
|
|
98
111
|
# import static package.Class.method;
|
|
99
112
|
import_pattern = re.compile(
|
|
100
|
-
r
|
|
101
|
-
re.MULTILINE
|
|
113
|
+
r"import\s+(?:static\s+)?([\w.]+)(?:\.\*)?\s*;", re.MULTILINE
|
|
102
114
|
)
|
|
103
|
-
|
|
104
|
-
for line_num, line in enumerate(content.split(
|
|
115
|
+
|
|
116
|
+
for line_num, line in enumerate(content.split("\n"), start=1):
|
|
105
117
|
import_match = import_pattern.search(line)
|
|
106
118
|
if import_match:
|
|
107
119
|
module_path = import_match.group(1)
|
|
108
120
|
if module_path:
|
|
109
121
|
# Extract class name if it's a specific import
|
|
110
|
-
parts = module_path.split(
|
|
122
|
+
parts = module_path.split(".")
|
|
111
123
|
imported_symbol = None
|
|
112
|
-
if len(parts) > 1 and not line.strip().endswith(
|
|
124
|
+
if len(parts) > 1 and not line.strip().endswith(".*;"):
|
|
113
125
|
# Specific class import
|
|
114
126
|
imported_symbol = parts[-1]
|
|
115
|
-
module_path =
|
|
116
|
-
|
|
117
|
-
dependencies.append(
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
127
|
+
module_path = ".".join(parts[:-1])
|
|
128
|
+
|
|
129
|
+
dependencies.append(
|
|
130
|
+
Dependency(
|
|
131
|
+
from_module=module_path,
|
|
132
|
+
imported_symbol=imported_symbol,
|
|
133
|
+
file_path=file_path,
|
|
134
|
+
line=line_num,
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
124
138
|
return dependencies
|
|
125
139
|
|
|
126
140
|
def build_dependency_graph(self, project_root: str) -> DependencyGraph:
|
|
127
141
|
"""Builds a dependency graph for a Java project."""
|
|
128
142
|
graph = DependencyGraph()
|
|
129
|
-
|
|
143
|
+
|
|
130
144
|
for root, dirs, files in os.walk(project_root):
|
|
131
145
|
dirs[:] = filter_walk_dirs(dirs)
|
|
132
|
-
|
|
146
|
+
|
|
133
147
|
for file in files:
|
|
134
|
-
if not file.endswith(
|
|
148
|
+
if not file.endswith(".java"):
|
|
135
149
|
continue
|
|
136
|
-
|
|
150
|
+
|
|
137
151
|
file_path = os.path.join(root, file)
|
|
138
152
|
try:
|
|
139
|
-
with open(file_path,
|
|
153
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
140
154
|
content = f.read()
|
|
141
|
-
|
|
155
|
+
|
|
142
156
|
dependencies = self.analyze_imports(file_path, content)
|
|
143
157
|
for dep in dependencies:
|
|
144
158
|
# Skip java.* and javax.* standard library packages
|
|
145
|
-
if not dep.from_module.startswith((
|
|
146
|
-
dep_path = self._resolve_module_path(
|
|
159
|
+
if not dep.from_module.startswith(("java.", "javax.")):
|
|
160
|
+
dep_path = self._resolve_module_path(
|
|
161
|
+
project_root,
|
|
162
|
+
dep.from_module,
|
|
163
|
+
dep.imported_symbol,
|
|
164
|
+
file_path,
|
|
165
|
+
)
|
|
147
166
|
if dep_path and dep_path != file_path:
|
|
148
167
|
graph.add_dependency(file_path, dep_path)
|
|
149
168
|
except Exception:
|
|
150
169
|
continue
|
|
151
|
-
|
|
170
|
+
|
|
152
171
|
return graph
|
|
153
172
|
|
|
154
|
-
def _resolve_module_path(
|
|
173
|
+
def _resolve_module_path(
|
|
174
|
+
self,
|
|
175
|
+
project_root: str,
|
|
176
|
+
package_name: str,
|
|
177
|
+
class_name: Optional[str],
|
|
178
|
+
from_file: str,
|
|
179
|
+
) -> Optional[str]:
|
|
155
180
|
"""Resolve a Java package name to a file path."""
|
|
156
181
|
if not package_name:
|
|
157
182
|
return None
|
|
158
|
-
|
|
183
|
+
|
|
159
184
|
# Convert package name to directory path
|
|
160
|
-
package_path = package_name.replace(
|
|
161
|
-
|
|
185
|
+
package_path = package_name.replace(".", os.sep)
|
|
186
|
+
|
|
162
187
|
# Try to find the class file
|
|
163
188
|
if class_name:
|
|
164
189
|
# Specific class import
|
|
165
|
-
class_file = class_name +
|
|
166
|
-
resolved = os.path.normpath(
|
|
190
|
+
class_file = class_name + ".java"
|
|
191
|
+
resolved = os.path.normpath(
|
|
192
|
+
os.path.join(
|
|
193
|
+
project_root, "src", "main", "java", package_path, class_file
|
|
194
|
+
)
|
|
195
|
+
)
|
|
167
196
|
if os.path.exists(resolved) and os.path.isfile(resolved):
|
|
168
197
|
return resolved
|
|
169
|
-
|
|
198
|
+
|
|
170
199
|
# Try alternative source directories
|
|
171
|
-
for src_dir in [
|
|
172
|
-
resolved = os.path.normpath(
|
|
200
|
+
for src_dir in ["src", "source", "java"]:
|
|
201
|
+
resolved = os.path.normpath(
|
|
202
|
+
os.path.join(project_root, src_dir, package_path, class_file)
|
|
203
|
+
)
|
|
173
204
|
if os.path.exists(resolved) and os.path.isfile(resolved):
|
|
174
205
|
return resolved
|
|
175
206
|
else:
|
|
176
207
|
# Wildcard import - try to find package-info.java or any class in the package
|
|
177
|
-
package_dir = os.path.normpath(
|
|
208
|
+
package_dir = os.path.normpath(
|
|
209
|
+
os.path.join(project_root, "src", "main", "java", package_path)
|
|
210
|
+
)
|
|
178
211
|
if os.path.exists(package_dir) and os.path.isdir(package_dir):
|
|
179
212
|
# Return the first .java file found (or package-info.java if exists)
|
|
180
213
|
for file in os.listdir(package_dir):
|
|
181
|
-
if file.endswith(
|
|
214
|
+
if file.endswith(".java"):
|
|
182
215
|
resolved = os.path.join(package_dir, file)
|
|
183
216
|
if os.path.isfile(resolved):
|
|
184
217
|
return resolved
|
|
185
|
-
|
|
218
|
+
|
|
186
219
|
return None
|
|
187
220
|
|
|
188
221
|
|
|
189
222
|
# --- Java Language Support ---
|
|
190
223
|
|
|
224
|
+
|
|
191
225
|
class JavaLanguageSupport(BaseLanguageSupport):
|
|
192
226
|
"""Java语言支持。"""
|
|
193
227
|
|
|
@@ -197,7 +231,7 @@ class JavaLanguageSupport(BaseLanguageSupport):
|
|
|
197
231
|
|
|
198
232
|
@property
|
|
199
233
|
def file_extensions(self) -> Set[str]:
|
|
200
|
-
return {
|
|
234
|
+
return {".java"}
|
|
201
235
|
|
|
202
236
|
def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
|
|
203
237
|
if not JAVA_LANGUAGE:
|
|
@@ -209,4 +243,3 @@ class JavaLanguageSupport(BaseLanguageSupport):
|
|
|
209
243
|
|
|
210
244
|
def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
|
|
211
245
|
return JavaDependencyAnalyzer()
|
|
212
|
-
|