ai-coding-assistant 0.5.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.
- ai_coding_assistant-0.5.0.dist-info/METADATA +226 -0
- ai_coding_assistant-0.5.0.dist-info/RECORD +89 -0
- ai_coding_assistant-0.5.0.dist-info/WHEEL +4 -0
- ai_coding_assistant-0.5.0.dist-info/entry_points.txt +3 -0
- ai_coding_assistant-0.5.0.dist-info/licenses/LICENSE +21 -0
- coding_assistant/__init__.py +3 -0
- coding_assistant/__main__.py +19 -0
- coding_assistant/cli/__init__.py +1 -0
- coding_assistant/cli/app.py +158 -0
- coding_assistant/cli/commands/__init__.py +19 -0
- coding_assistant/cli/commands/ask.py +178 -0
- coding_assistant/cli/commands/config.py +438 -0
- coding_assistant/cli/commands/diagram.py +267 -0
- coding_assistant/cli/commands/document.py +410 -0
- coding_assistant/cli/commands/explain.py +192 -0
- coding_assistant/cli/commands/fix.py +249 -0
- coding_assistant/cli/commands/index.py +162 -0
- coding_assistant/cli/commands/refactor.py +245 -0
- coding_assistant/cli/commands/search.py +182 -0
- coding_assistant/cli/commands/serve_docs.py +128 -0
- coding_assistant/cli/repl.py +381 -0
- coding_assistant/cli/theme.py +90 -0
- coding_assistant/codebase/__init__.py +1 -0
- coding_assistant/codebase/crawler.py +93 -0
- coding_assistant/codebase/parser.py +266 -0
- coding_assistant/config/__init__.py +25 -0
- coding_assistant/config/config_manager.py +615 -0
- coding_assistant/config/settings.py +82 -0
- coding_assistant/context/__init__.py +19 -0
- coding_assistant/context/chunker.py +443 -0
- coding_assistant/context/enhanced_retriever.py +322 -0
- coding_assistant/context/hybrid_search.py +311 -0
- coding_assistant/context/ranker.py +355 -0
- coding_assistant/context/retriever.py +119 -0
- coding_assistant/context/window.py +362 -0
- coding_assistant/documentation/__init__.py +23 -0
- coding_assistant/documentation/agents/__init__.py +27 -0
- coding_assistant/documentation/agents/coordinator.py +510 -0
- coding_assistant/documentation/agents/module_documenter.py +111 -0
- coding_assistant/documentation/agents/synthesizer.py +139 -0
- coding_assistant/documentation/agents/task_delegator.py +100 -0
- coding_assistant/documentation/decomposition/__init__.py +21 -0
- coding_assistant/documentation/decomposition/context_preserver.py +477 -0
- coding_assistant/documentation/decomposition/module_detector.py +302 -0
- coding_assistant/documentation/decomposition/partitioner.py +621 -0
- coding_assistant/documentation/generators/__init__.py +14 -0
- coding_assistant/documentation/generators/dataflow_generator.py +440 -0
- coding_assistant/documentation/generators/diagram_generator.py +511 -0
- coding_assistant/documentation/graph/__init__.py +13 -0
- coding_assistant/documentation/graph/dependency_builder.py +468 -0
- coding_assistant/documentation/graph/module_analyzer.py +475 -0
- coding_assistant/documentation/writers/__init__.py +11 -0
- coding_assistant/documentation/writers/markdown_writer.py +322 -0
- coding_assistant/embeddings/__init__.py +0 -0
- coding_assistant/embeddings/generator.py +89 -0
- coding_assistant/embeddings/store.py +187 -0
- coding_assistant/exceptions/__init__.py +50 -0
- coding_assistant/exceptions/base.py +110 -0
- coding_assistant/exceptions/llm.py +249 -0
- coding_assistant/exceptions/recovery.py +263 -0
- coding_assistant/exceptions/storage.py +213 -0
- coding_assistant/exceptions/validation.py +230 -0
- coding_assistant/llm/__init__.py +1 -0
- coding_assistant/llm/client.py +277 -0
- coding_assistant/llm/gemini_client.py +181 -0
- coding_assistant/llm/groq_client.py +160 -0
- coding_assistant/llm/prompts.py +98 -0
- coding_assistant/llm/together_client.py +160 -0
- coding_assistant/operations/__init__.py +13 -0
- coding_assistant/operations/differ.py +369 -0
- coding_assistant/operations/generator.py +347 -0
- coding_assistant/operations/linter.py +430 -0
- coding_assistant/operations/validator.py +406 -0
- coding_assistant/storage/__init__.py +9 -0
- coding_assistant/storage/database.py +363 -0
- coding_assistant/storage/session.py +231 -0
- coding_assistant/utils/__init__.py +31 -0
- coding_assistant/utils/cache.py +477 -0
- coding_assistant/utils/hardware.py +132 -0
- coding_assistant/utils/keystore.py +206 -0
- coding_assistant/utils/logger.py +32 -0
- coding_assistant/utils/progress.py +311 -0
- coding_assistant/validation/__init__.py +13 -0
- coding_assistant/validation/files.py +305 -0
- coding_assistant/validation/inputs.py +335 -0
- coding_assistant/validation/params.py +280 -0
- coding_assistant/validation/sanitizers.py +243 -0
- coding_assistant/vcs/__init__.py +5 -0
- coding_assistant/vcs/git.py +269 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""Code parser using tree-sitter for better code understanding."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List, Dict, Optional
|
|
4
|
+
import tree_sitter_python as tspython
|
|
5
|
+
from tree_sitter import Language, Parser, Node
|
|
6
|
+
|
|
7
|
+
# Optional language imports - gracefully handle missing languages
|
|
8
|
+
try:
|
|
9
|
+
import tree_sitter_javascript as tsjs
|
|
10
|
+
JAVASCRIPT_AVAILABLE = True
|
|
11
|
+
except ImportError:
|
|
12
|
+
JAVASCRIPT_AVAILABLE = False
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import tree_sitter_java as tsjava
|
|
16
|
+
JAVA_AVAILABLE = True
|
|
17
|
+
except ImportError:
|
|
18
|
+
JAVA_AVAILABLE = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CodeParser:
|
|
22
|
+
"""Parse code files and extract structured information across multiple languages."""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
"""Initialize parsers for multiple programming languages."""
|
|
26
|
+
# Python (always available)
|
|
27
|
+
self.PY_LANGUAGE = Language(tspython.language())
|
|
28
|
+
|
|
29
|
+
# Initialize parsers dict
|
|
30
|
+
self.parsers = {
|
|
31
|
+
'python': Parser(self.PY_LANGUAGE)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# JavaScript/TypeScript (optional)
|
|
35
|
+
if JAVASCRIPT_AVAILABLE:
|
|
36
|
+
self.JS_LANGUAGE = Language(tsjs.language())
|
|
37
|
+
self.parsers['javascript'] = Parser(self.JS_LANGUAGE)
|
|
38
|
+
self.parsers['typescript'] = Parser(self.JS_LANGUAGE)
|
|
39
|
+
|
|
40
|
+
# Java (optional)
|
|
41
|
+
if JAVA_AVAILABLE:
|
|
42
|
+
self.JAVA_LANGUAGE = Language(tsjava.language())
|
|
43
|
+
self.parsers['java'] = Parser(self.JAVA_LANGUAGE)
|
|
44
|
+
|
|
45
|
+
# Default parser for backward compatibility
|
|
46
|
+
self.parser = self.parsers['python']
|
|
47
|
+
|
|
48
|
+
def detect_language(self, file_path: str) -> str:
|
|
49
|
+
"""
|
|
50
|
+
Detect programming language from file extension.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
file_path: Path to the file
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Language name (python, javascript, typescript, java, etc.)
|
|
57
|
+
"""
|
|
58
|
+
extension = Path(file_path).suffix.lower()
|
|
59
|
+
|
|
60
|
+
extension_map = {
|
|
61
|
+
'.py': 'python',
|
|
62
|
+
'.js': 'javascript',
|
|
63
|
+
'.jsx': 'javascript',
|
|
64
|
+
'.ts': 'typescript',
|
|
65
|
+
'.tsx': 'typescript',
|
|
66
|
+
'.java': 'java',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return extension_map.get(extension, 'python')
|
|
70
|
+
|
|
71
|
+
def parse_file(self, file_path: str, content: str, language: Optional[str] = None) -> Dict:
|
|
72
|
+
"""
|
|
73
|
+
Parse a code file and extract functions, classes, and metadata.
|
|
74
|
+
|
|
75
|
+
Supports multiple languages: Python, JavaScript, TypeScript, Java.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
file_path: Path to the file
|
|
79
|
+
content: File contents
|
|
80
|
+
language: Programming language (auto-detected if not provided)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dictionary with parsed information
|
|
84
|
+
"""
|
|
85
|
+
# Detect language if not provided
|
|
86
|
+
if language is None:
|
|
87
|
+
language = self.detect_language(file_path)
|
|
88
|
+
|
|
89
|
+
# Get appropriate parser
|
|
90
|
+
parser = self.parsers.get(language, self.parser)
|
|
91
|
+
|
|
92
|
+
# Parse the content
|
|
93
|
+
tree = parser.parse(bytes(content, "utf8"))
|
|
94
|
+
root = tree.root_node
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
'file_path': file_path,
|
|
98
|
+
'language': language,
|
|
99
|
+
'functions': self._extract_functions(root, content, language),
|
|
100
|
+
'classes': self._extract_classes(root, content, language),
|
|
101
|
+
'imports': self._extract_imports(root, content, language),
|
|
102
|
+
'chunks': self._create_chunks(root, content, file_path, language)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def _extract_functions(self, node: Node, content: str, language: str = 'python') -> List[Dict]:
|
|
106
|
+
"""Extract all function definitions (language-aware)."""
|
|
107
|
+
functions = []
|
|
108
|
+
|
|
109
|
+
# Define function node types per language
|
|
110
|
+
function_types = {
|
|
111
|
+
'python': ['function_definition'],
|
|
112
|
+
'javascript': ['function_declaration', 'function', 'arrow_function', 'method_definition'],
|
|
113
|
+
'typescript': ['function_declaration', 'function', 'arrow_function', 'method_definition'],
|
|
114
|
+
'java': ['method_declaration']
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
target_types = function_types.get(language, ['function_definition'])
|
|
118
|
+
|
|
119
|
+
def traverse(n: Node):
|
|
120
|
+
if n.type in target_types:
|
|
121
|
+
name_node = n.child_by_field_name('name')
|
|
122
|
+
if name_node:
|
|
123
|
+
functions.append({
|
|
124
|
+
'name': content[name_node.start_byte:name_node.end_byte],
|
|
125
|
+
'start_line': n.start_point[0],
|
|
126
|
+
'end_line': n.end_point[0],
|
|
127
|
+
'code': content[n.start_byte:n.end_byte]
|
|
128
|
+
})
|
|
129
|
+
elif language in ['javascript', 'typescript'] and n.type == 'arrow_function':
|
|
130
|
+
# Arrow functions might not have a name node
|
|
131
|
+
# Try to get name from parent variable declaration
|
|
132
|
+
parent = n.parent
|
|
133
|
+
if parent and parent.type == 'variable_declarator':
|
|
134
|
+
name_node = parent.child_by_field_name('name')
|
|
135
|
+
if name_node:
|
|
136
|
+
functions.append({
|
|
137
|
+
'name': content[name_node.start_byte:name_node.end_byte],
|
|
138
|
+
'start_line': n.start_point[0],
|
|
139
|
+
'end_line': n.end_point[0],
|
|
140
|
+
'code': content[n.start_byte:n.end_byte]
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
for child in n.children:
|
|
144
|
+
traverse(child)
|
|
145
|
+
|
|
146
|
+
traverse(node)
|
|
147
|
+
return functions
|
|
148
|
+
|
|
149
|
+
def _extract_classes(self, node: Node, content: str, language: str = 'python') -> List[Dict]:
|
|
150
|
+
"""Extract all class definitions (language-aware)."""
|
|
151
|
+
classes = []
|
|
152
|
+
|
|
153
|
+
# Define class node types per language
|
|
154
|
+
class_types = {
|
|
155
|
+
'python': ['class_definition'],
|
|
156
|
+
'javascript': ['class_declaration'],
|
|
157
|
+
'typescript': ['class_declaration'],
|
|
158
|
+
'java': ['class_declaration']
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
target_types = class_types.get(language, ['class_definition'])
|
|
162
|
+
|
|
163
|
+
def traverse(n: Node):
|
|
164
|
+
if n.type in target_types:
|
|
165
|
+
name_node = n.child_by_field_name('name')
|
|
166
|
+
if name_node:
|
|
167
|
+
classes.append({
|
|
168
|
+
'name': content[name_node.start_byte:name_node.end_byte],
|
|
169
|
+
'start_line': n.start_point[0],
|
|
170
|
+
'end_line': n.end_point[0],
|
|
171
|
+
'code': content[n.start_byte:n.end_byte]
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
for child in n.children:
|
|
175
|
+
traverse(child)
|
|
176
|
+
|
|
177
|
+
traverse(node)
|
|
178
|
+
return classes
|
|
179
|
+
|
|
180
|
+
def _extract_imports(self, node: Node, content: str, language: str = 'python') -> List[str]:
|
|
181
|
+
"""Extract all import statements (language-aware)."""
|
|
182
|
+
imports = []
|
|
183
|
+
|
|
184
|
+
# Define import node types per language
|
|
185
|
+
import_types = {
|
|
186
|
+
'python': ['import_statement', 'import_from_statement'],
|
|
187
|
+
'javascript': ['import_statement'],
|
|
188
|
+
'typescript': ['import_statement'],
|
|
189
|
+
'java': ['import_declaration']
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
target_types = import_types.get(language, ['import_statement', 'import_from_statement'])
|
|
193
|
+
|
|
194
|
+
def traverse(n: Node):
|
|
195
|
+
if n.type in target_types:
|
|
196
|
+
imports.append(content[n.start_byte:n.end_byte])
|
|
197
|
+
|
|
198
|
+
for child in n.children:
|
|
199
|
+
traverse(child)
|
|
200
|
+
|
|
201
|
+
traverse(node)
|
|
202
|
+
return imports
|
|
203
|
+
|
|
204
|
+
def _create_chunks(self, node: Node, content: str, file_path: str, language: str = 'python') -> List[Dict]:
|
|
205
|
+
"""
|
|
206
|
+
Create smart code chunks for embedding.
|
|
207
|
+
|
|
208
|
+
Strategy:
|
|
209
|
+
1. Each function is a chunk
|
|
210
|
+
2. Each class is a chunk
|
|
211
|
+
3. File header (imports, module docstring) is a chunk
|
|
212
|
+
"""
|
|
213
|
+
chunks = []
|
|
214
|
+
|
|
215
|
+
# Extract file header (imports + module docstring)
|
|
216
|
+
header_lines = []
|
|
217
|
+
lines = content.split('\n')
|
|
218
|
+
|
|
219
|
+
# Get module docstring if exists
|
|
220
|
+
if node.children and node.children[0].type == 'expression_statement':
|
|
221
|
+
first_expr = node.children[0]
|
|
222
|
+
if first_expr.children and first_expr.children[0].type == 'string':
|
|
223
|
+
header_lines.append(content[first_expr.start_byte:first_expr.end_byte])
|
|
224
|
+
|
|
225
|
+
# Get all imports
|
|
226
|
+
imports = self._extract_imports(node, content, language)
|
|
227
|
+
if imports:
|
|
228
|
+
header_lines.extend(imports)
|
|
229
|
+
|
|
230
|
+
if header_lines:
|
|
231
|
+
chunks.append({
|
|
232
|
+
'type': 'header',
|
|
233
|
+
'file_path': file_path,
|
|
234
|
+
'content': '\n'.join(header_lines),
|
|
235
|
+
'start_line': 0,
|
|
236
|
+
'end_line': len(header_lines),
|
|
237
|
+
'language': language
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
# Extract function chunks
|
|
241
|
+
functions = self._extract_functions(node, content, language)
|
|
242
|
+
for func in functions:
|
|
243
|
+
chunks.append({
|
|
244
|
+
'type': 'function',
|
|
245
|
+
'file_path': file_path,
|
|
246
|
+
'name': func['name'],
|
|
247
|
+
'content': func['code'],
|
|
248
|
+
'start_line': func['start_line'],
|
|
249
|
+
'end_line': func['end_line'],
|
|
250
|
+
'language': language
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
# Extract class chunks
|
|
254
|
+
classes = self._extract_classes(node, content, language)
|
|
255
|
+
for cls in classes:
|
|
256
|
+
chunks.append({
|
|
257
|
+
'type': 'class',
|
|
258
|
+
'file_path': file_path,
|
|
259
|
+
'name': cls['name'],
|
|
260
|
+
'content': cls['code'],
|
|
261
|
+
'start_line': cls['start_line'],
|
|
262
|
+
'end_line': cls['end_line'],
|
|
263
|
+
'language': language
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
return chunks
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Configuration module."""
|
|
2
|
+
|
|
3
|
+
from coding_assistant.config.config_manager import (
|
|
4
|
+
Config,
|
|
5
|
+
ConfigManager,
|
|
6
|
+
ProjectConfig,
|
|
7
|
+
LLMConfig,
|
|
8
|
+
EmbeddingConfig,
|
|
9
|
+
SearchConfig,
|
|
10
|
+
CacheConfig,
|
|
11
|
+
UIConfig,
|
|
12
|
+
StorageConfig
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
'Config',
|
|
17
|
+
'ConfigManager',
|
|
18
|
+
'ProjectConfig',
|
|
19
|
+
'LLMConfig',
|
|
20
|
+
'EmbeddingConfig',
|
|
21
|
+
'SearchConfig',
|
|
22
|
+
'CacheConfig',
|
|
23
|
+
'UIConfig',
|
|
24
|
+
'StorageConfig',
|
|
25
|
+
]
|