tree-sitter-analyzer 1.7.4__py3-none-any.whl → 1.7.7__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.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

@@ -181,6 +181,15 @@ class ListFilesTool(BaseMCPTool):
181
181
 
182
182
  @handle_mcp_errors("list_files")
183
183
  async def execute(self, arguments: dict[str, Any]) -> dict[str, Any]:
184
+ # Check if fd command is available
185
+ if not fd_rg_utils.check_external_command("fd"):
186
+ return {
187
+ "success": False,
188
+ "error": "fd command not found. Please install fd (https://github.com/sharkdp/fd) to use this tool.",
189
+ "count": 0,
190
+ "results": []
191
+ }
192
+
184
193
  self.validate_arguments(arguments)
185
194
  roots = self._validate_roots(arguments["roots"]) # normalized absolutes
186
195
 
@@ -113,17 +113,24 @@ class QueryTool(BaseMCPTool):
113
113
  if not file_path:
114
114
  raise ValueError("file_path is required")
115
115
 
116
+ # Security validation BEFORE path resolution to catch symlinks
117
+ is_valid, error_msg = self.security_validator.validate_file_path(file_path)
118
+ if not is_valid:
119
+ raise ValueError(
120
+ f"Invalid or unsafe file path: {error_msg or file_path}"
121
+ )
122
+
116
123
  # Resolve file path to absolute path
117
124
  resolved_file_path = self.path_resolver.resolve(file_path)
118
125
  logger.info(f"Querying file: {file_path} (resolved to: {resolved_file_path})")
119
126
 
120
- # Security validation using resolved path
127
+ # Additional security validation on resolved path
121
128
  is_valid, error_msg = self.security_validator.validate_file_path(
122
129
  resolved_file_path
123
130
  )
124
131
  if not is_valid:
125
132
  raise ValueError(
126
- f"Invalid or unsafe file path: {error_msg or resolved_file_path}"
133
+ f"Invalid or unsafe resolved path: {error_msg or resolved_file_path}"
127
134
  )
128
135
 
129
136
  # Get query parameters
@@ -116,34 +116,70 @@ class ReadPartialTool(BaseMCPTool):
116
116
  suppress_output = arguments.get("suppress_output", False)
117
117
  output_format = arguments.get("format", "text")
118
118
 
119
+ # Security validation BEFORE path resolution to catch symlinks
120
+ is_valid, error_msg = self.security_validator.validate_file_path(file_path, self.project_root)
121
+ if not is_valid:
122
+ logger.warning(
123
+ f"Security validation failed for file path: {file_path} - {error_msg}"
124
+ )
125
+ return {
126
+ "success": False,
127
+ "error": f"Security validation failed: {error_msg}",
128
+ "file_path": file_path
129
+ }
130
+
119
131
  # Resolve file path using common path resolver
120
132
  resolved_path = self.path_resolver.resolve(file_path)
121
133
 
122
- # Security validation (validate resolved absolute path when possible)
123
- is_valid, error_msg = self.security_validator.validate_file_path(resolved_path)
134
+ # Additional security validation on resolved path
135
+ is_valid, error_msg = self.security_validator.validate_file_path(resolved_path, self.project_root)
124
136
  if not is_valid:
125
137
  logger.warning(
126
- f"Security validation failed for file path: {file_path} - {error_msg}"
138
+ f"Security validation failed for resolved path: {resolved_path} - {error_msg}"
127
139
  )
128
- raise ValueError(f"Invalid file path: {error_msg}")
140
+ return {
141
+ "success": False,
142
+ "error": f"Security validation failed for resolved path: {error_msg}",
143
+ "file_path": file_path
144
+ }
129
145
 
130
146
  # Validate file exists
131
147
  if not Path(resolved_path).exists():
132
- raise ValueError("Invalid file path: file does not exist")
148
+ return {
149
+ "success": False,
150
+ "error": "Invalid file path: file does not exist",
151
+ "file_path": file_path
152
+ }
133
153
 
134
154
  # Validate line numbers
135
155
  if start_line < 1:
136
- raise ValueError("start_line must be >= 1")
156
+ return {
157
+ "success": False,
158
+ "error": "start_line must be >= 1",
159
+ "file_path": file_path
160
+ }
137
161
 
138
162
  if end_line is not None and end_line < start_line:
139
- raise ValueError("end_line must be >= start_line")
163
+ return {
164
+ "success": False,
165
+ "error": "end_line must be >= start_line",
166
+ "file_path": file_path
167
+ }
140
168
 
141
169
  # Validate column numbers
142
170
  if start_column is not None and start_column < 0:
143
- raise ValueError("start_column must be >= 0")
171
+ return {
172
+ "success": False,
173
+ "error": "start_column must be >= 0",
174
+ "file_path": file_path
175
+ }
144
176
 
145
177
  if end_column is not None and end_column < 0:
146
- raise ValueError("end_column must be >= 0")
178
+ return {
179
+ "success": False,
180
+ "error": "end_column must be >= 0",
181
+ "file_path": file_path
182
+ }
147
183
 
148
184
  logger.info(
149
185
  f"Reading partial content from {file_path}: lines {start_line}-{end_line or 'end'}"
@@ -160,9 +196,19 @@ class ReadPartialTool(BaseMCPTool):
160
196
  )
161
197
 
162
198
  if content is None:
163
- raise RuntimeError(
164
- f"Failed to read partial content from file: {file_path}"
165
- )
199
+ return {
200
+ "success": False,
201
+ "error": f"Failed to read partial content from file: {file_path}",
202
+ "file_path": file_path
203
+ }
204
+
205
+ # Check if content is empty or invalid range
206
+ if not content or content.strip() == "":
207
+ return {
208
+ "success": False,
209
+ "error": f"Invalid line range or empty content: start_line={start_line}, end_line={end_line}",
210
+ "file_path": file_path
211
+ }
166
212
 
167
213
  # Build result structure compatible with CLI --partial-read format
168
214
  result_data = {
@@ -198,8 +244,14 @@ class ReadPartialTool(BaseMCPTool):
198
244
  f"Successfully read {len(content)} characters from {file_path}"
199
245
  )
200
246
 
247
+ # Calculate lines extracted
248
+ lines_extracted = len(content.split('\n')) if content else 0
249
+ if end_line:
250
+ lines_extracted = end_line - start_line + 1
251
+
201
252
  # Build result - conditionally include partial_content_result based on suppress_output
202
253
  result = {
254
+ "success": True,
203
255
  "file_path": file_path,
204
256
  "range": {
205
257
  "start_line": start_line,
@@ -208,11 +260,39 @@ class ReadPartialTool(BaseMCPTool):
208
260
  "end_column": end_column,
209
261
  },
210
262
  "content_length": len(content),
263
+ "lines_extracted": lines_extracted,
211
264
  }
212
265
 
213
266
  # Only include partial_content_result if not suppressed or no output file specified
214
267
  if not suppress_output or not output_file:
215
- result["partial_content_result"] = cli_output
268
+ if output_format == "json":
269
+ # For JSON format, return structured data with exact line count
270
+ lines = content.split('\n') if content else []
271
+
272
+ # If end_line is specified, ensure we return exactly the requested number of lines
273
+ if end_line and len(lines) > lines_extracted:
274
+ lines = lines[:lines_extracted]
275
+ elif end_line and len(lines) < lines_extracted:
276
+ # Pad with empty lines if needed (shouldn't normally happen)
277
+ lines.extend([''] * (lines_extracted - len(lines)))
278
+
279
+ result["partial_content_result"] = {
280
+ "lines": lines,
281
+ "metadata": {
282
+ "file_path": file_path,
283
+ "range": {
284
+ "start_line": start_line,
285
+ "end_line": end_line,
286
+ "start_column": start_column,
287
+ "end_column": end_column,
288
+ },
289
+ "content_length": len(content),
290
+ "lines_count": len(lines)
291
+ }
292
+ }
293
+ else:
294
+ # For text/raw format, return CLI-compatible string
295
+ result["partial_content_result"] = cli_output
216
296
 
217
297
  # Handle file output if requested
218
298
  if output_file:
@@ -254,7 +334,11 @@ class ReadPartialTool(BaseMCPTool):
254
334
 
255
335
  except Exception as e:
256
336
  logger.error(f"Error reading partial content from {file_path}: {e}")
257
- raise
337
+ return {
338
+ "success": False,
339
+ "error": str(e),
340
+ "file_path": file_path
341
+ }
258
342
 
259
343
  def _read_file_partial(
260
344
  self,
@@ -289,6 +289,15 @@ class SearchContentTool(BaseMCPTool):
289
289
 
290
290
  @handle_mcp_errors("search_content")
291
291
  async def execute(self, arguments: dict[str, Any]) -> dict[str, Any] | int:
292
+ # Check if rg command is available
293
+ if not fd_rg_utils.check_external_command("rg"):
294
+ return {
295
+ "success": False,
296
+ "error": "rg (ripgrep) command not found. Please install ripgrep (https://github.com/BurntSushi/ripgrep) to use this tool.",
297
+ "count": 0,
298
+ "results": []
299
+ }
300
+
292
301
  self.validate_arguments(arguments)
293
302
 
294
303
  roots = arguments.get("roots")
@@ -242,6 +242,7 @@ class TableFormatTool(BaseMCPTool):
242
242
  package_info = {"name": packages[0].name}
243
243
 
244
244
  return {
245
+ "success": True,
245
246
  "file_path": result.file_path,
246
247
  "language": result.language,
247
248
  "package": package_info,
@@ -378,18 +379,26 @@ class TableFormatTool(BaseMCPTool):
378
379
  output_file = args.get("output_file")
379
380
  suppress_output = args.get("suppress_output", False)
380
381
 
382
+ # Security validation BEFORE path resolution to catch symlinks
383
+ is_valid, error_msg = self.security_validator.validate_file_path(file_path)
384
+ if not is_valid:
385
+ self.logger.warning(
386
+ f"Security validation failed for file path: {file_path} - {error_msg}"
387
+ )
388
+ raise ValueError(f"Invalid file path: {error_msg}")
389
+
381
390
  # Resolve file path using common path resolver
382
391
  resolved_path = self.path_resolver.resolve(file_path)
383
392
 
384
- # Security validation
393
+ # Additional security validation on resolved path
385
394
  is_valid, error_msg = self.security_validator.validate_file_path(
386
395
  resolved_path
387
396
  )
388
397
  if not is_valid:
389
398
  self.logger.warning(
390
- f"Security validation failed for file path: {file_path} - {error_msg}"
399
+ f"Security validation failed for resolved path: {resolved_path} - {error_msg}"
391
400
  )
392
- raise ValueError(f"Invalid file path: {error_msg}")
401
+ raise ValueError(f"Invalid resolved path: {error_msg}")
393
402
 
394
403
  # Sanitize format_type input
395
404
  if format_type:
@@ -470,6 +479,7 @@ class TableFormatTool(BaseMCPTool):
470
479
 
471
480
  # Build result - conditionally include table_output based on suppress_output
472
481
  result = {
482
+ "success": True,
473
483
  "format_type": format_type,
474
484
  "file_path": file_path,
475
485
  "language": language,
@@ -100,12 +100,13 @@ class SecurityValidator:
100
100
 
101
101
  # Layer 4: Absolute path check (cross-platform)
102
102
  if Path(file_path).is_absolute() or file_path.startswith(("/", "\\")):
103
+ log_debug(f"Processing absolute path: {file_path}")
103
104
  # If project boundaries are configured, enforce them strictly
104
105
  if self.boundary_manager and self.boundary_manager.project_root:
105
106
  if not self.boundary_manager.is_within_project(file_path):
106
107
  return False, "Absolute path must be within project directory"
107
- # Within project
108
- return True, ""
108
+ # Within project - continue with symlink checks
109
+ log_debug("Absolute path is within project, continuing with symlink checks")
109
110
  else:
110
111
  # In test/dev contexts without project boundaries, allow absolute
111
112
  # paths under system temp folder only (safe sandbox)
@@ -113,12 +114,13 @@ class SecurityValidator:
113
114
 
114
115
  temp_dir = Path(tempfile.gettempdir()).resolve()
115
116
  real_path = Path(file_path).resolve()
117
+ log_debug(f"Checking if {real_path} is under temp dir {temp_dir}")
116
118
  try:
117
119
  real_path.relative_to(temp_dir)
118
- return True, ""
120
+ log_debug("Path is under temp directory, continuing with symlink checks")
121
+ # Don't return here - continue with symlink checks
119
122
  except ValueError:
120
- pass
121
- return False, "Absolute file paths are not allowed"
123
+ return False, "Absolute file paths are not allowed"
122
124
 
123
125
  # Layer 5: Path normalization and traversal check
124
126
  norm_path = str(Path(file_path))
@@ -136,12 +138,69 @@ class SecurityValidator:
136
138
  "Access denied. File path must be within project directory",
137
139
  )
138
140
 
139
- # Layer 7: Symbolic link check (if file exists)
141
+ # Layer 7: Symbolic link and junction check (check both original and resolved paths)
142
+ # First check the original file_path directly for symlinks and junctions
143
+ try:
144
+ original_path = Path(file_path)
145
+ log_debug(f"Checking symlink status for original path: {original_path}")
146
+ # Check for symlinks even if the file doesn't exist yet (broken symlinks)
147
+ is_symlink = original_path.is_symlink()
148
+ log_debug(f"original_path.is_symlink() = {is_symlink}")
149
+ if is_symlink:
150
+ log_warning(f"Symbolic link detected in original path: {original_path}")
151
+ return False, "Symbolic links are not allowed"
152
+
153
+ # Additional check for Windows junctions and reparse points (only if exists)
154
+ if original_path.exists() and self._is_junction_or_reparse_point(original_path):
155
+ log_warning(f"Junction or reparse point detected in original path: {original_path}")
156
+ return False, "Junctions and reparse points are not allowed"
157
+
158
+ except (OSError, PermissionError) as e:
159
+ # If we can't check symlink status, continue with other checks
160
+ log_debug(f"Exception checking symlink status: {e}")
161
+ pass
162
+
163
+ # Then check the full path (base_path + norm_path) if base_path is provided
140
164
  if base_path:
141
165
  full_path = Path(base_path) / norm_path
142
- if full_path.exists() and full_path.is_symlink():
143
- log_warning(f"Symbolic link detected: {full_path}")
144
- return False, "Symbolic links are not allowed"
166
+
167
+ # Check if the full path is a symlink or junction
168
+ try:
169
+ # Check for symlinks even if the file doesn't exist yet (broken symlinks)
170
+ if full_path.is_symlink():
171
+ log_warning(f"Symbolic link detected: {full_path}")
172
+ return False, "Symbolic links are not allowed"
173
+
174
+ # Additional check for Windows junctions and reparse points (only if exists)
175
+ if full_path.exists() and self._is_junction_or_reparse_point(full_path):
176
+ log_warning(f"Junction or reparse point detected: {full_path}")
177
+ return False, "Junctions and reparse points are not allowed"
178
+
179
+ except (OSError, PermissionError):
180
+ # If we can't check symlink status due to permissions, be cautious
181
+ log_warning(f"Cannot verify symlink status for: {full_path}")
182
+ pass
183
+
184
+ # Check parent directories for junctions (Windows-specific security measure)
185
+ try:
186
+ if self._has_junction_in_path(full_path):
187
+ log_warning(f"Junction detected in path hierarchy: {full_path}")
188
+ return False, "Paths containing junctions are not allowed"
189
+ except (OSError, PermissionError):
190
+ # If we can't check parent directories, continue
191
+ pass
192
+ else:
193
+ # For absolute paths or when no base_path is provided, use original_path
194
+ full_path = original_path
195
+
196
+ # Check parent directories for junctions
197
+ try:
198
+ if self._has_junction_in_path(full_path):
199
+ log_warning(f"Junction detected in path hierarchy: {full_path}")
200
+ return False, "Paths containing junctions are not allowed"
201
+ except (OSError, PermissionError):
202
+ # If we can't check parent directories, continue
203
+ pass
145
204
 
146
205
  log_debug(f"File path validation passed: {file_path}")
147
206
  return True, ""
@@ -268,3 +327,103 @@ class SecurityValidator:
268
327
  except Exception as e:
269
328
  log_warning(f"Glob pattern validation error: {e}")
270
329
  return False, f"Validation error: {str(e)}"
330
+
331
+ def validate_path(self, path: str, base_path: str | None = None) -> tuple[bool, str]:
332
+ """
333
+ Alias for validate_file_path for backward compatibility.
334
+
335
+ Args:
336
+ path: Path to validate
337
+ base_path: Optional base path for relative path validation
338
+
339
+ Returns:
340
+ Tuple of (is_valid, error_message)
341
+ """
342
+ return self.validate_file_path(path, base_path)
343
+
344
+ def is_safe_path(self, path: str, base_path: str | None = None) -> bool:
345
+ """
346
+ Check if a path is safe (backward compatibility method).
347
+
348
+ Args:
349
+ path: Path to check
350
+ base_path: Optional base path for relative path validation
351
+
352
+ Returns:
353
+ True if path is safe, False otherwise
354
+ """
355
+ is_valid, _ = self.validate_file_path(path, base_path)
356
+ return is_valid
357
+
358
+ def _is_junction_or_reparse_point(self, path: Path) -> bool:
359
+ """
360
+ Check if a path is a Windows junction or reparse point.
361
+
362
+ Args:
363
+ path: Path to check
364
+
365
+ Returns:
366
+ True if the path is a junction or reparse point
367
+ """
368
+ try:
369
+ import platform
370
+ if platform.system() != "Windows":
371
+ return False
372
+
373
+ # On Windows, check for reparse points using stat
374
+ import stat
375
+ if path.exists():
376
+ path_stat = path.stat()
377
+ # Check if it has the reparse point attribute
378
+ if hasattr(stat, 'FILE_ATTRIBUTE_REPARSE_POINT'):
379
+ return bool(path_stat.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT)
380
+
381
+ # Alternative method using Windows API
382
+ try:
383
+ import ctypes
384
+ from ctypes import wintypes
385
+
386
+ # GetFileAttributesW function
387
+ _GetFileAttributesW = ctypes.windll.kernel32.GetFileAttributesW
388
+ _GetFileAttributesW.argtypes = [wintypes.LPCWSTR]
389
+ _GetFileAttributesW.restype = wintypes.DWORD
390
+
391
+ FILE_ATTRIBUTE_REPARSE_POINT = 0x400
392
+ INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF
393
+
394
+ attributes = _GetFileAttributesW(str(path))
395
+ if attributes != INVALID_FILE_ATTRIBUTES:
396
+ return bool(attributes & FILE_ATTRIBUTE_REPARSE_POINT)
397
+
398
+ except (ImportError, AttributeError, OSError):
399
+ pass
400
+
401
+ except Exception:
402
+ # If any error occurs, assume it's not a junction for safety
403
+ pass
404
+
405
+ return False
406
+
407
+ def _has_junction_in_path(self, path: Path) -> bool:
408
+ """
409
+ Check if any parent directory in the path is a junction.
410
+
411
+ Args:
412
+ path: Path to check
413
+
414
+ Returns:
415
+ True if any parent directory is a junction
416
+ """
417
+ try:
418
+ current_path = path.resolve() if path.exists() else path
419
+
420
+ # Check each parent directory
421
+ for parent in current_path.parents:
422
+ if self._is_junction_or_reparse_point(parent):
423
+ return True
424
+
425
+ except Exception:
426
+ # If any error occurs, assume no junctions for safety
427
+ pass
428
+
429
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tree-sitter-analyzer
3
- Version: 1.7.4
3
+ Version: 1.7.7
4
4
  Summary: Extensible multi-language code analyzer framework using Tree-sitter with dynamic plugin architecture
5
5
  Project-URL: Homepage, https://github.com/aimasteracc/tree-sitter-analyzer
6
6
  Project-URL: Documentation, https://github.com/aimasteracc/tree-sitter-analyzer#readme
@@ -34,6 +34,7 @@ Requires-Python: >=3.10
34
34
  Requires-Dist: cachetools>=5.0.0
35
35
  Requires-Dist: chardet>=5.0.0
36
36
  Requires-Dist: mcp>=1.12.3
37
+ Requires-Dist: psutil>=5.9.8
37
38
  Requires-Dist: tree-sitter-cpp<0.25.0,>=0.23.4
38
39
  Requires-Dist: tree-sitter-java<0.25.0,>=0.23.5
39
40
  Requires-Dist: tree-sitter-javascript<0.25.0,>=0.23.1
@@ -123,6 +124,21 @@ Requires-Dist: tree-sitter-typescript<0.25.0,>=0.20.0; extra == 'full'
123
124
  Requires-Dist: types-psutil>=5.9.0; extra == 'full'
124
125
  Provides-Extra: go
125
126
  Requires-Dist: tree-sitter-go<0.25.0,>=0.20.0; extra == 'go'
127
+ Provides-Extra: integration
128
+ Requires-Dist: anyio>=4.0.0; extra == 'integration'
129
+ Requires-Dist: mcp>=1.12.2; extra == 'integration'
130
+ Requires-Dist: memory-profiler>=0.61.0; extra == 'integration'
131
+ Requires-Dist: psutil>=5.9.8; extra == 'integration'
132
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'integration'
133
+ Requires-Dist: pytest-benchmark>=4.0.0; extra == 'integration'
134
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'integration'
135
+ Requires-Dist: pytest-mock>=3.14.1; extra == 'integration'
136
+ Requires-Dist: pytest>=8.4.1; extra == 'integration'
137
+ Requires-Dist: tree-sitter-java>=0.23.5; extra == 'integration'
138
+ Requires-Dist: tree-sitter-javascript>=0.23.1; extra == 'integration'
139
+ Requires-Dist: tree-sitter-markdown>=0.3.1; extra == 'integration'
140
+ Requires-Dist: tree-sitter-python>=0.23.0; extra == 'integration'
141
+ Requires-Dist: tree-sitter-typescript>=0.20.0; extra == 'integration'
126
142
  Provides-Extra: java
127
143
  Requires-Dist: tree-sitter-java<0.25.0,>=0.23.5; extra == 'java'
128
144
  Provides-Extra: javascript
@@ -171,11 +187,12 @@ Description-Content-Type: text/markdown
171
187
 
172
188
  [![Python Version](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
173
189
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
174
- [![Tests](https://img.shields.io/badge/tests-2934%20passed-brightgreen.svg)](#quality-assurance)
175
- [![Coverage](https://img.shields.io/badge/coverage-80.09%25-green.svg)](#quality-assurance)
190
+ [![Tests](https://img.shields.io/badge/tests-3088%20passed-brightgreen.svg)](#quality-assurance)
191
+ [![Coverage](https://codecov.io/gh/aimasteracc/tree-sitter-analyzer/branch/main/graph/badge.svg)](https://codecov.io/gh/aimasteracc/tree-sitter-analyzer)
176
192
  [![Quality](https://img.shields.io/badge/quality-enterprise%20grade-blue.svg)](#quality-assurance)
177
193
  [![PyPI](https://img.shields.io/pypi/v/tree-sitter-analyzer.svg)](https://pypi.org/project/tree-sitter-analyzer/)
178
- [![Version](https://img.shields.io/badge/version-1.7.4-blue.svg)](https://github.com/aimasteracc/tree-sitter-analyzer/releases)
194
+ [![Version](https://img.shields.io/badge/version-1.7.5-blue.svg)](https://github.com/aimasteracc/tree-sitter-analyzer/releases)
195
+ [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/aimasteracc/tree-sitter-analyzer)
179
196
  [![GitHub Stars](https://img.shields.io/github/stars/aimasteracc/tree-sitter-analyzer.svg?style=social)](https://github.com/aimasteracc/tree-sitter-analyzer)
180
197
 
181
198
  ## 🚀 Enterprise-Grade Code Analysis Tool for the AI Era
@@ -225,8 +242,8 @@ Tree-sitter Analyzer is an enterprise-grade code analysis tool designed for the
225
242
  | **Go** | Basic Support | Basic syntax parsing |
226
243
 
227
244
  ### 🏆 Production Ready
228
- - **2,934 Tests** - 100% pass rate, enterprise-grade quality assurance
229
- - **80.09% Coverage** - Comprehensive test coverage
245
+ - **3,088 Tests** - 100% pass rate, enterprise-grade quality assurance
246
+ - **High Coverage** - Comprehensive test coverage
230
247
  - **Cross-platform Support** - Compatible with Windows, macOS, Linux
231
248
  - **Continuous Maintenance** - Active development and community support
232
249
 
@@ -736,13 +753,13 @@ uv run python -m tree_sitter_analyzer --show-query-languages
736
753
  ## 8. 🏆 Quality Assurance
737
754
 
738
755
  ### 📊 Quality Metrics
739
- - **2,934 tests** - 100% pass rate ✅
740
- - **80.09% code coverage** - Comprehensive test suite
756
+ - **3,088 tests** - 100% pass rate ✅
757
+ - **High code coverage** - Comprehensive test suite
741
758
  - **Zero test failures** - Production ready
742
759
  - **Cross-platform support** - Windows, macOS, Linux
743
760
 
744
- ### ⚡ Latest Quality Achievements (v1.7.4)
745
- - ✅ **📊 Enhanced Quality Metrics** - Test count increased to 2934 (up from 2831), coverage improved to 80.09%
761
+ ### ⚡ Latest Quality Achievements (v1.7.5)
762
+ - ✅ **📊 Enhanced Quality Metrics** - Test count increased to 3,088 coverage maintained at high levels
746
763
  - ✅ **🔧 System Stability** - All tests passing with enhanced system stability and reliability
747
764
  - ✅ **🆕 Complete Markdown Support** - Added new complete Markdown language plugin supporting all major Markdown elements
748
765
  - ✅ **📝 Enhanced Document Analysis** - Support for intelligent extraction of headers, code blocks, links, images, tables, task lists
@@ -772,19 +789,15 @@ uv run pytest tests/test_mcp_server_initialization.py -v
772
789
 
773
790
  ### 📈 Test Coverage Details
774
791
 
775
- | Module Category | Module Name | Coverage | Quality Level | Main Features |
776
- |------------------|-------------|-----------|---------------|---------------|
777
- | **🔧 Core Modules** | Language Detector | 98.41% | Excellent | Automatic programming language recognition |
778
- | | CLI Main Entry | 94.36% | Excellent | Command line interface |
779
- | | Query Filter System | 96.06% | Excellent | Code querying and filtering |
780
- | | Query Service | 86.25% | Good | Query execution engine |
781
- | | MCP Error Handling | 82.76% | Good | AI assistant integration error handling |
782
- | **🌍 Language Plugins** | Java Plugin | 80.30% | Excellent | Complete enterprise-grade support |
783
- | | JavaScript Plugin | 76.74% | Good | Modern ES6+ feature support |
784
- | | Python Plugin | 82.84% | Excellent | Complete type annotation support |
785
- | **🤖 MCP Tools** | File Search Tool | 88.77% | Excellent | fd/ripgrep integration |
786
- | | Content Search Tool | 92.70% | Excellent | Regular expression search |
787
- | | Combined Search Tool | 91.57% | Excellent | Two-stage search |
792
+ The project maintains high-quality test coverage. For detailed module coverage information, please visit:
793
+
794
+ [![Coverage Details](https://codecov.io/gh/aimasteracc/tree-sitter-analyzer/branch/main/graph/badge.svg)](https://codecov.io/gh/aimasteracc/tree-sitter-analyzer)
795
+
796
+ **Click the badge above to view:**
797
+ - 📊 **Module-by-Module Coverage** - Detailed coverage statistics for each module
798
+ - 📈 **Coverage Trends** - Historical coverage change trends
799
+ - 🔍 **Uncovered Code Lines** - Specific locations of untested code
800
+ - 📋 **Detailed Reports** - Complete coverage analysis reports
788
801
 
789
802
  ### ✅ Documentation Verification Status
790
803
 
@@ -797,7 +810,7 @@ uv run pytest tests/test_mcp_server_initialization.py -v
797
810
  **Verification environment:**
798
811
  - Operating systems: Windows 10, macOS, Linux
799
812
  - Python version: 3.10+
800
- - Project version: tree-sitter-analyzer v1.7.4
813
+ - Project version: tree-sitter-analyzer v1.7.5
801
814
  - Test files: BigService.java (1419 lines), sample.py (256 lines), MultiClass.java (54 lines)
802
815
 
803
816
  ---
@@ -805,26 +818,22 @@ uv run pytest tests/test_mcp_server_initialization.py -v
805
818
  ## 9. 📚 Documentation & Support
806
819
 
807
820
  ### 📖 Complete Documentation
808
- - **[User MCP Setup Guide](MCP_SETUP_USERS.md)** - Simple setup guide
809
- - **[Developer MCP Setup Guide](MCP_SETUP_DEVELOPERS.md)** - Local development setup
810
- - **[Project Root Configuration](PROJECT_ROOT_CONFIG.md)** - Complete configuration reference
811
- - **[API Documentation](docs/api.md)** - Detailed API reference
812
- - **[Contributing Guide](CONTRIBUTING.md)** - How to contribute code
813
- - **[Onboarding & Training Guide](training/README.md)** - System onboarding materials for new members/maintainers
821
+ This project provides complete documentation support, including:
822
+
823
+ - **Quick Start Guide** - See the [Quick Start](#3--quick-start) section of this README
824
+ - **MCP Configuration Guide** - See the [AI Users Configuration](#31--ai-users-claude-desktop-cursor-etc) section
825
+ - **CLI Usage Guide** - See the [Complete CLI Commands](#6--complete-cli-commands) section
826
+ - **Core Features Documentation** - See the [Core Features](#7-️-core-features) section
814
827
 
815
828
  ### 🤖 AI Collaboration Support
816
829
  This project supports AI-assisted development with professional quality control:
817
830
 
818
831
  ```bash
819
- # AI system pre-generation checks
832
+ # AI system code generation pre-checks
820
833
  uv run python check_quality.py --new-code-only
821
834
  uv run python llm_code_checker.py --check-all
822
835
  ```
823
836
 
824
- 📖 **Detailed guides**:
825
- - [AI Collaboration Guide](AI_COLLABORATION_GUIDE.md)
826
- - [LLM Coding Guidelines](LLM_CODING_GUIDELINES.md)
827
-
828
837
  ### 💝 Sponsors & Acknowledgments
829
838
 
830
839
  **[@o93](https://github.com/o93)** - *Lead Sponsor & Supporter*