tree-sitter-analyzer 1.8.2__py3-none-any.whl → 1.8.4__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.
- tree_sitter_analyzer/__init__.py +1 -1
- tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py +12 -1
- tree_sitter_analyzer/mcp/tools/query_tool.py +2 -2
- tree_sitter_analyzer/mcp/tools/search_content_tool.py +12 -1
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +2 -2
- tree_sitter_analyzer/mcp/utils/file_output_factory.py +204 -0
- tree_sitter_analyzer/mcp/utils/file_output_manager.py +52 -2
- tree_sitter_analyzer/utils.py +66 -19
- {tree_sitter_analyzer-1.8.2.dist-info → tree_sitter_analyzer-1.8.4.dist-info}/METADATA +37 -25
- {tree_sitter_analyzer-1.8.2.dist-info → tree_sitter_analyzer-1.8.4.dist-info}/RECORD +12 -11
- {tree_sitter_analyzer-1.8.2.dist-info → tree_sitter_analyzer-1.8.4.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.8.2.dist-info → tree_sitter_analyzer-1.8.4.dist-info}/entry_points.txt +0 -0
tree_sitter_analyzer/__init__.py
CHANGED
|
@@ -27,7 +27,18 @@ class FindAndGrepTool(BaseMCPTool):
|
|
|
27
27
|
def __init__(self, project_root: str | None = None) -> None:
|
|
28
28
|
"""Initialize the find and grep tool."""
|
|
29
29
|
super().__init__(project_root)
|
|
30
|
-
self.file_output_manager = FileOutputManager(project_root)
|
|
30
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_root)
|
|
31
|
+
|
|
32
|
+
def set_project_path(self, project_path: str) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Update the project path for all components.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
project_path: New project root directory
|
|
38
|
+
"""
|
|
39
|
+
super().set_project_path(project_path)
|
|
40
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_path)
|
|
41
|
+
logger.info(f"FindAndGrepTool project path updated to: {project_path}")
|
|
31
42
|
|
|
32
43
|
def get_tool_definition(self) -> dict[str, Any]:
|
|
33
44
|
return {
|
|
@@ -26,7 +26,7 @@ class QueryTool(BaseMCPTool):
|
|
|
26
26
|
"""Initialize query tool"""
|
|
27
27
|
super().__init__(project_root)
|
|
28
28
|
self.query_service = QueryService(project_root)
|
|
29
|
-
self.file_output_manager = FileOutputManager(project_root)
|
|
29
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_root)
|
|
30
30
|
|
|
31
31
|
def set_project_path(self, project_path: str) -> None:
|
|
32
32
|
"""
|
|
@@ -37,7 +37,7 @@ class QueryTool(BaseMCPTool):
|
|
|
37
37
|
"""
|
|
38
38
|
super().set_project_path(project_path)
|
|
39
39
|
self.query_service = QueryService(project_path)
|
|
40
|
-
self.file_output_manager.
|
|
40
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_path)
|
|
41
41
|
logger.info(f"QueryTool project path updated to: {project_path}")
|
|
42
42
|
|
|
43
43
|
def get_tool_definition(self) -> dict[str, Any]:
|
|
@@ -37,7 +37,18 @@ class SearchContentTool(BaseMCPTool):
|
|
|
37
37
|
"""
|
|
38
38
|
super().__init__(project_root)
|
|
39
39
|
self.cache = get_default_cache() if enable_cache else None
|
|
40
|
-
self.file_output_manager = FileOutputManager(project_root)
|
|
40
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_root)
|
|
41
|
+
|
|
42
|
+
def set_project_path(self, project_path: str) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Update the project path for all components.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
project_path: New project root directory
|
|
48
|
+
"""
|
|
49
|
+
super().set_project_path(project_path)
|
|
50
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_path)
|
|
51
|
+
logger.info(f"SearchContentTool project path updated to: {project_path}")
|
|
41
52
|
|
|
42
53
|
def get_tool_definition(self) -> dict[str, Any]:
|
|
43
54
|
return {
|
|
@@ -42,7 +42,7 @@ class TableFormatTool(BaseMCPTool):
|
|
|
42
42
|
"""Initialize the table format tool."""
|
|
43
43
|
super().__init__(project_root)
|
|
44
44
|
self.analysis_engine = get_analysis_engine(project_root)
|
|
45
|
-
self.file_output_manager = FileOutputManager(project_root)
|
|
45
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_root)
|
|
46
46
|
self.logger = logger
|
|
47
47
|
|
|
48
48
|
def set_project_path(self, project_path: str) -> None:
|
|
@@ -54,7 +54,7 @@ class TableFormatTool(BaseMCPTool):
|
|
|
54
54
|
"""
|
|
55
55
|
super().set_project_path(project_path)
|
|
56
56
|
self.analysis_engine = get_analysis_engine(project_path)
|
|
57
|
-
self.file_output_manager.
|
|
57
|
+
self.file_output_manager = FileOutputManager.get_managed_instance(project_path)
|
|
58
58
|
logger.info(f"TableFormatTool project path updated to: {project_path}")
|
|
59
59
|
|
|
60
60
|
def get_tool_schema(self) -> dict[str, Any]:
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
File Output Manager Factory
|
|
4
|
+
|
|
5
|
+
This module provides a Managed Singleton Factory Pattern for FileOutputManager
|
|
6
|
+
to prevent duplicate initialization and ensure consistent instance management
|
|
7
|
+
across MCP tools.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import threading
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, Optional
|
|
13
|
+
|
|
14
|
+
from ...utils import setup_logger
|
|
15
|
+
from .file_output_manager import FileOutputManager
|
|
16
|
+
|
|
17
|
+
# Set up logging
|
|
18
|
+
logger = setup_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FileOutputManagerFactory:
|
|
22
|
+
"""
|
|
23
|
+
Factory class that manages FileOutputManager instances using a Managed Singleton
|
|
24
|
+
pattern. Each project root gets its own singleton instance, ensuring consistency
|
|
25
|
+
across MCP tools while preventing duplicate initialization.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Class-level lock for thread safety
|
|
29
|
+
_lock = threading.RLock()
|
|
30
|
+
|
|
31
|
+
# Dictionary to store instances by project root
|
|
32
|
+
_instances: Dict[str, FileOutputManager] = {}
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def get_instance(cls, project_root: Optional[str] = None) -> FileOutputManager:
|
|
36
|
+
"""
|
|
37
|
+
Get or create a FileOutputManager instance for the specified project root.
|
|
38
|
+
|
|
39
|
+
This method implements the Managed Singleton pattern - one instance per
|
|
40
|
+
project root, ensuring consistency across all MCP tools.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
project_root: Project root directory. If None, uses current working directory.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
FileOutputManager instance for the specified project root
|
|
47
|
+
"""
|
|
48
|
+
# Normalize project root path
|
|
49
|
+
normalized_root = cls._normalize_project_root(project_root)
|
|
50
|
+
|
|
51
|
+
# Double-checked locking pattern for thread safety
|
|
52
|
+
if normalized_root not in cls._instances:
|
|
53
|
+
with cls._lock:
|
|
54
|
+
if normalized_root not in cls._instances:
|
|
55
|
+
logger.info(f"Creating new FileOutputManager instance for project root: {normalized_root}")
|
|
56
|
+
cls._instances[normalized_root] = FileOutputManager(normalized_root)
|
|
57
|
+
else:
|
|
58
|
+
logger.debug(f"Using existing FileOutputManager instance for project root: {normalized_root}")
|
|
59
|
+
else:
|
|
60
|
+
logger.debug(f"Using existing FileOutputManager instance for project root: {normalized_root}")
|
|
61
|
+
|
|
62
|
+
return cls._instances[normalized_root]
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def _normalize_project_root(cls, project_root: Optional[str]) -> str:
|
|
66
|
+
"""
|
|
67
|
+
Normalize project root path for consistent key generation.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
project_root: Raw project root path
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Normalized absolute path string
|
|
74
|
+
"""
|
|
75
|
+
if project_root is None:
|
|
76
|
+
return str(Path.cwd().resolve())
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
return str(Path(project_root).resolve())
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(f"Failed to resolve project root path '{project_root}': {e}")
|
|
82
|
+
return str(Path.cwd().resolve())
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def clear_instance(cls, project_root: Optional[str] = None) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
Clear a specific FileOutputManager instance from the factory.
|
|
88
|
+
|
|
89
|
+
This method is primarily for testing purposes or when you need to
|
|
90
|
+
force recreation of an instance.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
project_root: Project root directory. If None, uses current working directory.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
True if instance was cleared, False if it didn't exist
|
|
97
|
+
"""
|
|
98
|
+
normalized_root = cls._normalize_project_root(project_root)
|
|
99
|
+
|
|
100
|
+
with cls._lock:
|
|
101
|
+
if normalized_root in cls._instances:
|
|
102
|
+
logger.info(f"Clearing FileOutputManager instance for project root: {normalized_root}")
|
|
103
|
+
del cls._instances[normalized_root]
|
|
104
|
+
return True
|
|
105
|
+
else:
|
|
106
|
+
logger.debug(f"No FileOutputManager instance found for project root: {normalized_root}")
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def clear_all_instances(cls) -> int:
|
|
111
|
+
"""
|
|
112
|
+
Clear all FileOutputManager instances from the factory.
|
|
113
|
+
|
|
114
|
+
This method is primarily for testing purposes or cleanup.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Number of instances that were cleared
|
|
118
|
+
"""
|
|
119
|
+
with cls._lock:
|
|
120
|
+
count = len(cls._instances)
|
|
121
|
+
if count > 0:
|
|
122
|
+
logger.info(f"Clearing all {count} FileOutputManager instances")
|
|
123
|
+
cls._instances.clear()
|
|
124
|
+
else:
|
|
125
|
+
logger.debug("No FileOutputManager instances to clear")
|
|
126
|
+
return count
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def get_instance_count(cls) -> int:
|
|
130
|
+
"""
|
|
131
|
+
Get the current number of managed instances.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Number of currently managed FileOutputManager instances
|
|
135
|
+
"""
|
|
136
|
+
with cls._lock:
|
|
137
|
+
return len(cls._instances)
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def get_managed_project_roots(cls) -> list[str]:
|
|
141
|
+
"""
|
|
142
|
+
Get list of all currently managed project roots.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
List of project root paths that have managed instances
|
|
146
|
+
"""
|
|
147
|
+
with cls._lock:
|
|
148
|
+
return list(cls._instances.keys())
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def update_project_root(cls, old_root: Optional[str], new_root: str) -> bool:
|
|
152
|
+
"""
|
|
153
|
+
Update the project root for an existing instance.
|
|
154
|
+
|
|
155
|
+
This method moves an existing instance from one project root key to another,
|
|
156
|
+
and updates the instance's internal project root.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
old_root: Current project root (None for current working directory)
|
|
160
|
+
new_root: New project root
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
True if update was successful, False if old instance didn't exist
|
|
164
|
+
"""
|
|
165
|
+
old_normalized = cls._normalize_project_root(old_root)
|
|
166
|
+
new_normalized = cls._normalize_project_root(new_root)
|
|
167
|
+
|
|
168
|
+
if old_normalized == new_normalized:
|
|
169
|
+
logger.debug(f"Project root update not needed: {old_normalized}")
|
|
170
|
+
return True
|
|
171
|
+
|
|
172
|
+
with cls._lock:
|
|
173
|
+
if old_normalized in cls._instances:
|
|
174
|
+
instance = cls._instances[old_normalized]
|
|
175
|
+
|
|
176
|
+
# Update the instance's internal project root
|
|
177
|
+
instance.set_project_root(new_root)
|
|
178
|
+
|
|
179
|
+
# Move to new key
|
|
180
|
+
cls._instances[new_normalized] = instance
|
|
181
|
+
del cls._instances[old_normalized]
|
|
182
|
+
|
|
183
|
+
logger.info(f"Updated FileOutputManager project root: {old_normalized} -> {new_normalized}")
|
|
184
|
+
return True
|
|
185
|
+
else:
|
|
186
|
+
logger.warning(f"No FileOutputManager instance found for old project root: {old_normalized}")
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# Convenience function for backward compatibility and ease of use
|
|
191
|
+
def get_file_output_manager(project_root: Optional[str] = None) -> FileOutputManager:
|
|
192
|
+
"""
|
|
193
|
+
Convenience function to get a FileOutputManager instance.
|
|
194
|
+
|
|
195
|
+
This function provides a simple interface to the factory while maintaining
|
|
196
|
+
the singleton behavior per project root.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
project_root: Project root directory. If None, uses current working directory.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
FileOutputManager instance for the specified project root
|
|
203
|
+
"""
|
|
204
|
+
return FileOutputManagerFactory.get_instance(project_root)
|
|
@@ -4,12 +4,15 @@ File Output Manager for MCP Tools
|
|
|
4
4
|
|
|
5
5
|
This module provides functionality to save analysis results to files with
|
|
6
6
|
appropriate extensions based on content type, with security validation.
|
|
7
|
+
|
|
8
|
+
Enhanced with Managed Singleton Factory Pattern support for consistent
|
|
9
|
+
instance management across MCP tools.
|
|
7
10
|
"""
|
|
8
11
|
|
|
9
12
|
import json
|
|
10
13
|
import os
|
|
11
14
|
from pathlib import Path
|
|
12
|
-
from typing import Any
|
|
15
|
+
from typing import Any, Optional
|
|
13
16
|
|
|
14
17
|
from ...utils import setup_logger
|
|
15
18
|
|
|
@@ -21,9 +24,12 @@ class FileOutputManager:
|
|
|
21
24
|
"""
|
|
22
25
|
Manages file output for analysis results with automatic extension detection
|
|
23
26
|
and security validation.
|
|
27
|
+
|
|
28
|
+
Enhanced with factory method support for consistent instance management
|
|
29
|
+
across MCP tools while maintaining full backward compatibility.
|
|
24
30
|
"""
|
|
25
31
|
|
|
26
|
-
def __init__(self, project_root: str
|
|
32
|
+
def __init__(self, project_root: Optional[str] = None):
|
|
27
33
|
"""
|
|
28
34
|
Initialize the file output manager.
|
|
29
35
|
|
|
@@ -33,6 +39,50 @@ class FileOutputManager:
|
|
|
33
39
|
self.project_root = project_root
|
|
34
40
|
self._output_path = None
|
|
35
41
|
self._initialize_output_path()
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def get_managed_instance(cls, project_root: Optional[str] = None) -> 'FileOutputManager':
|
|
45
|
+
"""
|
|
46
|
+
Get a managed FileOutputManager instance using the factory pattern.
|
|
47
|
+
|
|
48
|
+
This method provides access to the Managed Singleton Factory Pattern,
|
|
49
|
+
ensuring one instance per project root for optimal resource usage
|
|
50
|
+
and consistency across MCP tools.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
project_root: Project root directory. If None, uses current working directory.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
FileOutputManager instance managed by the factory
|
|
57
|
+
|
|
58
|
+
Note:
|
|
59
|
+
This method requires the factory module to be available. If the factory
|
|
60
|
+
is not available, it falls back to creating a new instance directly.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
# Import here to avoid circular imports
|
|
64
|
+
from .file_output_factory import FileOutputManagerFactory
|
|
65
|
+
return FileOutputManagerFactory.get_instance(project_root)
|
|
66
|
+
except ImportError as e:
|
|
67
|
+
logger.warning(f"Factory not available, creating new instance directly: {e}")
|
|
68
|
+
return cls(project_root)
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def create_instance(cls, project_root: Optional[str] = None) -> 'FileOutputManager':
|
|
72
|
+
"""
|
|
73
|
+
Create a new FileOutputManager instance directly (bypass factory).
|
|
74
|
+
|
|
75
|
+
This method creates a new instance without using the factory pattern.
|
|
76
|
+
Use this when you specifically need a separate instance that won't
|
|
77
|
+
be managed by the factory.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
project_root: Project root directory. If None, uses current working directory.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
New FileOutputManager instance
|
|
84
|
+
"""
|
|
85
|
+
return cls(project_root)
|
|
36
86
|
|
|
37
87
|
def _initialize_output_path(self) -> None:
|
|
38
88
|
"""Initialize the output path from environment variables or project root."""
|
tree_sitter_analyzer/utils.py
CHANGED
|
@@ -9,7 +9,9 @@ import atexit
|
|
|
9
9
|
import logging
|
|
10
10
|
import os
|
|
11
11
|
import sys
|
|
12
|
+
import tempfile
|
|
12
13
|
from functools import wraps
|
|
14
|
+
from pathlib import Path
|
|
13
15
|
from typing import Any
|
|
14
16
|
|
|
15
17
|
|
|
@@ -51,6 +53,10 @@ def setup_logger(
|
|
|
51
53
|
if name.startswith("test_"):
|
|
52
54
|
logger.handlers.clear()
|
|
53
55
|
|
|
56
|
+
# Initialize file logging variables at function scope
|
|
57
|
+
enable_file_log = os.environ.get("TREE_SITTER_ANALYZER_ENABLE_FILE_LOG", "").lower() == "true"
|
|
58
|
+
file_log_level = level # Default to main logger level
|
|
59
|
+
|
|
54
60
|
if not logger.handlers: # Avoid duplicate handlers
|
|
55
61
|
# Create a safe handler that writes to stderr to avoid breaking MCP stdio
|
|
56
62
|
handler = SafeStreamHandler()
|
|
@@ -60,27 +66,68 @@ def setup_logger(
|
|
|
60
66
|
handler.setFormatter(formatter)
|
|
61
67
|
logger.addHandler(handler)
|
|
62
68
|
|
|
63
|
-
#
|
|
69
|
+
# Optional file logging for debugging when launched by clients (e.g., Cursor)
|
|
64
70
|
# This helps diagnose cases where stdio is captured by the client and logs are hidden.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
# Only enabled when TREE_SITTER_ANALYZER_ENABLE_FILE_LOG is set to 'true'
|
|
72
|
+
if enable_file_log:
|
|
73
|
+
try:
|
|
74
|
+
# Determine log directory
|
|
75
|
+
log_dir = os.environ.get("TREE_SITTER_ANALYZER_LOG_DIR")
|
|
76
|
+
if log_dir:
|
|
77
|
+
# Use specified directory
|
|
78
|
+
log_path = Path(log_dir) / "tree_sitter_analyzer.log"
|
|
79
|
+
# Ensure directory exists
|
|
80
|
+
Path(log_dir).mkdir(parents=True, exist_ok=True)
|
|
81
|
+
else:
|
|
82
|
+
# Use system temporary directory
|
|
83
|
+
temp_dir = tempfile.gettempdir()
|
|
84
|
+
log_path = Path(temp_dir) / "tree_sitter_analyzer.log"
|
|
85
|
+
|
|
86
|
+
# Determine file log level
|
|
87
|
+
file_log_level_str = os.environ.get("TREE_SITTER_ANALYZER_FILE_LOG_LEVEL", "").upper()
|
|
88
|
+
if file_log_level_str and file_log_level_str in ["DEBUG", "INFO", "WARNING", "ERROR"]:
|
|
89
|
+
if file_log_level_str == "DEBUG":
|
|
90
|
+
file_log_level = logging.DEBUG
|
|
91
|
+
elif file_log_level_str == "INFO":
|
|
92
|
+
file_log_level = logging.INFO
|
|
93
|
+
elif file_log_level_str == "WARNING":
|
|
94
|
+
file_log_level = logging.WARNING
|
|
95
|
+
elif file_log_level_str == "ERROR":
|
|
96
|
+
file_log_level = logging.ERROR
|
|
97
|
+
else:
|
|
98
|
+
# Use same level as main logger
|
|
99
|
+
file_log_level = level
|
|
100
|
+
|
|
101
|
+
file_handler = logging.FileHandler(str(log_path), encoding="utf-8")
|
|
102
|
+
file_handler.setFormatter(formatter)
|
|
103
|
+
file_handler.setLevel(file_log_level)
|
|
104
|
+
logger.addHandler(file_handler)
|
|
105
|
+
|
|
106
|
+
# Log the file location for debugging purposes
|
|
107
|
+
if hasattr(sys, "stderr") and hasattr(sys.stderr, "write"):
|
|
108
|
+
try:
|
|
109
|
+
sys.stderr.write(f"[logging_setup] File logging enabled: {log_path}\n")
|
|
110
|
+
except Exception:
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
except Exception as e:
|
|
114
|
+
# Never let logging configuration break runtime behavior; log to stderr if possible
|
|
115
|
+
if hasattr(sys, "stderr") and hasattr(sys.stderr, "write"):
|
|
116
|
+
try:
|
|
117
|
+
sys.stderr.write(
|
|
118
|
+
f"[logging_setup] file handler init skipped: {e}\n"
|
|
119
|
+
)
|
|
120
|
+
except Exception:
|
|
121
|
+
...
|
|
80
122
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
|
|
123
|
+
# Set the logger level to the minimum of main level and file log level
|
|
124
|
+
# This ensures that all messages that should go to any handler are processed
|
|
125
|
+
final_level = level
|
|
126
|
+
if enable_file_log:
|
|
127
|
+
# Use the minimum level to ensure all messages reach their intended handlers
|
|
128
|
+
final_level = min(level, file_log_level)
|
|
129
|
+
|
|
130
|
+
logger.setLevel(final_level)
|
|
84
131
|
|
|
85
132
|
# For test loggers, ensure they don't inherit from parent and force level
|
|
86
133
|
if logger.name.startswith("test_"):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tree-sitter-analyzer
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.4
|
|
4
4
|
Summary: AI-era enterprise-grade code analysis tool with comprehensive HTML/CSS support, dynamic plugin architecture, and MCP integration
|
|
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
|
|
@@ -198,11 +198,11 @@ Description-Content-Type: text/markdown
|
|
|
198
198
|
|
|
199
199
|
[](https://python.org)
|
|
200
200
|
[](LICENSE)
|
|
201
|
-
[](#quality-assurance)
|
|
202
202
|
[](https://codecov.io/gh/aimasteracc/tree-sitter-analyzer)
|
|
203
203
|
[](#quality-assurance)
|
|
204
204
|
[](https://pypi.org/project/tree-sitter-analyzer/)
|
|
205
|
-
[](https://github.com/aimasteracc/tree-sitter-analyzer/releases)
|
|
206
206
|
[](https://zread.ai/aimasteracc/tree-sitter-analyzer)
|
|
207
207
|
[](https://github.com/aimasteracc/tree-sitter-analyzer)
|
|
208
208
|
|
|
@@ -255,7 +255,7 @@ Tree-sitter Analyzer is an enterprise-grade code analysis tool designed for the
|
|
|
255
255
|
| **Go** | Basic Support | Basic syntax parsing |
|
|
256
256
|
|
|
257
257
|
### 🏆 Production Ready
|
|
258
|
-
- **3,
|
|
258
|
+
- **3,380 Tests** - 100% pass rate, enterprise-grade quality assurance
|
|
259
259
|
- **High Coverage** - Comprehensive test coverage
|
|
260
260
|
- **Cross-platform Support** - Compatible with Windows, macOS, Linux
|
|
261
261
|
- **Continuous Maintenance** - Active development and community support
|
|
@@ -373,6 +373,7 @@ rg --version
|
|
|
373
373
|
- **Roo Code**: Supports MCP protocol, use the same configuration format
|
|
374
374
|
- **Other MCP-compatible clients**: Use the same server configuration
|
|
375
375
|
|
|
376
|
+
|
|
376
377
|
---
|
|
377
378
|
|
|
378
379
|
### 3.2 💻 CLI Users (Command Line Tools)
|
|
@@ -633,13 +634,37 @@ Tree-sitter Analyzer provides a rich set of MCP tools designed for AI assistants
|
|
|
633
634
|
| | `analyze_code_structure` | Code structure analysis and table generation | 🆕 suppress_output parameter, multiple formats (full/compact/csv/json/html), automatic language detection |
|
|
634
635
|
| | `extract_code_section` | Precise code section extraction | Specified line range extraction, large file efficient processing, original format preservation |
|
|
635
636
|
| **🔍 Intelligent Search** | `list_files` | High-performance file discovery | fd-based, glob patterns, file type filters, time range control |
|
|
636
|
-
| | `search_content` | Regex content search | ripgrep-based, multiple output formats, context control, encoding handling |
|
|
637
|
-
| | `find_and_grep` | Two-stage search | File discovery → content search, fd+ripgrep combination, intelligent cache optimization |
|
|
637
|
+
| | `search_content` | Regex content search | ripgrep-based, multiple output formats, context control, encoding handling, 🆕 unified `set_project_path` support |
|
|
638
|
+
| | `find_and_grep` | Two-stage search | File discovery → content search, fd+ripgrep combination, intelligent cache optimization, 🆕 unified `set_project_path` support |
|
|
638
639
|
| **🔧 Advanced Queries** | `query_code` | tree-sitter queries | Predefined query keys, custom query strings, filter expression support |
|
|
639
|
-
| **⚙️ System Management** | `set_project_path` | Project root path setting | Security boundary control, automatic path validation |
|
|
640
|
+
| **⚙️ System Management** | `set_project_path` | Project root path setting | Security boundary control, automatic path validation, 🆕 unified across all MCP tools |
|
|
640
641
|
| **📁 Resource Access** | Code file resources | URI code file access | File content access via URI identification |
|
|
641
642
|
| | Project statistics resources | Project statistics data access | Project analysis data and statistical information |
|
|
642
643
|
|
|
644
|
+
### 🆕 v1.8.4 New Feature: Configurable File Logging
|
|
645
|
+
|
|
646
|
+
Revolutionary environment variable-controlled file logging system:
|
|
647
|
+
|
|
648
|
+
- **🔧 Environment Variable Control**: Flexible file logging behavior control through environment variables
|
|
649
|
+
- `TREE_SITTER_ANALYZER_ENABLE_FILE_LOG`: Enable/disable file logging
|
|
650
|
+
- `TREE_SITTER_ANALYZER_LOG_DIR`: Custom log directory path
|
|
651
|
+
- `TREE_SITTER_ANALYZER_FILE_LOG_LEVEL`: Control file log level
|
|
652
|
+
- **🛡️ Improved Default Behavior**: File logging disabled by default to prevent user project pollution
|
|
653
|
+
- **📁 Smart Directory Selection**: Uses system temp directory when enabled, keeping projects clean
|
|
654
|
+
- **🔄 Backward Compatibility**: Maintains all existing functionality unchanged
|
|
655
|
+
- **📚 Complete Documentation Support**: Includes debugging guides and troubleshooting documentation
|
|
656
|
+
|
|
657
|
+
### 🆕 v1.8.3 New Feature: MCP Tools Design Consistency Enhancement
|
|
658
|
+
|
|
659
|
+
Comprehensive MCP tools unification and design consistency improvements:
|
|
660
|
+
|
|
661
|
+
- **🔧 Unified `set_project_path` Implementation**: SearchContentTool and FindAndGrepTool now have consistent `set_project_path` method implementation
|
|
662
|
+
- **🏗️ Design Consistency Across All MCP Tools**: All 4 MCP tools (QueryTool, TableFormatTool, SearchContentTool, FindAndGrepTool) now have unified interface design
|
|
663
|
+
- **📁 FileOutputManager Integration**: Unified FileOutputManager factory pattern for consistent file output management
|
|
664
|
+
- **🔄 Dynamic Project Path Changes**: All MCP tools now support dynamic project path changes through unified interface
|
|
665
|
+
- **🛡️ Enhanced Security Boundaries**: Consistent security boundary protection across all MCP tools
|
|
666
|
+
- **📋 Improved Developer Experience**: Unified interface makes MCP tool development and usage more consistent
|
|
667
|
+
|
|
643
668
|
### 🆕 v1.8.2 New Feature: CLI Security and Argument Validation Enhancement
|
|
644
669
|
|
|
645
670
|
Comprehensive CLI security improvements and argument validation optimization:
|
|
@@ -848,12 +873,12 @@ uv run python -m tree_sitter_analyzer --show-query-languages
|
|
|
848
873
|
## 8. 🏆 Quality Assurance
|
|
849
874
|
|
|
850
875
|
### 📊 Quality Metrics
|
|
851
|
-
- **3,
|
|
876
|
+
- **3,380 tests** - 100% pass rate ✅
|
|
852
877
|
- **High code coverage** - Comprehensive test suite
|
|
853
878
|
- **Zero test failures** - Production ready
|
|
854
879
|
- **Cross-platform support** - Windows, macOS, Linux
|
|
855
880
|
|
|
856
|
-
### ⚡ Latest Quality Achievements (v1.8.
|
|
881
|
+
### ⚡ Latest Quality Achievements (v1.8.3)
|
|
857
882
|
- ✅ **🔒 CLI Security Enhancement** - Fixed CLI mode security boundary errors, ensuring file access security
|
|
858
883
|
- ✅ **✅ Argument Validation Improvement** - Implemented complete CLI argument validation system, preventing invalid parameter combinations
|
|
859
884
|
- ✅ **🚫 Exclusive Parameter Control** - `--table` and `--query-key` parameters properly implement exclusive control
|
|
@@ -863,22 +888,6 @@ uv run python -m tree_sitter_analyzer --show-query-languages
|
|
|
863
888
|
- ✅ **🧪 Test Environment Support** - Temporary directory access permission in test environments
|
|
864
889
|
- ✅ **📋 User Experience Improvement** - More intuitive command-line interface and error handling mechanisms
|
|
865
890
|
|
|
866
|
-
### ⚡ v1.7.5 Quality Achievements
|
|
867
|
-
- ✅ **📊 Enhanced Quality Metrics** - Test count increased to 3,342 coverage maintained at high levels
|
|
868
|
-
- ✅ **🔧 System Stability** - All tests passing with enhanced system stability and reliability
|
|
869
|
-
- ✅ **🆕 Complete Markdown Support** - Added new complete Markdown language plugin supporting all major Markdown elements
|
|
870
|
-
- ✅ **📝 Enhanced Document Analysis** - Support for intelligent extraction of headers, code blocks, links, images, tables, task lists
|
|
871
|
-
- ✅ **🔍 Markdown Query System** - 17 predefined query types with alias and custom query support
|
|
872
|
-
- ✅ **🧪 Comprehensive Test Validation** - Added extensive Markdown test cases ensuring feature stability
|
|
873
|
-
- ✅ **📊 Structured Output** - Convert Markdown documents to structured data for easy AI processing
|
|
874
|
-
- ✅ **File output optimization** - MCP search tools now include `suppress_output` and `output_file` parameters for massive token savings
|
|
875
|
-
- ✅ **Intelligent format detection** - Automatic selection of optimal file formats (JSON/Markdown) for storage and reading optimization
|
|
876
|
-
- ✅ **ROO rules documentation** - Added comprehensive tree-sitter-analyzer MCP optimization usage guide
|
|
877
|
-
- ✅ **Enhanced token management** - Response size reduced by up to 99% when outputting search results to files
|
|
878
|
-
- ✅ **Enterprise-grade test coverage** - Comprehensive test suite including complete validation of file output optimization features
|
|
879
|
-
- ✅ **Complete MCP tools** - Complete MCP server tool set supporting advanced file search and content analysis
|
|
880
|
-
- ✅ **Cross-platform path compatibility** - Fixed differences between Windows short path names and macOS symbolic links
|
|
881
|
-
- ✅ **GitFlow implementation** - Professional development/release branch strategy
|
|
882
891
|
|
|
883
892
|
### ⚙️ Running Tests
|
|
884
893
|
```bash
|
|
@@ -930,6 +939,9 @@ This project provides complete documentation support, including:
|
|
|
930
939
|
- **MCP Configuration Guide** - See the [AI Users Configuration](#31--ai-users-claude-desktop-cursor-etc) section
|
|
931
940
|
- **CLI Usage Guide** - See the [Complete CLI Commands](#6--complete-cli-commands) section
|
|
932
941
|
- **Core Features Documentation** - See the [Core Features](#7-️-core-features) section
|
|
942
|
+
- **Contributing Guide** - See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development guidelines and document management
|
|
943
|
+
- **Analysis Results** - See [docs/analysis/](docs/analysis/) for project analysis reports and metrics
|
|
944
|
+
- **Feature Specifications** - See [specs/](specs/) for detailed feature specifications and implementation plans
|
|
933
945
|
|
|
934
946
|
### 🤖 AI Collaboration Support
|
|
935
947
|
This project supports AI-assisted development with professional quality control:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
tree_sitter_analyzer/__init__.py,sha256=
|
|
1
|
+
tree_sitter_analyzer/__init__.py,sha256=Bg7okJtLa1BS4OaksNMVLvvdDXWbdWF0AKsoRp5aTig,3067
|
|
2
2
|
tree_sitter_analyzer/__main__.py,sha256=Zl79tpe4UaMu-7yeztc06tgP0CVMRnvGgas4ZQP5SCs,228
|
|
3
3
|
tree_sitter_analyzer/api.py,sha256=gqHatRpVm8k0jEfFm45iokHRPYJjEcud6MtrCSg1V0A,22169
|
|
4
4
|
tree_sitter_analyzer/cli_main.py,sha256=RAPn4VGHVOfC2vrU1Sef7PEPcypMwuI5GgWiwoYL1PE,11100
|
|
@@ -13,7 +13,7 @@ tree_sitter_analyzer/output_manager.py,sha256=hRAp6Aa9k05UVvZkOyRCEz2Lf7blx05fWn
|
|
|
13
13
|
tree_sitter_analyzer/project_detector.py,sha256=-zmtm12EvVD_6TDxS_6KpzuswP2Bpppnxq50kAEDyMA,9430
|
|
14
14
|
tree_sitter_analyzer/query_loader.py,sha256=rtUZ_ZBhacb2uvM8aPrf0XiigUDtxflfjbenfKcatEI,10407
|
|
15
15
|
tree_sitter_analyzer/table_formatter.py,sha256=tPKw77LLlQ7k5MMs9_Ez7qsSroNaSzZPoplyPtKHLhA,28577
|
|
16
|
-
tree_sitter_analyzer/utils.py,sha256=
|
|
16
|
+
tree_sitter_analyzer/utils.py,sha256=YN4n_XDJQAvcP2eKqYV7AzsZW1UMtks9O4BLR2youjs,16110
|
|
17
17
|
tree_sitter_analyzer/cli/__init__.py,sha256=O_3URpbdu5Ilb2-r48LjbZuWtOWQu_BhL3pa6C0G3Bk,871
|
|
18
18
|
tree_sitter_analyzer/cli/__main__.py,sha256=Xq8o8-0dPnMDU9WZqmqhzr98rx8rvoffTUHAkAwl-L8,218
|
|
19
19
|
tree_sitter_analyzer/cli/argument_validator.py,sha256=n336uNVWE9FFWc5s1ADKNQq53_BSnqdTtqEFk90UDBI,2574
|
|
@@ -72,16 +72,17 @@ tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py,sha256=Yb9lpUPGuvRbawmE15ic
|
|
|
72
72
|
tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py,sha256=mssed7bEfGeGxW4mOf7dg8BDS1oqHLolIBNX9DaZ3DM,8997
|
|
73
73
|
tree_sitter_analyzer/mcp/tools/base_tool.py,sha256=qf2My325azlnKOugNVMN_R1jtZcjXVy354sGVKzvZls,3546
|
|
74
74
|
tree_sitter_analyzer/mcp/tools/fd_rg_utils.py,sha256=9jQ4D5yREs7Nt8L0s-NdVtmaKXJAAOKqAAI8mkW3T2o,18664
|
|
75
|
-
tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py,sha256=
|
|
75
|
+
tree_sitter_analyzer/mcp/tools/find_and_grep_tool.py,sha256=OLJToDgLj74irikqC5kJQ_k5isAw9YzkVVOrQIRrQnc,32063
|
|
76
76
|
tree_sitter_analyzer/mcp/tools/list_files_tool.py,sha256=nd6uiOqbsr8NUqNL46d8QnOM-XpMTDOFiaccjBaGLl8,18268
|
|
77
|
-
tree_sitter_analyzer/mcp/tools/query_tool.py,sha256=
|
|
77
|
+
tree_sitter_analyzer/mcp/tools/query_tool.py,sha256=3_TVIfkkZSJo0WNBsiTnctYlq59OVgZYI4IMX2-zsuA,17056
|
|
78
78
|
tree_sitter_analyzer/mcp/tools/read_partial_tool.py,sha256=lC3Zigp3_v8RU_fi5Fz0O_idjP6z_AmgoqVQOethL3I,18493
|
|
79
|
-
tree_sitter_analyzer/mcp/tools/search_content_tool.py,sha256=
|
|
80
|
-
tree_sitter_analyzer/mcp/tools/table_format_tool.py,sha256=
|
|
79
|
+
tree_sitter_analyzer/mcp/tools/search_content_tool.py,sha256=t-ui0KA78vKqIA5VCD_ep2dl0wexkRgqx9dvYvedies,32905
|
|
80
|
+
tree_sitter_analyzer/mcp/tools/table_format_tool.py,sha256=lbE2GQKllsV0vGyhmX5wMPhGn9BT0FoRMV17FcE0FWo,22604
|
|
81
81
|
tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py,sha256=-zZnqN9WcoyRTKM_16ADH859LSebzi34BGYwQL2zCOs,25084
|
|
82
82
|
tree_sitter_analyzer/mcp/utils/__init__.py,sha256=TgTTKsRJAqF95g1fAp5SR_zQVDkImpc_5R0Dw529UUw,3126
|
|
83
83
|
tree_sitter_analyzer/mcp/utils/error_handler.py,sha256=msrQHX67K3vhJsEc3OPRz5mmWU_yoHz55Lnxy0IZuy4,18404
|
|
84
|
-
tree_sitter_analyzer/mcp/utils/
|
|
84
|
+
tree_sitter_analyzer/mcp/utils/file_output_factory.py,sha256=qhLP4p8wfqz0oM19iTlStxak8fu0Aq40OKdPmqkhPBg,7454
|
|
85
|
+
tree_sitter_analyzer/mcp/utils/file_output_manager.py,sha256=_MideWK9KexXHpbEtxXpHyGA2Rp4m3xKVCvtIx4-Y-Q,10829
|
|
85
86
|
tree_sitter_analyzer/mcp/utils/gitignore_detector.py,sha256=_KKd2tIqudG95Pn53wScDr5wZWEijuUA6CFc04J7Ubo,11942
|
|
86
87
|
tree_sitter_analyzer/mcp/utils/path_resolver.py,sha256=77BmbyEuJCuDPNH9POcTOS4tYBorPu-IXFGpBC1DxOk,15006
|
|
87
88
|
tree_sitter_analyzer/mcp/utils/search_cache.py,sha256=ZNv84st6PeejDY1B50AKTbItpXs9HS6JrpR-Ozjyc1c,12991
|
|
@@ -102,7 +103,7 @@ tree_sitter_analyzer/security/regex_checker.py,sha256=jWK6H8PTPgzbwRPfK_RZ8bBTS6
|
|
|
102
103
|
tree_sitter_analyzer/security/validator.py,sha256=PJ2CxYANMi7Ot4rPq2sUgfEF0f7EXoS_3mWqEG4Y-8w,21966
|
|
103
104
|
tree_sitter_analyzer/utils/__init__.py,sha256=U2zLA7-80BE7NB9nV5coL2hdS-TPey22U4il9VkPfRA,3747
|
|
104
105
|
tree_sitter_analyzer/utils/tree_sitter_compat.py,sha256=9hvig3RQp_9H-YN1AWjW1Dl8fugYOPF-M8TRb41LMZU,10861
|
|
105
|
-
tree_sitter_analyzer-1.8.
|
|
106
|
-
tree_sitter_analyzer-1.8.
|
|
107
|
-
tree_sitter_analyzer-1.8.
|
|
108
|
-
tree_sitter_analyzer-1.8.
|
|
106
|
+
tree_sitter_analyzer-1.8.4.dist-info/METADATA,sha256=WWE_1AkppJ-PZ6PsD5aAa1jDwl7_vyPARYHEWSpduFA,49119
|
|
107
|
+
tree_sitter_analyzer-1.8.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
108
|
+
tree_sitter_analyzer-1.8.4.dist-info/entry_points.txt,sha256=TJmEXxAMz3og3VPphTHsuE8tNJxf7GuAPjNHwVhXRnc,972
|
|
109
|
+
tree_sitter_analyzer-1.8.4.dist-info/RECORD,,
|
|
File without changes
|
{tree_sitter_analyzer-1.8.2.dist-info → tree_sitter_analyzer-1.8.4.dist-info}/entry_points.txt
RENAMED
|
File without changes
|