jarvis-ai-assistant 0.3.30__py3-none-any.whl → 0.7.0__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 (115) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +289 -87
  3. jarvis/jarvis_agent/agent_manager.py +17 -8
  4. jarvis/jarvis_agent/edit_file_handler.py +374 -86
  5. jarvis/jarvis_agent/event_bus.py +1 -1
  6. jarvis/jarvis_agent/file_context_handler.py +79 -0
  7. jarvis/jarvis_agent/jarvis.py +601 -43
  8. jarvis/jarvis_agent/main.py +32 -2
  9. jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
  10. jarvis/jarvis_agent/run_loop.py +38 -5
  11. jarvis/jarvis_agent/share_manager.py +8 -1
  12. jarvis/jarvis_agent/stdio_redirect.py +295 -0
  13. jarvis/jarvis_agent/task_analyzer.py +5 -2
  14. jarvis/jarvis_agent/task_planner.py +496 -0
  15. jarvis/jarvis_agent/utils.py +5 -1
  16. jarvis/jarvis_agent/web_bridge.py +189 -0
  17. jarvis/jarvis_agent/web_output_sink.py +53 -0
  18. jarvis/jarvis_agent/web_server.py +751 -0
  19. jarvis/jarvis_c2rust/__init__.py +26 -0
  20. jarvis/jarvis_c2rust/cli.py +613 -0
  21. jarvis/jarvis_c2rust/collector.py +258 -0
  22. jarvis/jarvis_c2rust/library_replacer.py +1122 -0
  23. jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
  24. jarvis/jarvis_c2rust/optimizer.py +960 -0
  25. jarvis/jarvis_c2rust/scanner.py +1681 -0
  26. jarvis/jarvis_c2rust/transpiler.py +2325 -0
  27. jarvis/jarvis_code_agent/build_validation_config.py +133 -0
  28. jarvis/jarvis_code_agent/code_agent.py +1171 -94
  29. jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
  30. jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
  31. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
  32. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
  33. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
  34. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
  35. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
  36. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
  37. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
  38. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
  39. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
  40. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
  41. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
  42. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
  43. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
  44. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
  45. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
  46. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
  47. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
  48. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
  49. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
  50. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
  51. jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
  52. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
  53. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
  54. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
  55. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
  56. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
  57. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
  58. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
  59. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
  60. jarvis/jarvis_code_agent/lint.py +270 -8
  61. jarvis/jarvis_code_agent/utils.py +142 -0
  62. jarvis/jarvis_code_analysis/code_review.py +483 -569
  63. jarvis/jarvis_data/config_schema.json +97 -8
  64. jarvis/jarvis_git_utils/git_commiter.py +38 -26
  65. jarvis/jarvis_mcp/sse_mcp_client.py +2 -2
  66. jarvis/jarvis_mcp/stdio_mcp_client.py +1 -1
  67. jarvis/jarvis_memory_organizer/memory_organizer.py +1 -1
  68. jarvis/jarvis_multi_agent/__init__.py +239 -25
  69. jarvis/jarvis_multi_agent/main.py +37 -1
  70. jarvis/jarvis_platform/base.py +103 -51
  71. jarvis/jarvis_platform/openai.py +26 -1
  72. jarvis/jarvis_platform/yuanbao.py +1 -1
  73. jarvis/jarvis_platform_manager/service.py +2 -2
  74. jarvis/jarvis_rag/cli.py +4 -4
  75. jarvis/jarvis_sec/__init__.py +3605 -0
  76. jarvis/jarvis_sec/checkers/__init__.py +32 -0
  77. jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
  78. jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
  79. jarvis/jarvis_sec/cli.py +116 -0
  80. jarvis/jarvis_sec/report.py +257 -0
  81. jarvis/jarvis_sec/status.py +264 -0
  82. jarvis/jarvis_sec/types.py +20 -0
  83. jarvis/jarvis_sec/workflow.py +219 -0
  84. jarvis/jarvis_stats/cli.py +1 -1
  85. jarvis/jarvis_stats/stats.py +1 -1
  86. jarvis/jarvis_stats/visualizer.py +1 -1
  87. jarvis/jarvis_tools/cli/main.py +1 -0
  88. jarvis/jarvis_tools/execute_script.py +46 -9
  89. jarvis/jarvis_tools/generate_new_tool.py +3 -1
  90. jarvis/jarvis_tools/read_code.py +275 -12
  91. jarvis/jarvis_tools/read_symbols.py +141 -0
  92. jarvis/jarvis_tools/read_webpage.py +5 -3
  93. jarvis/jarvis_tools/registry.py +73 -35
  94. jarvis/jarvis_tools/search_web.py +15 -11
  95. jarvis/jarvis_tools/sub_agent.py +24 -42
  96. jarvis/jarvis_tools/sub_code_agent.py +14 -13
  97. jarvis/jarvis_tools/virtual_tty.py +1 -1
  98. jarvis/jarvis_utils/config.py +187 -35
  99. jarvis/jarvis_utils/embedding.py +3 -0
  100. jarvis/jarvis_utils/git_utils.py +181 -6
  101. jarvis/jarvis_utils/globals.py +3 -3
  102. jarvis/jarvis_utils/http.py +1 -1
  103. jarvis/jarvis_utils/input.py +78 -2
  104. jarvis/jarvis_utils/methodology.py +25 -19
  105. jarvis/jarvis_utils/utils.py +644 -359
  106. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/METADATA +85 -1
  107. jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
  108. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +4 -0
  109. jarvis/jarvis_agent/config.py +0 -92
  110. jarvis/jarvis_tools/edit_file.py +0 -179
  111. jarvis/jarvis_tools/rewrite_file.py +0 -191
  112. jarvis_ai_assistant-0.3.30.dist-info/RECORD +0 -137
  113. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
  114. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
  115. {jarvis_ai_assistant-0.3.30.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,185 @@
1
+ """语言注册表。
2
+
3
+ 管理所有语言支持的注册和发现机制。
4
+ """
5
+
6
+ import os
7
+ from typing import Dict, Optional, Set
8
+
9
+ from .base_language import BaseLanguageSupport
10
+ from .dependency_analyzer import DependencyAnalyzer
11
+ from .symbol_extractor import SymbolExtractor
12
+
13
+
14
+ class LanguageRegistry:
15
+ """语言支持注册表。
16
+
17
+ 负责管理所有已注册的语言支持,提供语言检测和工厂方法。
18
+ """
19
+
20
+ def __init__(self):
21
+ self._languages: Dict[str, BaseLanguageSupport] = {}
22
+ self._extension_map: Dict[str, str] = {} # extension -> language_name
23
+
24
+ def register(self, language_support: BaseLanguageSupport) -> None:
25
+ """注册一个语言支持。
26
+
27
+ Args:
28
+ language_support: 语言支持实例
29
+ """
30
+ lang_name = language_support.language_name
31
+ self._languages[lang_name] = language_support
32
+
33
+ # 注册文件扩展名映射
34
+ for ext in language_support.file_extensions:
35
+ # 如果扩展名已存在,记录警告但不覆盖(保留第一个注册的)
36
+ if ext in self._extension_map and self._extension_map[ext] != lang_name:
37
+ print(f"Warning: Extension {ext} already registered for "
38
+ f"{self._extension_map[ext]}, ignoring registration for {lang_name}")
39
+ else:
40
+ self._extension_map[ext] = lang_name
41
+
42
+ def unregister(self, language_name: str) -> None:
43
+ """取消注册一个语言支持。
44
+
45
+ Args:
46
+ language_name: 语言名称
47
+ """
48
+ if language_name in self._languages:
49
+ self._languages.pop(language_name)
50
+ # 移除扩展名映射
51
+ extensions_to_remove = [
52
+ ext for ext, lang in self._extension_map.items()
53
+ if lang == language_name
54
+ ]
55
+ for ext in extensions_to_remove:
56
+ del self._extension_map[ext]
57
+
58
+ def detect_language(self, file_path: str) -> Optional[str]:
59
+ """根据文件路径检测编程语言。
60
+
61
+ Args:
62
+ file_path: 文件路径
63
+
64
+ Returns:
65
+ 语言名称,如果无法检测则返回None
66
+ """
67
+ _, ext = os.path.splitext(file_path)
68
+ return self._extension_map.get(ext)
69
+
70
+ def get_language_support(self, language_name: str) -> Optional[BaseLanguageSupport]:
71
+ """获取指定语言的支持实例。
72
+
73
+ Args:
74
+ language_name: 语言名称
75
+
76
+ Returns:
77
+ 语言支持实例,如果未注册则返回None
78
+ """
79
+ return self._languages.get(language_name)
80
+
81
+ def get_symbol_extractor(self, language_name: str) -> Optional[SymbolExtractor]:
82
+ """获取指定语言的符号提取器。
83
+
84
+ Args:
85
+ language_name: 语言名称
86
+
87
+ Returns:
88
+ SymbolExtractor实例,如果不支持则返回None
89
+ """
90
+ lang_support = self.get_language_support(language_name)
91
+ if lang_support:
92
+ return lang_support.create_symbol_extractor()
93
+ return None
94
+
95
+ def get_dependency_analyzer(self, language_name: str) -> Optional[DependencyAnalyzer]:
96
+ """获取指定语言的依赖分析器。
97
+
98
+ Args:
99
+ language_name: 语言名称
100
+
101
+ Returns:
102
+ DependencyAnalyzer实例,如果不支持则返回None
103
+ """
104
+ lang_support = self.get_language_support(language_name)
105
+ if lang_support:
106
+ return lang_support.create_dependency_analyzer()
107
+ return None
108
+
109
+ def get_supported_languages(self) -> Set[str]:
110
+ """获取所有已注册的语言名称集合。
111
+
112
+ Returns:
113
+ 语言名称集合
114
+ """
115
+ return set(self._languages.keys())
116
+
117
+ def is_supported(self, file_path: str) -> bool:
118
+ """检查文件是否被支持。
119
+
120
+ Args:
121
+ file_path: 文件路径
122
+
123
+ Returns:
124
+ 如果文件被支持返回True,否则返回False
125
+ """
126
+ return self.detect_language(file_path) is not None
127
+
128
+
129
+ # 全局注册表实例
130
+ _registry = LanguageRegistry()
131
+
132
+
133
+ def get_registry() -> LanguageRegistry:
134
+ """获取全局语言注册表实例。
135
+
136
+ Returns:
137
+ 全局LanguageRegistry实例
138
+ """
139
+ return _registry
140
+
141
+
142
+ def register_language(language_support: BaseLanguageSupport) -> None:
143
+ """注册一个语言支持(便捷函数)。
144
+
145
+ Args:
146
+ language_support: 语言支持实例
147
+ """
148
+ _registry.register(language_support)
149
+
150
+
151
+ def detect_language(file_path: str) -> Optional[str]:
152
+ """检测文件的语言(便捷函数)。
153
+
154
+ Args:
155
+ file_path: 文件路径
156
+
157
+ Returns:
158
+ 语言名称,如果无法检测则返回None
159
+ """
160
+ return _registry.detect_language(file_path)
161
+
162
+
163
+ def get_symbol_extractor(language: str) -> Optional[SymbolExtractor]:
164
+ """获取指定语言的符号提取器(便捷函数)。
165
+
166
+ Args:
167
+ language: 语言名称
168
+
169
+ Returns:
170
+ SymbolExtractor实例,如果不支持则返回None
171
+ """
172
+ return _registry.get_symbol_extractor(language)
173
+
174
+
175
+ def get_dependency_analyzer(language: str) -> Optional[DependencyAnalyzer]:
176
+ """获取指定语言的依赖分析器(便捷函数)。
177
+
178
+ Args:
179
+ language: 语言名称
180
+
181
+ Returns:
182
+ DependencyAnalyzer实例,如果不支持则返回None
183
+ """
184
+ return _registry.get_dependency_analyzer(language)
185
+
@@ -0,0 +1,89 @@
1
+ """语言支持模块。
2
+
3
+ 提供语言检测和工厂函数,使用语言注册表管理所有语言支持。
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ from .dependency_analyzer import DependencyAnalyzer
9
+ from .language_registry import (
10
+ detect_language as _detect_language,
11
+ get_dependency_analyzer as _get_dependency_analyzer,
12
+ get_symbol_extractor as _get_symbol_extractor,
13
+ register_language,
14
+ )
15
+ from .symbol_extractor import SymbolExtractor
16
+
17
+ # 自动注册所有语言支持
18
+ # 使用try-except确保某个语言支持导入失败不影响其他语言
19
+
20
+ # Python语言支持(必需,因为它是核心语言)
21
+ try:
22
+ from .languages import PythonLanguageSupport
23
+ register_language(PythonLanguageSupport())
24
+ except ImportError as e:
25
+ print(f"Warning: Failed to import PythonLanguageSupport: {e}")
26
+
27
+ # Rust语言支持(可选,需要tree-sitter)
28
+ try:
29
+ from .languages import RustLanguageSupport
30
+ register_language(RustLanguageSupport())
31
+ except (ImportError, RuntimeError):
32
+ pass # 静默失败,tree-sitter可能不可用
33
+
34
+ # Go语言支持(可选,需要tree-sitter)
35
+ try:
36
+ from .languages import GoLanguageSupport
37
+ register_language(GoLanguageSupport())
38
+ except (ImportError, RuntimeError):
39
+ pass # 静默失败,tree-sitter可能不可用
40
+
41
+ # C语言支持(可选,需要tree-sitter)
42
+ try:
43
+ from .languages import CLanguageSupport
44
+ register_language(CLanguageSupport())
45
+ except (ImportError, RuntimeError):
46
+ pass # 静默失败,tree-sitter可能不可用
47
+
48
+ # C++语言支持(可选,需要tree-sitter)
49
+ try:
50
+ from .languages import CppLanguageSupport
51
+ register_language(CppLanguageSupport())
52
+ except (ImportError, RuntimeError):
53
+ pass # 静默失败,tree-sitter可能不可用
54
+
55
+
56
+ def detect_language(file_path: str) -> Optional[str]:
57
+ """检测文件的编程语言。
58
+
59
+ Args:
60
+ file_path: 文件路径
61
+
62
+ Returns:
63
+ 语言名称,如果无法检测则返回None
64
+ """
65
+ return _detect_language(file_path)
66
+
67
+
68
+ def get_symbol_extractor(language: str) -> Optional[SymbolExtractor]:
69
+ """获取指定语言的符号提取器。
70
+
71
+ Args:
72
+ language: 语言名称
73
+
74
+ Returns:
75
+ SymbolExtractor实例,如果不支持则返回None
76
+ """
77
+ return _get_symbol_extractor(language)
78
+
79
+
80
+ def get_dependency_analyzer(language: str) -> Optional[DependencyAnalyzer]:
81
+ """获取指定语言的依赖分析器。
82
+
83
+ Args:
84
+ language: 语言名称
85
+
86
+ Returns:
87
+ DependencyAnalyzer实例,如果不支持则返回None
88
+ """
89
+ return _get_dependency_analyzer(language)
@@ -0,0 +1,31 @@
1
+ """语言支持实现模块。
2
+
3
+ 包含各种编程语言的支持实现。
4
+ """
5
+
6
+ # 导入所有语言支持类,以便自动注册
7
+ # 使用try-except确保某个语言支持导入失败不影响其他语言
8
+
9
+ from .python_language import PythonLanguageSupport
10
+
11
+ __all__ = ['PythonLanguageSupport']
12
+
13
+ # 尝试导入tree-sitter相关的语言支持
14
+ try:
15
+ from .rust_language import RustLanguageSupport
16
+ __all__.append('RustLanguageSupport')
17
+ except (ImportError, RuntimeError):
18
+ pass
19
+
20
+ try:
21
+ from .go_language import GoLanguageSupport
22
+ __all__.append('GoLanguageSupport')
23
+ except (ImportError, RuntimeError):
24
+ pass
25
+
26
+ try:
27
+ from .c_cpp_language import CLanguageSupport, CppLanguageSupport
28
+ __all__.extend(['CLanguageSupport', 'CppLanguageSupport'])
29
+ except (ImportError, RuntimeError):
30
+ pass
31
+
@@ -0,0 +1,231 @@
1
+ """C/C++语言支持实现。"""
2
+
3
+ import os
4
+ import re
5
+ from typing import List, Optional, Set
6
+
7
+ from tree_sitter import Language, Node
8
+
9
+ from ..base_language import BaseLanguageSupport
10
+ from ..dependency_analyzer import Dependency, DependencyAnalyzer, DependencyGraph
11
+ from ..file_ignore import filter_walk_dirs
12
+ from ..symbol_extractor import Symbol, SymbolExtractor
13
+ from ..tree_sitter_extractor import TreeSitterExtractor
14
+
15
+
16
+ # --- C/C++ Symbol Query ---
17
+
18
+ C_CPP_SYMBOL_QUERY = """
19
+ (function_declarator
20
+ declarator: (identifier) @function.name)
21
+
22
+ (struct_specifier
23
+ name: (type_identifier) @struct.name)
24
+
25
+ (class_specifier
26
+ name: (type_identifier) @class.name)
27
+
28
+ (union_specifier
29
+ name: (type_identifier) @union.name)
30
+
31
+ (enum_specifier
32
+ name: (type_identifier) @enum.name)
33
+ """
34
+
35
+ # --- C/C++ Language Setup ---
36
+
37
+ try:
38
+ import tree_sitter_c
39
+ C_LANGUAGE: Optional[Language] = tree_sitter_c.language()
40
+ except (ImportError, Exception):
41
+ C_LANGUAGE = None
42
+
43
+ try:
44
+ import tree_sitter_cpp
45
+ CPP_LANGUAGE: Optional[Language] = tree_sitter_cpp.language()
46
+ except (ImportError, Exception):
47
+ CPP_LANGUAGE = None
48
+
49
+
50
+ # --- C/C++ Symbol Extractors ---
51
+
52
+ class CSymbolExtractor(TreeSitterExtractor):
53
+ """Extracts symbols from C code using tree-sitter."""
54
+
55
+ def __init__(self):
56
+ if not C_LANGUAGE:
57
+ raise RuntimeError("C tree-sitter grammar not available.")
58
+ super().__init__(C_LANGUAGE, C_CPP_SYMBOL_QUERY)
59
+
60
+ def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
61
+ kind_map = {
62
+ "function.name": "function",
63
+ "struct.name": "struct",
64
+ "union.name": "union",
65
+ "enum.name": "enum",
66
+ }
67
+ symbol_kind = kind_map.get(name)
68
+ if not symbol_kind:
69
+ return None
70
+
71
+ return Symbol(
72
+ name=node.text.decode('utf8'),
73
+ kind=symbol_kind,
74
+ file_path=file_path,
75
+ line_start=node.start_point[0] + 1,
76
+ line_end=node.end_point[0] + 1,
77
+ )
78
+
79
+
80
+ class CppSymbolExtractor(TreeSitterExtractor):
81
+ """Extracts symbols from C++ code using tree-sitter."""
82
+
83
+ def __init__(self):
84
+ if not CPP_LANGUAGE:
85
+ raise RuntimeError("C++ tree-sitter grammar not available.")
86
+ super().__init__(CPP_LANGUAGE, C_CPP_SYMBOL_QUERY)
87
+
88
+ def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
89
+ kind_map = {
90
+ "function.name": "function",
91
+ "struct.name": "struct",
92
+ "class.name": "class",
93
+ "union.name": "union",
94
+ "enum.name": "enum",
95
+ }
96
+ symbol_kind = kind_map.get(name)
97
+ if not symbol_kind:
98
+ return None
99
+
100
+ return Symbol(
101
+ name=node.text.decode('utf8'),
102
+ kind=symbol_kind,
103
+ file_path=file_path,
104
+ line_start=node.start_point[0] + 1,
105
+ line_end=node.end_point[0] + 1,
106
+ )
107
+
108
+
109
+ # --- C/C++ Dependency Analyzers ---
110
+
111
+ class CDependencyAnalyzer(DependencyAnalyzer):
112
+ """Analyzes C include dependencies."""
113
+
114
+ def analyze_imports(self, file_path: str, content: str) -> List[Dependency]:
115
+ """Analyzes C #include statements."""
116
+ dependencies: List[Dependency] = []
117
+
118
+ # Match #include directives
119
+ # Format: #include <header.h> or #include "header.h"
120
+ include_pattern = re.compile(r'#include\s+[<"]([^>"]+)[>"]')
121
+
122
+ for line_num, line in enumerate(content.split('\n'), start=1):
123
+ match = include_pattern.search(line)
124
+ if match:
125
+ header = match.group(1)
126
+ dependencies.append(Dependency(
127
+ from_module=header,
128
+ imported_symbol=None,
129
+ file_path=file_path,
130
+ line=line_num,
131
+ ))
132
+
133
+ return dependencies
134
+
135
+ def build_dependency_graph(self, project_root: str) -> DependencyGraph:
136
+ """Builds a dependency graph for a C project."""
137
+ graph = DependencyGraph()
138
+ extensions = {'.c', '.h'}
139
+
140
+ for root, dirs, files in os.walk(project_root):
141
+ dirs[:] = filter_walk_dirs(dirs)
142
+
143
+ for file in files:
144
+ if not any(file.endswith(ext) for ext in extensions):
145
+ continue
146
+
147
+ file_path = os.path.join(root, file)
148
+ try:
149
+ with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
150
+ content = f.read()
151
+
152
+ dependencies = self.analyze_imports(file_path, content)
153
+ for dep in dependencies:
154
+ dep_path = self._resolve_header_path(project_root, dep.from_module, file_path)
155
+ if dep_path and dep_path != file_path:
156
+ graph.add_dependency(file_path, dep_path)
157
+ except Exception:
158
+ continue
159
+
160
+ return graph
161
+
162
+ def _resolve_header_path(self, project_root: str, header_name: str, from_file: str) -> Optional[str]:
163
+ """Resolve a header name to a file path."""
164
+ # Try relative to current file
165
+ base_dir = os.path.dirname(from_file)
166
+ relative_path = os.path.join(base_dir, header_name)
167
+ if os.path.exists(relative_path):
168
+ return relative_path
169
+
170
+ # Try in project root
171
+ for root, dirs, files in os.walk(project_root):
172
+ dirs[:] = filter_walk_dirs(dirs)
173
+ if header_name in files:
174
+ return os.path.join(root, header_name)
175
+
176
+ return None
177
+
178
+ def _is_source_file(self, file_path: str) -> bool:
179
+ """Check if a file is a C source file."""
180
+ return file_path.endswith(('.c', '.h'))
181
+
182
+
183
+ class CppDependencyAnalyzer(CDependencyAnalyzer):
184
+ """Analyzes C++ include dependencies (same as C)."""
185
+
186
+ def _is_source_file(self, file_path: str) -> bool:
187
+ """Check if a file is a C++ source file."""
188
+ return file_path.endswith(('.cpp', '.hpp', '.cc', '.cxx', '.hxx', '.h'))
189
+
190
+
191
+ class CLanguageSupport(BaseLanguageSupport):
192
+ """C语言支持类。"""
193
+
194
+ @property
195
+ def language_name(self) -> str:
196
+ return 'c'
197
+
198
+ @property
199
+ def file_extensions(self) -> Set[str]:
200
+ return {'.c', '.h'}
201
+
202
+ def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
203
+ try:
204
+ return CSymbolExtractor()
205
+ except RuntimeError:
206
+ return None
207
+
208
+ def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
209
+ return CDependencyAnalyzer()
210
+
211
+
212
+ class CppLanguageSupport(BaseLanguageSupport):
213
+ """C++语言支持类。"""
214
+
215
+ @property
216
+ def language_name(self) -> str:
217
+ return 'cpp'
218
+
219
+ @property
220
+ def file_extensions(self) -> Set[str]:
221
+ return {'.cpp', '.hpp', '.cc', '.cxx', '.hxx'}
222
+
223
+ def create_symbol_extractor(self) -> Optional[SymbolExtractor]:
224
+ try:
225
+ return CppSymbolExtractor()
226
+ except RuntimeError:
227
+ return None
228
+
229
+ def create_dependency_analyzer(self) -> Optional[DependencyAnalyzer]:
230
+ return CppDependencyAnalyzer()
231
+