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

Files changed (70) hide show
  1. tree_sitter_analyzer/__init__.py +132 -132
  2. tree_sitter_analyzer/__main__.py +11 -11
  3. tree_sitter_analyzer/api.py +533 -533
  4. tree_sitter_analyzer/cli/__init__.py +39 -39
  5. tree_sitter_analyzer/cli/__main__.py +12 -12
  6. tree_sitter_analyzer/cli/commands/__init__.py +26 -26
  7. tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
  8. tree_sitter_analyzer/cli/commands/base_command.py +178 -160
  9. tree_sitter_analyzer/cli/commands/default_command.py +18 -18
  10. tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -141
  11. tree_sitter_analyzer/cli/commands/query_command.py +88 -81
  12. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  13. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  14. tree_sitter_analyzer/cli/commands/table_command.py +235 -235
  15. tree_sitter_analyzer/cli/info_commands.py +121 -121
  16. tree_sitter_analyzer/cli_main.py +303 -297
  17. tree_sitter_analyzer/core/__init__.py +15 -15
  18. tree_sitter_analyzer/core/analysis_engine.py +580 -555
  19. tree_sitter_analyzer/core/cache_service.py +320 -320
  20. tree_sitter_analyzer/core/engine.py +566 -566
  21. tree_sitter_analyzer/core/parser.py +293 -293
  22. tree_sitter_analyzer/encoding_utils.py +459 -459
  23. tree_sitter_analyzer/exceptions.py +406 -337
  24. tree_sitter_analyzer/file_handler.py +210 -210
  25. tree_sitter_analyzer/formatters/__init__.py +1 -1
  26. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  27. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  28. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  29. tree_sitter_analyzer/interfaces/cli.py +528 -528
  30. tree_sitter_analyzer/interfaces/cli_adapter.py +343 -343
  31. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  32. tree_sitter_analyzer/interfaces/mcp_server.py +425 -405
  33. tree_sitter_analyzer/languages/__init__.py +10 -10
  34. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  35. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  36. tree_sitter_analyzer/mcp/__init__.py +31 -31
  37. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  38. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  39. tree_sitter_analyzer/mcp/server.py +408 -333
  40. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  41. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +673 -654
  42. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -247
  43. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  44. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +308 -300
  45. tree_sitter_analyzer/mcp/tools/table_format_tool.py +379 -362
  46. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +559 -543
  47. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  48. tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
  49. tree_sitter_analyzer/output_manager.py +253 -253
  50. tree_sitter_analyzer/plugins/__init__.py +280 -280
  51. tree_sitter_analyzer/plugins/base.py +529 -529
  52. tree_sitter_analyzer/plugins/manager.py +379 -379
  53. tree_sitter_analyzer/project_detector.py +317 -0
  54. tree_sitter_analyzer/queries/__init__.py +26 -26
  55. tree_sitter_analyzer/queries/java.py +391 -391
  56. tree_sitter_analyzer/queries/javascript.py +148 -148
  57. tree_sitter_analyzer/queries/python.py +285 -285
  58. tree_sitter_analyzer/queries/typescript.py +229 -229
  59. tree_sitter_analyzer/query_loader.py +257 -257
  60. tree_sitter_analyzer/security/__init__.py +22 -0
  61. tree_sitter_analyzer/security/boundary_manager.py +237 -0
  62. tree_sitter_analyzer/security/regex_checker.py +292 -0
  63. tree_sitter_analyzer/security/validator.py +241 -0
  64. tree_sitter_analyzer/table_formatter.py +652 -589
  65. tree_sitter_analyzer/utils.py +277 -277
  66. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/METADATA +27 -1
  67. tree_sitter_analyzer-0.8.1.dist-info/RECORD +77 -0
  68. tree_sitter_analyzer-0.7.0.dist-info/RECORD +0 -72
  69. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/WHEEL +0 -0
  70. {tree_sitter_analyzer-0.7.0.dist-info → tree_sitter_analyzer-0.8.1.dist-info}/entry_points.txt +0 -0
@@ -1,277 +1,277 @@
1
- #!/usr/bin/env python3
2
- """
3
- Utilities for Tree-sitter Analyzer
4
-
5
- Provides logging, debugging, and common utility functions.
6
- """
7
-
8
- import atexit
9
- import logging
10
- import sys
11
- from functools import wraps
12
- from typing import Any
13
-
14
-
15
- # Configure global logger
16
- def setup_logger(
17
- name: str = "tree_sitter_analyzer", level: int = logging.INFO
18
- ) -> logging.Logger:
19
- """Setup unified logger for the project"""
20
- import os
21
-
22
- # Get log level from environment variable
23
- env_level = os.environ.get("LOG_LEVEL", "").upper()
24
- if env_level == "DEBUG":
25
- level = logging.DEBUG
26
- elif env_level == "INFO":
27
- level = logging.INFO
28
- elif env_level == "WARNING":
29
- level = logging.WARNING
30
- elif env_level == "ERROR":
31
- level = logging.ERROR
32
-
33
- logger = logging.getLogger(name)
34
-
35
- if not logger.handlers: # Avoid duplicate handlers
36
- # Create a safe handler that won't fail on closed streams
37
- handler = SafeStreamHandler(sys.stdout)
38
- formatter = logging.Formatter(
39
- "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
40
- )
41
- handler.setFormatter(formatter)
42
- logger.addHandler(handler)
43
- logger.setLevel(level)
44
-
45
- return logger
46
-
47
-
48
- class SafeStreamHandler(logging.StreamHandler):
49
- """
50
- A StreamHandler that safely handles closed streams
51
- """
52
-
53
- def emit(self, record: Any) -> None:
54
- """
55
- Emit a record, safely handling closed streams
56
- """
57
- try:
58
- # Check if stream is closed before writing
59
- if hasattr(self.stream, "closed") and self.stream.closed:
60
- return
61
-
62
- # Check if we can write to the stream
63
- if not hasattr(self.stream, "write"):
64
- return
65
-
66
- super().emit(record)
67
- except (ValueError, OSError, AttributeError):
68
- # Silently ignore I/O errors during shutdown
69
- pass
70
- except Exception:
71
- # For any other unexpected errors, use handleError
72
- self.handleError(record)
73
-
74
-
75
- def setup_safe_logging_shutdown() -> None:
76
- """
77
- Setup safe logging shutdown to prevent I/O errors
78
- """
79
-
80
- def cleanup_logging() -> None:
81
- """Clean up logging handlers safely"""
82
- try:
83
- # Get all loggers
84
- loggers = [logging.getLogger()] + [
85
- logging.getLogger(name) for name in logging.Logger.manager.loggerDict
86
- ]
87
-
88
- for logger in loggers:
89
- for handler in logger.handlers[:]:
90
- try:
91
- handler.close()
92
- logger.removeHandler(handler)
93
- except Exception:
94
- pass
95
- except Exception:
96
- pass
97
-
98
- # Register cleanup function
99
- atexit.register(cleanup_logging)
100
-
101
-
102
- # Setup safe shutdown on import
103
- setup_safe_logging_shutdown()
104
-
105
-
106
- # Global logger instance
107
- logger = setup_logger()
108
-
109
-
110
- def log_info(message: str, *args: Any, **kwargs: Any) -> None:
111
- """Log info message"""
112
- try:
113
- logger.info(message, *args, **kwargs)
114
- except (ValueError, OSError):
115
- pass # Silently ignore I/O errors
116
-
117
-
118
- def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
119
- """Log warning message"""
120
- try:
121
- logger.warning(message, *args, **kwargs)
122
- except (ValueError, OSError):
123
- pass # Silently ignore I/O errors
124
-
125
-
126
- def log_error(message: str, *args: Any, **kwargs: Any) -> None:
127
- """Log error message"""
128
- try:
129
- logger.error(message, *args, **kwargs)
130
- except (ValueError, OSError):
131
- pass # Silently ignore I/O errors
132
-
133
-
134
- def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
135
- """Log debug message"""
136
- try:
137
- logger.debug(message, *args, **kwargs)
138
- except (ValueError, OSError):
139
- pass # Silently ignore I/O errors
140
-
141
-
142
- def suppress_output(func: Any) -> Any:
143
- """Decorator to suppress print statements in production"""
144
-
145
- @wraps(func)
146
- def wrapper(*args: Any, **kwargs: Any) -> Any:
147
- # Check if we're in test/debug mode
148
- if getattr(sys, "_testing", False):
149
- return func(*args, **kwargs)
150
-
151
- # Redirect stdout to suppress prints
152
- old_stdout = sys.stdout
153
- try:
154
- sys.stdout = (
155
- open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
156
- )
157
- result = func(*args, **kwargs)
158
- finally:
159
- try:
160
- sys.stdout.close()
161
- except Exception:
162
- pass
163
- sys.stdout = old_stdout
164
-
165
- return result
166
-
167
- return wrapper
168
-
169
-
170
- class QuietMode:
171
- """Context manager for quiet execution"""
172
-
173
- def __init__(self, enabled: bool = True):
174
- self.enabled = enabled
175
- self.old_level: int | None = None
176
-
177
- def __enter__(self) -> "QuietMode":
178
- if self.enabled:
179
- self.old_level = logger.level
180
- logger.setLevel(logging.ERROR)
181
- return self
182
-
183
- def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
184
- if self.enabled and self.old_level is not None:
185
- logger.setLevel(self.old_level)
186
-
187
-
188
- def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
189
- """Safe print function that can be controlled"""
190
- if quiet:
191
- return
192
-
193
- level_map = {
194
- "info": log_info,
195
- "warning": log_warning,
196
- "error": log_error,
197
- "debug": log_debug,
198
- }
199
-
200
- log_func = level_map.get(level.lower(), log_info)
201
- log_func(message)
202
-
203
-
204
- def create_performance_logger(name: str) -> logging.Logger:
205
- """Create performance-focused logger"""
206
- perf_logger = logging.getLogger(f"{name}.performance")
207
-
208
- if not perf_logger.handlers:
209
- handler = SafeStreamHandler()
210
- formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
211
- handler.setFormatter(formatter)
212
- perf_logger.addHandler(handler)
213
- perf_logger.setLevel(logging.INFO)
214
-
215
- return perf_logger
216
-
217
-
218
- # Performance logger instance
219
- perf_logger = create_performance_logger("tree_sitter_analyzer")
220
-
221
-
222
- def log_performance(
223
- operation: str,
224
- execution_time: float | None = None,
225
- details: dict[Any, Any] | str | None = None,
226
- ) -> None:
227
- """Log performance metrics"""
228
- try:
229
- message = f"{operation}"
230
- if execution_time is not None:
231
- message += f": {execution_time:.4f}s"
232
- if details:
233
- if isinstance(details, dict):
234
- detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
235
- else:
236
- detail_str = str(details)
237
- message += f" - {detail_str}"
238
- perf_logger.info(message)
239
- except (ValueError, OSError):
240
- pass # Silently ignore I/O errors
241
-
242
-
243
- def setup_performance_logger() -> logging.Logger:
244
- """Set up performance logging"""
245
- perf_logger = logging.getLogger("performance")
246
-
247
- # Add handler if not already configured
248
- if not perf_logger.handlers:
249
- handler = SafeStreamHandler()
250
- formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
251
- handler.setFormatter(formatter)
252
- perf_logger.addHandler(handler)
253
- perf_logger.setLevel(logging.INFO)
254
-
255
- return perf_logger
256
-
257
-
258
- class LoggingContext:
259
- """Context manager for controlling logging behavior"""
260
-
261
- def __init__(self, enabled: bool = True, level: int | None = None):
262
- self.enabled = enabled
263
- self.level = level
264
- self.old_level: int | None = None
265
- self.target_logger = (
266
- logging.getLogger()
267
- ) # Use root logger for compatibility with tests
268
-
269
- def __enter__(self) -> "LoggingContext":
270
- if self.enabled and self.level is not None:
271
- self.old_level = self.target_logger.level
272
- self.target_logger.setLevel(self.level)
273
- return self
274
-
275
- def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
276
- if self.enabled and self.old_level is not None:
277
- self.target_logger.setLevel(self.old_level)
1
+ #!/usr/bin/env python3
2
+ """
3
+ Utilities for Tree-sitter Analyzer
4
+
5
+ Provides logging, debugging, and common utility functions.
6
+ """
7
+
8
+ import atexit
9
+ import logging
10
+ import sys
11
+ from functools import wraps
12
+ from typing import Any
13
+
14
+
15
+ # Configure global logger
16
+ def setup_logger(
17
+ name: str = "tree_sitter_analyzer", level: int = logging.INFO
18
+ ) -> logging.Logger:
19
+ """Setup unified logger for the project"""
20
+ import os
21
+
22
+ # Get log level from environment variable
23
+ env_level = os.environ.get("LOG_LEVEL", "").upper()
24
+ if env_level == "DEBUG":
25
+ level = logging.DEBUG
26
+ elif env_level == "INFO":
27
+ level = logging.INFO
28
+ elif env_level == "WARNING":
29
+ level = logging.WARNING
30
+ elif env_level == "ERROR":
31
+ level = logging.ERROR
32
+
33
+ logger = logging.getLogger(name)
34
+
35
+ if not logger.handlers: # Avoid duplicate handlers
36
+ # Create a safe handler that won't fail on closed streams
37
+ handler = SafeStreamHandler(sys.stdout)
38
+ formatter = logging.Formatter(
39
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
40
+ )
41
+ handler.setFormatter(formatter)
42
+ logger.addHandler(handler)
43
+ logger.setLevel(level)
44
+
45
+ return logger
46
+
47
+
48
+ class SafeStreamHandler(logging.StreamHandler):
49
+ """
50
+ A StreamHandler that safely handles closed streams
51
+ """
52
+
53
+ def emit(self, record: Any) -> None:
54
+ """
55
+ Emit a record, safely handling closed streams
56
+ """
57
+ try:
58
+ # Check if stream is closed before writing
59
+ if hasattr(self.stream, "closed") and self.stream.closed:
60
+ return
61
+
62
+ # Check if we can write to the stream
63
+ if not hasattr(self.stream, "write"):
64
+ return
65
+
66
+ super().emit(record)
67
+ except (ValueError, OSError, AttributeError):
68
+ # Silently ignore I/O errors during shutdown
69
+ pass
70
+ except Exception:
71
+ # For any other unexpected errors, use handleError
72
+ self.handleError(record)
73
+
74
+
75
+ def setup_safe_logging_shutdown() -> None:
76
+ """
77
+ Setup safe logging shutdown to prevent I/O errors
78
+ """
79
+
80
+ def cleanup_logging() -> None:
81
+ """Clean up logging handlers safely"""
82
+ try:
83
+ # Get all loggers
84
+ loggers = [logging.getLogger()] + [
85
+ logging.getLogger(name) for name in logging.Logger.manager.loggerDict
86
+ ]
87
+
88
+ for logger in loggers:
89
+ for handler in logger.handlers[:]:
90
+ try:
91
+ handler.close()
92
+ logger.removeHandler(handler)
93
+ except Exception:
94
+ pass
95
+ except Exception:
96
+ pass
97
+
98
+ # Register cleanup function
99
+ atexit.register(cleanup_logging)
100
+
101
+
102
+ # Setup safe shutdown on import
103
+ setup_safe_logging_shutdown()
104
+
105
+
106
+ # Global logger instance
107
+ logger = setup_logger()
108
+
109
+
110
+ def log_info(message: str, *args: Any, **kwargs: Any) -> None:
111
+ """Log info message"""
112
+ try:
113
+ logger.info(message, *args, **kwargs)
114
+ except (ValueError, OSError):
115
+ pass # Silently ignore I/O errors
116
+
117
+
118
+ def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
119
+ """Log warning message"""
120
+ try:
121
+ logger.warning(message, *args, **kwargs)
122
+ except (ValueError, OSError):
123
+ pass # Silently ignore I/O errors
124
+
125
+
126
+ def log_error(message: str, *args: Any, **kwargs: Any) -> None:
127
+ """Log error message"""
128
+ try:
129
+ logger.error(message, *args, **kwargs)
130
+ except (ValueError, OSError):
131
+ pass # Silently ignore I/O errors
132
+
133
+
134
+ def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
135
+ """Log debug message"""
136
+ try:
137
+ logger.debug(message, *args, **kwargs)
138
+ except (ValueError, OSError):
139
+ pass # Silently ignore I/O errors
140
+
141
+
142
+ def suppress_output(func: Any) -> Any:
143
+ """Decorator to suppress print statements in production"""
144
+
145
+ @wraps(func)
146
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
147
+ # Check if we're in test/debug mode
148
+ if getattr(sys, "_testing", False):
149
+ return func(*args, **kwargs)
150
+
151
+ # Redirect stdout to suppress prints
152
+ old_stdout = sys.stdout
153
+ try:
154
+ sys.stdout = (
155
+ open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
156
+ )
157
+ result = func(*args, **kwargs)
158
+ finally:
159
+ try:
160
+ sys.stdout.close()
161
+ except Exception:
162
+ pass
163
+ sys.stdout = old_stdout
164
+
165
+ return result
166
+
167
+ return wrapper
168
+
169
+
170
+ class QuietMode:
171
+ """Context manager for quiet execution"""
172
+
173
+ def __init__(self, enabled: bool = True):
174
+ self.enabled = enabled
175
+ self.old_level: int | None = None
176
+
177
+ def __enter__(self) -> "QuietMode":
178
+ if self.enabled:
179
+ self.old_level = logger.level
180
+ logger.setLevel(logging.ERROR)
181
+ return self
182
+
183
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
184
+ if self.enabled and self.old_level is not None:
185
+ logger.setLevel(self.old_level)
186
+
187
+
188
+ def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
189
+ """Safe print function that can be controlled"""
190
+ if quiet:
191
+ return
192
+
193
+ level_map = {
194
+ "info": log_info,
195
+ "warning": log_warning,
196
+ "error": log_error,
197
+ "debug": log_debug,
198
+ }
199
+
200
+ log_func = level_map.get(level.lower(), log_info)
201
+ log_func(message)
202
+
203
+
204
+ def create_performance_logger(name: str) -> logging.Logger:
205
+ """Create performance-focused logger"""
206
+ perf_logger = logging.getLogger(f"{name}.performance")
207
+
208
+ if not perf_logger.handlers:
209
+ handler = SafeStreamHandler()
210
+ formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
211
+ handler.setFormatter(formatter)
212
+ perf_logger.addHandler(handler)
213
+ perf_logger.setLevel(logging.INFO)
214
+
215
+ return perf_logger
216
+
217
+
218
+ # Performance logger instance
219
+ perf_logger = create_performance_logger("tree_sitter_analyzer")
220
+
221
+
222
+ def log_performance(
223
+ operation: str,
224
+ execution_time: float | None = None,
225
+ details: dict[Any, Any] | str | None = None,
226
+ ) -> None:
227
+ """Log performance metrics"""
228
+ try:
229
+ message = f"{operation}"
230
+ if execution_time is not None:
231
+ message += f": {execution_time:.4f}s"
232
+ if details:
233
+ if isinstance(details, dict):
234
+ detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
235
+ else:
236
+ detail_str = str(details)
237
+ message += f" - {detail_str}"
238
+ perf_logger.info(message)
239
+ except (ValueError, OSError):
240
+ pass # Silently ignore I/O errors
241
+
242
+
243
+ def setup_performance_logger() -> logging.Logger:
244
+ """Set up performance logging"""
245
+ perf_logger = logging.getLogger("performance")
246
+
247
+ # Add handler if not already configured
248
+ if not perf_logger.handlers:
249
+ handler = SafeStreamHandler()
250
+ formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
251
+ handler.setFormatter(formatter)
252
+ perf_logger.addHandler(handler)
253
+ perf_logger.setLevel(logging.INFO)
254
+
255
+ return perf_logger
256
+
257
+
258
+ class LoggingContext:
259
+ """Context manager for controlling logging behavior"""
260
+
261
+ def __init__(self, enabled: bool = True, level: int | None = None):
262
+ self.enabled = enabled
263
+ self.level = level
264
+ self.old_level: int | None = None
265
+ self.target_logger = (
266
+ logging.getLogger()
267
+ ) # Use root logger for compatibility with tests
268
+
269
+ def __enter__(self) -> "LoggingContext":
270
+ if self.enabled and self.level is not None:
271
+ self.old_level = self.target_logger.level
272
+ self.target_logger.setLevel(self.level)
273
+ return self
274
+
275
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
276
+ if self.enabled and self.old_level is not None:
277
+ self.target_logger.setLevel(self.old_level)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tree-sitter-analyzer
3
- Version: 0.7.0
3
+ Version: 0.8.1
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
@@ -33,8 +33,11 @@ Classifier: Typing :: Typed
33
33
  Requires-Python: >=3.10
34
34
  Requires-Dist: cachetools>=5.0.0
35
35
  Requires-Dist: chardet>=5.0.0
36
+ Requires-Dist: mcp>=1.12.3
36
37
  Requires-Dist: tree-sitter-cpp>=0.23.4
37
38
  Requires-Dist: tree-sitter-java>=0.23.5
39
+ Requires-Dist: tree-sitter-javascript>=0.23.1
40
+ Requires-Dist: tree-sitter-python>=0.23.6
38
41
  Requires-Dist: tree-sitter==0.24.0
39
42
  Provides-Extra: all-languages
40
43
  Requires-Dist: tree-sitter-c>=0.20.0; extra == 'all-languages'
@@ -303,9 +306,32 @@ uv sync --extra all --extra mcp
303
306
 
304
307
  - **[MCP Setup Guide for Users](https://github.com/aimasteracc/tree-sitter-analyzer/blob/main/MCP_SETUP_USERS.md)** - Simple setup for AI assistant users
305
308
  - **[MCP Setup Guide for Developers](https://github.com/aimasteracc/tree-sitter-analyzer/blob/main/MCP_SETUP_DEVELOPERS.md)** - Local development configuration
309
+ - **[Project Root Configuration](https://github.com/aimasteracc/tree-sitter-analyzer/blob/main/PROJECT_ROOT_CONFIG.md)** - Complete configuration reference
306
310
  - **[API Documentation](https://github.com/aimasteracc/tree-sitter-analyzer/blob/main/docs/api.md)** - Detailed API reference
307
311
  - **[Contributing Guide](https://github.com/aimasteracc/tree-sitter-analyzer/blob/main/CONTRIBUTING.md)** - How to contribute
308
312
 
313
+ ### 🔒 Project Root Configuration
314
+
315
+ Tree-sitter-analyzer automatically detects and secures your project boundaries:
316
+
317
+ - **Auto-detection**: Finds project root from `.git`, `pyproject.toml`, `package.json`, etc.
318
+ - **CLI**: Use `--project-root /path/to/project` for explicit control
319
+ - **MCP**: Set `TREE_SITTER_PROJECT_ROOT=${workspaceFolder}` for workspace integration
320
+ - **Security**: Only analyzes files within project boundaries
321
+
322
+ **Recommended MCP configuration:**
323
+ ```json
324
+ {
325
+ "mcpServers": {
326
+ "tree-sitter-analyzer": {
327
+ "command": "uv",
328
+ "args": ["run", "--with", "tree-sitter-analyzer[mcp]", "python", "-m", "tree_sitter_analyzer.mcp.server"],
329
+ "env": {"TREE_SITTER_PROJECT_ROOT": "${workspaceFolder}"}
330
+ }
331
+ }
332
+ }
333
+ ```
334
+
309
335
  ## 🧪 Testing
310
336
 
311
337
  This project maintains high code quality with **1126 passing tests**.