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.
Files changed (89) hide show
  1. ai_coding_assistant-0.5.0.dist-info/METADATA +226 -0
  2. ai_coding_assistant-0.5.0.dist-info/RECORD +89 -0
  3. ai_coding_assistant-0.5.0.dist-info/WHEEL +4 -0
  4. ai_coding_assistant-0.5.0.dist-info/entry_points.txt +3 -0
  5. ai_coding_assistant-0.5.0.dist-info/licenses/LICENSE +21 -0
  6. coding_assistant/__init__.py +3 -0
  7. coding_assistant/__main__.py +19 -0
  8. coding_assistant/cli/__init__.py +1 -0
  9. coding_assistant/cli/app.py +158 -0
  10. coding_assistant/cli/commands/__init__.py +19 -0
  11. coding_assistant/cli/commands/ask.py +178 -0
  12. coding_assistant/cli/commands/config.py +438 -0
  13. coding_assistant/cli/commands/diagram.py +267 -0
  14. coding_assistant/cli/commands/document.py +410 -0
  15. coding_assistant/cli/commands/explain.py +192 -0
  16. coding_assistant/cli/commands/fix.py +249 -0
  17. coding_assistant/cli/commands/index.py +162 -0
  18. coding_assistant/cli/commands/refactor.py +245 -0
  19. coding_assistant/cli/commands/search.py +182 -0
  20. coding_assistant/cli/commands/serve_docs.py +128 -0
  21. coding_assistant/cli/repl.py +381 -0
  22. coding_assistant/cli/theme.py +90 -0
  23. coding_assistant/codebase/__init__.py +1 -0
  24. coding_assistant/codebase/crawler.py +93 -0
  25. coding_assistant/codebase/parser.py +266 -0
  26. coding_assistant/config/__init__.py +25 -0
  27. coding_assistant/config/config_manager.py +615 -0
  28. coding_assistant/config/settings.py +82 -0
  29. coding_assistant/context/__init__.py +19 -0
  30. coding_assistant/context/chunker.py +443 -0
  31. coding_assistant/context/enhanced_retriever.py +322 -0
  32. coding_assistant/context/hybrid_search.py +311 -0
  33. coding_assistant/context/ranker.py +355 -0
  34. coding_assistant/context/retriever.py +119 -0
  35. coding_assistant/context/window.py +362 -0
  36. coding_assistant/documentation/__init__.py +23 -0
  37. coding_assistant/documentation/agents/__init__.py +27 -0
  38. coding_assistant/documentation/agents/coordinator.py +510 -0
  39. coding_assistant/documentation/agents/module_documenter.py +111 -0
  40. coding_assistant/documentation/agents/synthesizer.py +139 -0
  41. coding_assistant/documentation/agents/task_delegator.py +100 -0
  42. coding_assistant/documentation/decomposition/__init__.py +21 -0
  43. coding_assistant/documentation/decomposition/context_preserver.py +477 -0
  44. coding_assistant/documentation/decomposition/module_detector.py +302 -0
  45. coding_assistant/documentation/decomposition/partitioner.py +621 -0
  46. coding_assistant/documentation/generators/__init__.py +14 -0
  47. coding_assistant/documentation/generators/dataflow_generator.py +440 -0
  48. coding_assistant/documentation/generators/diagram_generator.py +511 -0
  49. coding_assistant/documentation/graph/__init__.py +13 -0
  50. coding_assistant/documentation/graph/dependency_builder.py +468 -0
  51. coding_assistant/documentation/graph/module_analyzer.py +475 -0
  52. coding_assistant/documentation/writers/__init__.py +11 -0
  53. coding_assistant/documentation/writers/markdown_writer.py +322 -0
  54. coding_assistant/embeddings/__init__.py +0 -0
  55. coding_assistant/embeddings/generator.py +89 -0
  56. coding_assistant/embeddings/store.py +187 -0
  57. coding_assistant/exceptions/__init__.py +50 -0
  58. coding_assistant/exceptions/base.py +110 -0
  59. coding_assistant/exceptions/llm.py +249 -0
  60. coding_assistant/exceptions/recovery.py +263 -0
  61. coding_assistant/exceptions/storage.py +213 -0
  62. coding_assistant/exceptions/validation.py +230 -0
  63. coding_assistant/llm/__init__.py +1 -0
  64. coding_assistant/llm/client.py +277 -0
  65. coding_assistant/llm/gemini_client.py +181 -0
  66. coding_assistant/llm/groq_client.py +160 -0
  67. coding_assistant/llm/prompts.py +98 -0
  68. coding_assistant/llm/together_client.py +160 -0
  69. coding_assistant/operations/__init__.py +13 -0
  70. coding_assistant/operations/differ.py +369 -0
  71. coding_assistant/operations/generator.py +347 -0
  72. coding_assistant/operations/linter.py +430 -0
  73. coding_assistant/operations/validator.py +406 -0
  74. coding_assistant/storage/__init__.py +9 -0
  75. coding_assistant/storage/database.py +363 -0
  76. coding_assistant/storage/session.py +231 -0
  77. coding_assistant/utils/__init__.py +31 -0
  78. coding_assistant/utils/cache.py +477 -0
  79. coding_assistant/utils/hardware.py +132 -0
  80. coding_assistant/utils/keystore.py +206 -0
  81. coding_assistant/utils/logger.py +32 -0
  82. coding_assistant/utils/progress.py +311 -0
  83. coding_assistant/validation/__init__.py +13 -0
  84. coding_assistant/validation/files.py +305 -0
  85. coding_assistant/validation/inputs.py +335 -0
  86. coding_assistant/validation/params.py +280 -0
  87. coding_assistant/validation/sanitizers.py +243 -0
  88. coding_assistant/vcs/__init__.py +5 -0
  89. coding_assistant/vcs/git.py +269 -0
@@ -0,0 +1,406 @@
1
+ """Syntax validation for Python and JavaScript/TypeScript code."""
2
+
3
+ import ast
4
+ import sys
5
+ from typing import Dict, Optional, Tuple
6
+ from pathlib import Path
7
+
8
+
9
+ class ValidationResult:
10
+ """Result of syntax validation."""
11
+
12
+ def __init__(self, is_valid: bool, error_message: Optional[str] = None,
13
+ line: Optional[int] = None, column: Optional[int] = None):
14
+ self.is_valid = is_valid
15
+ self.error_message = error_message
16
+ self.line = line
17
+ self.column = column
18
+
19
+ def __bool__(self):
20
+ return self.is_valid
21
+
22
+ def __repr__(self):
23
+ if self.is_valid:
24
+ return "ValidationResult(valid=True)"
25
+ return f"ValidationResult(valid=False, line={self.line}, error={self.error_message})"
26
+
27
+
28
+ class SyntaxValidator:
29
+ """Validate syntax for Python and JavaScript/TypeScript code."""
30
+
31
+ SUPPORTED_LANGUAGES = {'python', 'javascript', 'typescript', 'jsx', 'tsx'}
32
+
33
+ def __init__(self):
34
+ """Initialize the syntax validator."""
35
+ self._tree_sitter_available = False
36
+ self._ts_parser = None
37
+ self._js_language = None
38
+ self._ts_language = None
39
+
40
+ # Try to initialize tree-sitter for JS/TS
41
+ try:
42
+ from tree_sitter import Language, Parser
43
+ # Check if language libraries are built
44
+ # This would need tree-sitter language grammars pre-built
45
+ self._tree_sitter_available = True
46
+ except ImportError:
47
+ pass
48
+
49
+ def validate(self, code: str, language: str,
50
+ file_path: Optional[str] = None) -> ValidationResult:
51
+ """
52
+ Validate code syntax for the given language.
53
+
54
+ Args:
55
+ code: The source code to validate
56
+ language: The programming language (python, javascript, typescript)
57
+ file_path: Optional file path for better error messages
58
+
59
+ Returns:
60
+ ValidationResult indicating if code is valid
61
+
62
+ Raises:
63
+ ValueError: If language is not supported
64
+ """
65
+ language = language.lower()
66
+
67
+ if language not in self.SUPPORTED_LANGUAGES:
68
+ raise ValueError(
69
+ f"Unsupported language: {language}. "
70
+ f"Supported: {', '.join(self.SUPPORTED_LANGUAGES)}"
71
+ )
72
+
73
+ if language == 'python':
74
+ return self._validate_python(code, file_path)
75
+ elif language in ('javascript', 'jsx'):
76
+ return self._validate_javascript(code, file_path)
77
+ elif language in ('typescript', 'tsx'):
78
+ return self._validate_typescript(code, file_path)
79
+
80
+ def _validate_python(self, code: str,
81
+ file_path: Optional[str] = None) -> ValidationResult:
82
+ """
83
+ Validate Python code using AST parsing.
84
+
85
+ This provides the most accurate validation for Python code.
86
+ """
87
+ if not code.strip():
88
+ return ValidationResult(False, "Empty code", line=1, column=1)
89
+
90
+ try:
91
+ # First try: compile to check syntax
92
+ compile(code, file_path or '<string>', 'exec')
93
+
94
+ # Second try: parse AST for deeper validation
95
+ ast.parse(code, filename=file_path or '<string>')
96
+
97
+ return ValidationResult(True)
98
+
99
+ except SyntaxError as e:
100
+ return ValidationResult(
101
+ is_valid=False,
102
+ error_message=f"SyntaxError: {e.msg}",
103
+ line=e.lineno,
104
+ column=e.offset
105
+ )
106
+ except IndentationError as e:
107
+ return ValidationResult(
108
+ is_valid=False,
109
+ error_message=f"IndentationError: {e.msg}",
110
+ line=e.lineno,
111
+ column=e.offset
112
+ )
113
+ except Exception as e:
114
+ return ValidationResult(
115
+ is_valid=False,
116
+ error_message=f"Error: {str(e)}",
117
+ line=None,
118
+ column=None
119
+ )
120
+
121
+ def _validate_javascript(self, code: str,
122
+ file_path: Optional[str] = None) -> ValidationResult:
123
+ """
124
+ Validate JavaScript code.
125
+
126
+ Uses tree-sitter if available, otherwise basic heuristics.
127
+ """
128
+ if not code.strip():
129
+ return ValidationResult(False, "Empty code", line=1, column=1)
130
+
131
+ # Try tree-sitter first (most accurate)
132
+ if self._tree_sitter_available:
133
+ return self._validate_with_tree_sitter(code, 'javascript', file_path)
134
+
135
+ # Fallback: Try using Node.js if available
136
+ result = self._validate_with_nodejs(code, file_path)
137
+ if result:
138
+ return result
139
+
140
+ # Last resort: Basic syntax checks
141
+ return self._basic_javascript_validation(code)
142
+
143
+ def _validate_typescript(self, code: str,
144
+ file_path: Optional[str] = None) -> ValidationResult:
145
+ """
146
+ Validate TypeScript code.
147
+
148
+ Uses tree-sitter if available, otherwise tries tsc.
149
+ """
150
+ if not code.strip():
151
+ return ValidationResult(False, "Empty code", line=1, column=1)
152
+
153
+ # Try tree-sitter first
154
+ if self._tree_sitter_available:
155
+ return self._validate_with_tree_sitter(code, 'typescript', file_path)
156
+
157
+ # Fallback: Try TypeScript compiler if available
158
+ result = self._validate_with_tsc(code, file_path)
159
+ if result:
160
+ return result
161
+
162
+ # TypeScript is superset of JavaScript, try JS validation
163
+ return self._validate_javascript(code, file_path)
164
+
165
+ def _validate_with_tree_sitter(self, code: str, language: str,
166
+ file_path: Optional[str] = None) -> ValidationResult:
167
+ """Validate using tree-sitter parser."""
168
+ try:
169
+ from tree_sitter import Language, Parser
170
+
171
+ # Initialize parser if needed
172
+ if not self._ts_parser:
173
+ self._ts_parser = Parser()
174
+
175
+ # This requires pre-built language files
176
+ # For now, return a basic validation result
177
+ # TODO: Build tree-sitter language grammars
178
+ return ValidationResult(
179
+ is_valid=True,
180
+ error_message="Tree-sitter validation not fully implemented yet"
181
+ )
182
+
183
+ except Exception as e:
184
+ # If tree-sitter fails, don't block - return warning
185
+ return ValidationResult(
186
+ is_valid=True,
187
+ error_message=f"Tree-sitter validation unavailable: {e}"
188
+ )
189
+
190
+ def _validate_with_nodejs(self, code: str,
191
+ file_path: Optional[str] = None) -> Optional[ValidationResult]:
192
+ """Validate JavaScript using Node.js if available."""
193
+ import subprocess
194
+ import tempfile
195
+ import os
196
+
197
+ try:
198
+ # Create temp file with code
199
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
200
+ f.write(code)
201
+ temp_path = f.name
202
+
203
+ try:
204
+ # Try to parse with Node.js (--check flag)
205
+ result = subprocess.run(
206
+ ['node', '--check', temp_path],
207
+ capture_output=True,
208
+ text=True,
209
+ timeout=5
210
+ )
211
+
212
+ if result.returncode == 0:
213
+ return ValidationResult(True)
214
+ else:
215
+ # Parse error message
216
+ error_msg = result.stderr.strip()
217
+ return self._parse_nodejs_error(error_msg)
218
+
219
+ finally:
220
+ # Clean up temp file
221
+ os.unlink(temp_path)
222
+
223
+ except FileNotFoundError:
224
+ # Node.js not available
225
+ return None
226
+ except Exception:
227
+ return None
228
+
229
+ def _validate_with_tsc(self, code: str,
230
+ file_path: Optional[str] = None) -> Optional[ValidationResult]:
231
+ """Validate TypeScript using tsc if available."""
232
+ import subprocess
233
+ import tempfile
234
+ import os
235
+
236
+ try:
237
+ # Create temp file with code
238
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.ts', delete=False) as f:
239
+ f.write(code)
240
+ temp_path = f.name
241
+
242
+ try:
243
+ # Try to compile with TypeScript compiler
244
+ result = subprocess.run(
245
+ ['npx', 'tsc', '--noEmit', temp_path],
246
+ capture_output=True,
247
+ text=True,
248
+ timeout=10
249
+ )
250
+
251
+ if result.returncode == 0:
252
+ return ValidationResult(True)
253
+ else:
254
+ # Parse error message
255
+ error_msg = result.stdout.strip()
256
+ return self._parse_tsc_error(error_msg)
257
+
258
+ finally:
259
+ # Clean up temp file
260
+ os.unlink(temp_path)
261
+
262
+ except FileNotFoundError:
263
+ # tsc not available
264
+ return None
265
+ except Exception:
266
+ return None
267
+
268
+ def _basic_javascript_validation(self, code: str) -> ValidationResult:
269
+ """
270
+ Basic JavaScript syntax validation using heuristics.
271
+
272
+ This is a fallback when no proper parser is available.
273
+ """
274
+ lines = code.split('\n')
275
+
276
+ # Basic bracket matching
277
+ stack = []
278
+ bracket_pairs = {'(': ')', '[': ']', '{': '}'}
279
+
280
+ for line_num, line in enumerate(lines, 1):
281
+ # Skip comments
282
+ if line.strip().startswith('//'):
283
+ continue
284
+
285
+ for col_num, char in enumerate(line, 1):
286
+ if char in bracket_pairs:
287
+ stack.append((char, line_num, col_num))
288
+ elif char in bracket_pairs.values():
289
+ if not stack:
290
+ return ValidationResult(
291
+ is_valid=False,
292
+ error_message=f"Unexpected closing bracket '{char}'",
293
+ line=line_num,
294
+ column=col_num
295
+ )
296
+ opening, _, _ = stack.pop()
297
+ if bracket_pairs[opening] != char:
298
+ return ValidationResult(
299
+ is_valid=False,
300
+ error_message=f"Mismatched brackets: '{opening}' and '{char}'",
301
+ line=line_num,
302
+ column=col_num
303
+ )
304
+
305
+ if stack:
306
+ char, line_num, col_num = stack[-1]
307
+ return ValidationResult(
308
+ is_valid=False,
309
+ error_message=f"Unclosed bracket '{char}'",
310
+ line=line_num,
311
+ column=col_num
312
+ )
313
+
314
+ # If basic checks pass, assume valid
315
+ # (This is not comprehensive but better than nothing)
316
+ return ValidationResult(True)
317
+
318
+ def _parse_nodejs_error(self, error_msg: str) -> ValidationResult:
319
+ """Parse Node.js error message."""
320
+ # Node.js errors typically format as: file:line
321
+ # Example: "SyntaxError: Unexpected token '}'"
322
+ try:
323
+ if 'SyntaxError' in error_msg:
324
+ return ValidationResult(
325
+ is_valid=False,
326
+ error_message=error_msg.split('\n')[0],
327
+ line=None,
328
+ column=None
329
+ )
330
+ except:
331
+ pass
332
+
333
+ return ValidationResult(
334
+ is_valid=False,
335
+ error_message=error_msg[:200], # Limit message length
336
+ line=None,
337
+ column=None
338
+ )
339
+
340
+ def _parse_tsc_error(self, error_msg: str) -> ValidationResult:
341
+ """Parse TypeScript compiler error message."""
342
+ # tsc errors format: file(line,col): error TS####: message
343
+ try:
344
+ if error_msg:
345
+ return ValidationResult(
346
+ is_valid=False,
347
+ error_message=error_msg.split('\n')[0],
348
+ line=None,
349
+ column=None
350
+ )
351
+ except:
352
+ pass
353
+
354
+ return ValidationResult(
355
+ is_valid=False,
356
+ error_message=error_msg[:200],
357
+ line=None,
358
+ column=None
359
+ )
360
+
361
+ def validate_file(self, file_path: str) -> ValidationResult:
362
+ """
363
+ Validate a file based on its extension.
364
+
365
+ Args:
366
+ file_path: Path to the file to validate
367
+
368
+ Returns:
369
+ ValidationResult
370
+ """
371
+ path = Path(file_path)
372
+
373
+ if not path.exists():
374
+ return ValidationResult(
375
+ is_valid=False,
376
+ error_message=f"File not found: {file_path}"
377
+ )
378
+
379
+ # Determine language from extension
380
+ extension = path.suffix.lower()
381
+ language_map = {
382
+ '.py': 'python',
383
+ '.js': 'javascript',
384
+ '.jsx': 'jsx',
385
+ '.ts': 'typescript',
386
+ '.tsx': 'tsx',
387
+ '.mjs': 'javascript',
388
+ '.cjs': 'javascript',
389
+ }
390
+
391
+ language = language_map.get(extension)
392
+ if not language:
393
+ return ValidationResult(
394
+ is_valid=False,
395
+ error_message=f"Unsupported file extension: {extension}"
396
+ )
397
+
398
+ # Read and validate
399
+ try:
400
+ code = path.read_text(encoding='utf-8')
401
+ return self.validate(code, language, str(file_path))
402
+ except Exception as e:
403
+ return ValidationResult(
404
+ is_valid=False,
405
+ error_message=f"Error reading file: {e}"
406
+ )
@@ -0,0 +1,9 @@
1
+ """Storage module for session persistence."""
2
+
3
+ from coding_assistant.storage.database import Database
4
+ from coding_assistant.storage.session import SessionManager
5
+
6
+ __all__ = [
7
+ 'Database',
8
+ 'SessionManager',
9
+ ]