tree-sitter-analyzer 0.8.3__py3-none-any.whl → 0.9.2__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 (62) 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 +182 -180
  9. tree_sitter_analyzer/cli/commands/structure_command.py +138 -138
  10. tree_sitter_analyzer/cli/commands/summary_command.py +101 -101
  11. tree_sitter_analyzer/core/__init__.py +15 -15
  12. tree_sitter_analyzer/core/analysis_engine.py +74 -78
  13. tree_sitter_analyzer/core/cache_service.py +320 -320
  14. tree_sitter_analyzer/core/engine.py +566 -566
  15. tree_sitter_analyzer/core/parser.py +293 -293
  16. tree_sitter_analyzer/encoding_utils.py +459 -459
  17. tree_sitter_analyzer/file_handler.py +210 -210
  18. tree_sitter_analyzer/formatters/__init__.py +1 -1
  19. tree_sitter_analyzer/formatters/base_formatter.py +167 -167
  20. tree_sitter_analyzer/formatters/formatter_factory.py +78 -78
  21. tree_sitter_analyzer/formatters/java_formatter.py +18 -18
  22. tree_sitter_analyzer/formatters/python_formatter.py +19 -19
  23. tree_sitter_analyzer/interfaces/__init__.py +9 -9
  24. tree_sitter_analyzer/interfaces/cli.py +528 -528
  25. tree_sitter_analyzer/interfaces/cli_adapter.py +344 -343
  26. tree_sitter_analyzer/interfaces/mcp_adapter.py +206 -206
  27. tree_sitter_analyzer/language_detector.py +53 -53
  28. tree_sitter_analyzer/languages/__init__.py +10 -10
  29. tree_sitter_analyzer/languages/java_plugin.py +1 -1
  30. tree_sitter_analyzer/languages/javascript_plugin.py +446 -446
  31. tree_sitter_analyzer/languages/python_plugin.py +755 -755
  32. tree_sitter_analyzer/mcp/__init__.py +34 -31
  33. tree_sitter_analyzer/mcp/resources/__init__.py +44 -44
  34. tree_sitter_analyzer/mcp/resources/code_file_resource.py +209 -209
  35. tree_sitter_analyzer/mcp/server.py +623 -436
  36. tree_sitter_analyzer/mcp/tools/__init__.py +30 -30
  37. tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +10 -6
  38. tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +247 -242
  39. tree_sitter_analyzer/mcp/tools/base_tool.py +54 -54
  40. tree_sitter_analyzer/mcp/tools/read_partial_tool.py +310 -308
  41. tree_sitter_analyzer/mcp/tools/table_format_tool.py +386 -379
  42. tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +563 -559
  43. tree_sitter_analyzer/mcp/utils/__init__.py +107 -107
  44. tree_sitter_analyzer/models.py +10 -10
  45. tree_sitter_analyzer/output_manager.py +253 -253
  46. tree_sitter_analyzer/plugins/__init__.py +280 -280
  47. tree_sitter_analyzer/plugins/base.py +529 -529
  48. tree_sitter_analyzer/plugins/manager.py +379 -379
  49. tree_sitter_analyzer/queries/__init__.py +26 -26
  50. tree_sitter_analyzer/queries/java.py +391 -391
  51. tree_sitter_analyzer/queries/javascript.py +148 -148
  52. tree_sitter_analyzer/queries/python.py +285 -285
  53. tree_sitter_analyzer/queries/typescript.py +229 -229
  54. tree_sitter_analyzer/query_loader.py +257 -257
  55. tree_sitter_analyzer/security/boundary_manager.py +237 -279
  56. tree_sitter_analyzer/security/validator.py +60 -58
  57. tree_sitter_analyzer/utils.py +294 -277
  58. {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/METADATA +28 -19
  59. tree_sitter_analyzer-0.9.2.dist-info/RECORD +77 -0
  60. {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/entry_points.txt +1 -0
  61. tree_sitter_analyzer-0.8.3.dist-info/RECORD +0 -77
  62. {tree_sitter_analyzer-0.8.3.dist-info → tree_sitter_analyzer-0.9.2.dist-info}/WHEEL +0 -0
@@ -1,30 +1,30 @@
1
- #!/usr/bin/env python3
2
- """
3
- MCP Tools package for Tree-sitter Analyzer
4
-
5
- This package contains all MCP tools that provide specific functionality
6
- through the Model Context Protocol.
7
- """
8
-
9
- from typing import Any
10
-
11
- __version__ = "1.0.0"
12
-
13
- # Tool registry for easy access
14
- AVAILABLE_TOOLS: dict[str, dict[str, Any]] = {
15
- "analyze_code_scale": {
16
- "description": "Analyze code scale, complexity, and structure metrics",
17
- "module": "analyze_scale_tool",
18
- "class": "AnalyzeScaleTool",
19
- },
20
- # Future tools will be added here
21
- # "read_code_partial": {
22
- # "description": "Read partial content from code files",
23
- # "module": "read_partial_tool",
24
- # "class": "ReadPartialTool",
25
- # },
26
- }
27
-
28
- __all__ = [
29
- "AVAILABLE_TOOLS",
30
- ]
1
+ #!/usr/bin/env python3
2
+ """
3
+ MCP Tools package for Tree-sitter Analyzer
4
+
5
+ This package contains all MCP tools that provide specific functionality
6
+ through the Model Context Protocol.
7
+ """
8
+
9
+ from typing import Any
10
+
11
+ __version__ = "1.0.0"
12
+
13
+ # Tool registry for easy access
14
+ AVAILABLE_TOOLS: dict[str, dict[str, Any]] = {
15
+ "analyze_code_scale": {
16
+ "description": "Analyze code scale, complexity, and structure metrics",
17
+ "module": "analyze_scale_tool",
18
+ "class": "AnalyzeScaleTool",
19
+ },
20
+ # Future tools will be added here
21
+ # "read_code_partial": {
22
+ # "description": "Read partial content from code files",
23
+ # "module": "read_partial_tool",
24
+ # "class": "ReadPartialTool",
25
+ # },
26
+ }
27
+
28
+ __all__ = [
29
+ "AVAILABLE_TOOLS",
30
+ ]
@@ -255,7 +255,13 @@ class AnalyzeScaleTool:
255
255
  guidance["recommended_tools"].append("read_code_partial")
256
256
 
257
257
  # Ensure all required fields exist
258
- required_fields = ["complexity_hotspots", "classes", "methods", "fields", "imports"]
258
+ required_fields = [
259
+ "complexity_hotspots",
260
+ "classes",
261
+ "methods",
262
+ "fields",
263
+ "imports",
264
+ ]
259
265
  for field in required_fields:
260
266
  if field not in structural_overview:
261
267
  structural_overview[field] = []
@@ -348,10 +354,8 @@ class AnalyzeScaleTool:
348
354
  include_details = arguments.get("include_details", False)
349
355
  include_guidance = arguments.get("include_guidance", True)
350
356
 
351
- # Security validation (use project_root as base when available)
352
- is_valid, error_msg = self.security_validator.validate_file_path(
353
- file_path, base_path=self.project_root
354
- )
357
+ # Security validation
358
+ is_valid, error_msg = self.security_validator.validate_file_path(file_path)
355
359
  if not is_valid:
356
360
  logger.warning(
357
361
  f"Security validation failed for file path: {file_path} - {error_msg}"
@@ -364,7 +368,7 @@ class AnalyzeScaleTool:
364
368
 
365
369
  # Validate file exists
366
370
  if not Path(file_path).exists():
367
- raise FileNotFoundError(f"File not found: {file_path}")
371
+ raise ValueError("Invalid file path: file does not exist")
368
372
 
369
373
  # Detect language if not specified
370
374
  if not language:
@@ -1,242 +1,247 @@
1
- #!/usr/bin/env python3
2
- """
3
- CLI-Compatible Analyze Code Scale MCP Tool
4
-
5
- This tool provides code scale analysis with output format
6
- that matches the CLI --advanced --statistics output exactly.
7
- """
8
-
9
- import time
10
- from pathlib import Path
11
- from typing import Any, cast
12
-
13
- from ...core.analysis_engine import get_analysis_engine
14
- from ...language_detector import detect_language_from_file
15
- from ...utils import setup_logger
16
-
17
- # Set up logging
18
- logger = setup_logger(__name__)
19
-
20
-
21
- class AnalyzeScaleToolCLICompatible:
22
- """
23
- MCP Tool for analyzing code scale with CLI-compatible output format.
24
-
25
- This tool matches the exact output format of CLI --advanced --statistics.
26
- """
27
-
28
- def __init__(self) -> None:
29
- """Initialize the CLI-compatible analyze scale tool."""
30
- self.analysis_engine = get_analysis_engine()
31
- logger.info("AnalyzeScaleToolCLICompatible initialized")
32
-
33
- def get_tool_schema(self) -> dict[str, Any]:
34
- """
35
- Get the MCP tool schema for analyze_code_scale.
36
-
37
- Returns:
38
- Dictionary containing the tool schema
39
- """
40
- return {
41
- "type": "object",
42
- "properties": {
43
- "file_path": {
44
- "type": "string",
45
- "description": "Path to the code file to analyze",
46
- },
47
- "language": {
48
- "type": "string",
49
- "description": "Programming language (optional, auto-detected if not specified)",
50
- },
51
- "include_complexity": {
52
- "type": "boolean",
53
- "description": "Include complexity metrics in the analysis",
54
- "default": True,
55
- },
56
- "include_details": {
57
- "type": "boolean",
58
- "description": "Include detailed element information",
59
- "default": False,
60
- },
61
- },
62
- "required": ["file_path"],
63
- "additionalProperties": False,
64
- }
65
-
66
- async def execute(self, arguments: dict[str, Any]) -> dict[str, Any]:
67
- """
68
- Execute the analyze_code_scale tool with CLI-compatible output.
69
-
70
- Args:
71
- arguments: Tool arguments containing file_path and optional parameters
72
-
73
- Returns:
74
- Dictionary containing analysis results in CLI-compatible format
75
-
76
- Raises:
77
- ValueError: If required arguments are missing or invalid
78
- FileNotFoundError: If the specified file doesn't exist
79
- """
80
- # Validate required arguments
81
- if "file_path" not in arguments:
82
- raise ValueError("file_path is required")
83
-
84
- file_path = arguments["file_path"]
85
- language = arguments.get("language")
86
- # include_complexity = arguments.get("include_complexity", True) # Not used currently
87
- # include_details = arguments.get("include_details", False) # Not used currently
88
-
89
- # Validate file exists
90
- if not Path(file_path).exists():
91
- raise FileNotFoundError(f"File not found: {file_path}")
92
-
93
- # Detect language if not specified
94
- if not language:
95
- language = detect_language_from_file(file_path)
96
- if language == "unknown":
97
- raise ValueError(f"Could not detect language for file: {file_path}")
98
-
99
- logger.info(f"Analyzing code scale for {file_path} (language: {language})")
100
-
101
- try:
102
- # Use higher precision timer and measure ONLY the engine call
103
- start_time = time.perf_counter()
104
- analysis_result = await self.analysis_engine.analyze_file(file_path)
105
- analysis_time_ms = round((time.perf_counter() - start_time) * 1000, 2)
106
-
107
- # Handle potential None result (for testing purposes with mocked engine)
108
- if cast(Any, analysis_result) is None:
109
- return {
110
- "file_path": file_path,
111
- "success": False,
112
- "package_name": None,
113
- "element_counts": {
114
- "imports": 0,
115
- "classes": 0,
116
- "methods": 0,
117
- "fields": 0,
118
- "annotations": 0,
119
- },
120
- "analysis_time_ms": analysis_time_ms,
121
- "error_message": f"Failed to analyze file: {file_path}",
122
- }
123
-
124
- # Build CLI-compatible result structure (exact match with CLI --advanced --statistics)
125
- result = {
126
- "file_path": file_path,
127
- "success": True,
128
- "package_name": (
129
- analysis_result.package.name
130
- if analysis_result.package
131
- and hasattr(analysis_result.package, "name")
132
- else None
133
- ),
134
- "element_counts": {
135
- "imports": len(analysis_result.imports),
136
- "classes": len(analysis_result.classes),
137
- "methods": len(analysis_result.methods),
138
- "fields": len(analysis_result.fields),
139
- "annotations": len(getattr(analysis_result, "annotations", [])),
140
- },
141
- "analysis_time_ms": analysis_time_ms,
142
- "error_message": None,
143
- }
144
-
145
- logger.info(
146
- f"Successfully analyzed {file_path}: {len(analysis_result.classes)} classes, "
147
- f"{len(analysis_result.methods)} methods, {analysis_time_ms}ms"
148
- )
149
-
150
- return result
151
-
152
- except Exception as e:
153
- logger.error(f"Error analyzing {file_path}: {e}")
154
- # Return CLI-compatible error format
155
- return {
156
- "file_path": file_path,
157
- "success": False,
158
- "package_name": None,
159
- "element_counts": {
160
- "imports": 0,
161
- "classes": 0,
162
- "methods": 0,
163
- "fields": 0,
164
- "annotations": 0,
165
- },
166
- "analysis_time_ms": 0.0,
167
- "error_message": str(e),
168
- }
169
-
170
- def validate_arguments(self, arguments: dict[str, Any]) -> bool:
171
- """
172
- Validate tool arguments against the schema.
173
-
174
- Args:
175
- arguments: Arguments to validate
176
-
177
- Returns:
178
- True if arguments are valid
179
-
180
- Raises:
181
- ValueError: If arguments are invalid
182
- """
183
- schema = self.get_tool_schema()
184
- required_fields = schema.get("required", [])
185
-
186
- # Check required fields
187
- for field in required_fields:
188
- if field not in arguments:
189
- raise ValueError(f"Required field '{field}' is missing")
190
-
191
- # Validate file_path
192
- if "file_path" in arguments:
193
- file_path = arguments["file_path"]
194
- if not isinstance(file_path, str):
195
- raise ValueError("file_path must be a string")
196
- if not file_path.strip():
197
- raise ValueError("file_path cannot be empty")
198
-
199
- # Validate optional fields
200
- if "language" in arguments:
201
- language = arguments["language"]
202
- if not isinstance(language, str):
203
- raise ValueError("language must be a string")
204
-
205
- if "include_complexity" in arguments:
206
- include_complexity = arguments["include_complexity"]
207
- if not isinstance(include_complexity, bool):
208
- raise ValueError("include_complexity must be a boolean")
209
-
210
- if "include_details" in arguments:
211
- include_details = arguments["include_details"]
212
- if not isinstance(include_details, bool):
213
- raise ValueError("include_details must be a boolean")
214
-
215
- return True
216
-
217
- def get_tool_definition(self) -> Any:
218
- """
219
- Get the MCP tool definition for analyze_code_scale.
220
-
221
- Returns:
222
- Tool definition object compatible with MCP server
223
- """
224
- try:
225
- from mcp.types import Tool
226
-
227
- return Tool(
228
- name="analyze_code_scale",
229
- description="Analyze code scale, complexity, and structure metrics with CLI-compatible output format",
230
- inputSchema=self.get_tool_schema(),
231
- )
232
- except ImportError:
233
- # Fallback for when MCP is not available
234
- return {
235
- "name": "analyze_code_scale",
236
- "description": "Analyze code scale, complexity, and structure metrics with CLI-compatible output format",
237
- "inputSchema": self.get_tool_schema(),
238
- }
239
-
240
-
241
- # Tool instance for easy access
242
- analyze_scale_tool_cli_compatible = AnalyzeScaleToolCLICompatible()
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI-Compatible Analyze Code Scale MCP Tool
4
+
5
+ This tool provides code scale analysis with output format
6
+ that matches the CLI --advanced --statistics output exactly.
7
+ """
8
+
9
+ import time
10
+ from pathlib import Path
11
+ from typing import Any, cast
12
+
13
+ from ...core.analysis_engine import get_analysis_engine
14
+ from ...language_detector import detect_language_from_file
15
+ from ...utils import setup_logger
16
+
17
+ # Set up logging
18
+ logger = setup_logger(__name__)
19
+
20
+
21
+ class AnalyzeScaleToolCLICompatible:
22
+ """
23
+ MCP Tool for analyzing code scale with CLI-compatible output format.
24
+
25
+ This tool matches the exact output format of CLI --advanced --statistics.
26
+ """
27
+
28
+ def __init__(self) -> None:
29
+ """Initialize the CLI-compatible analyze scale tool."""
30
+ self.analysis_engine = get_analysis_engine()
31
+ logger.info("AnalyzeScaleToolCLICompatible initialized")
32
+
33
+ def get_tool_schema(self) -> dict[str, Any]:
34
+ """
35
+ Get the MCP tool schema for analyze_code_scale.
36
+
37
+ Returns:
38
+ Dictionary containing the tool schema
39
+ """
40
+ return {
41
+ "type": "object",
42
+ "properties": {
43
+ "file_path": {
44
+ "type": "string",
45
+ "description": "Path to the code file to analyze",
46
+ },
47
+ "language": {
48
+ "type": "string",
49
+ "description": "Programming language (optional, auto-detected if not specified)",
50
+ },
51
+ "include_complexity": {
52
+ "type": "boolean",
53
+ "description": "Include complexity metrics in the analysis",
54
+ "default": True,
55
+ },
56
+ "include_details": {
57
+ "type": "boolean",
58
+ "description": "Include detailed element information",
59
+ "default": False,
60
+ },
61
+ },
62
+ "required": ["file_path"],
63
+ "additionalProperties": False,
64
+ }
65
+
66
+ async def execute(self, arguments: dict[str, Any]) -> dict[str, Any]:
67
+ """
68
+ Execute the analyze_code_scale tool with CLI-compatible output.
69
+
70
+ Args:
71
+ arguments: Tool arguments containing file_path and optional parameters
72
+
73
+ Returns:
74
+ Dictionary containing analysis results in CLI-compatible format
75
+
76
+ Raises:
77
+ ValueError: If required arguments are missing or invalid
78
+ FileNotFoundError: If the specified file doesn't exist
79
+ """
80
+ # Validate required arguments
81
+ if "file_path" not in arguments:
82
+ raise ValueError("file_path is required")
83
+
84
+ file_path = arguments["file_path"]
85
+ language = arguments.get("language")
86
+ # include_complexity = arguments.get("include_complexity", True) # Not used currently
87
+ # include_details = arguments.get("include_details", False) # Not used currently
88
+
89
+ # Validate file exists
90
+ if not Path(file_path).exists():
91
+ raise FileNotFoundError(f"File not found: {file_path}")
92
+
93
+ # Detect language if not specified
94
+ if not language:
95
+ language = detect_language_from_file(file_path)
96
+ if language == "unknown":
97
+ raise ValueError(f"Could not detect language for file: {file_path}")
98
+
99
+ logger.info(f"Analyzing code scale for {file_path} (language: {language})")
100
+
101
+ try:
102
+ start_time = time.time()
103
+
104
+ # Use AdvancedAnalyzer for comprehensive analysis
105
+ analysis_result = await self.analysis_engine.analyze_file(file_path)
106
+
107
+ # Handle potential None result (for testing purposes with mocked engine)
108
+ # This can only happen in tests where the engine is mocked to return None
109
+ # Use cast to tell MyPy this is possible in testing scenarios
110
+ if cast(Any, analysis_result) is None:
111
+ return {
112
+ "file_path": file_path,
113
+ "success": False,
114
+ "package_name": None,
115
+ "element_counts": {
116
+ "imports": 0,
117
+ "classes": 0,
118
+ "methods": 0,
119
+ "fields": 0,
120
+ "annotations": 0,
121
+ },
122
+ "analysis_time_ms": round((time.time() - start_time) * 1000, 2),
123
+ "error_message": f"Failed to analyze file: {file_path}",
124
+ }
125
+
126
+ # Calculate analysis time
127
+ analysis_time_ms = round((time.time() - start_time) * 1000, 2)
128
+
129
+ # Build CLI-compatible result structure (exact match with CLI --advanced --statistics)
130
+ result = {
131
+ "file_path": file_path,
132
+ "success": True,
133
+ "package_name": (
134
+ analysis_result.package.name
135
+ if analysis_result.package
136
+ and hasattr(analysis_result.package, "name")
137
+ else None
138
+ ),
139
+ "element_counts": {
140
+ "imports": len(analysis_result.imports),
141
+ "classes": len(analysis_result.classes),
142
+ "methods": len(analysis_result.methods),
143
+ "fields": len(analysis_result.fields),
144
+ "annotations": len(getattr(analysis_result, "annotations", [])),
145
+ },
146
+ "analysis_time_ms": analysis_time_ms,
147
+ "error_message": None,
148
+ }
149
+
150
+ logger.info(
151
+ f"Successfully analyzed {file_path}: {len(analysis_result.classes)} classes, "
152
+ f"{len(analysis_result.methods)} methods, {analysis_time_ms}ms"
153
+ )
154
+
155
+ return result
156
+
157
+ except Exception as e:
158
+ logger.error(f"Error analyzing {file_path}: {e}")
159
+ # Return CLI-compatible error format
160
+ return {
161
+ "file_path": file_path,
162
+ "success": False,
163
+ "package_name": None,
164
+ "element_counts": {
165
+ "imports": 0,
166
+ "classes": 0,
167
+ "methods": 0,
168
+ "fields": 0,
169
+ "annotations": 0,
170
+ },
171
+ "analysis_time_ms": 0.0,
172
+ "error_message": str(e),
173
+ }
174
+
175
+ def validate_arguments(self, arguments: dict[str, Any]) -> bool:
176
+ """
177
+ Validate tool arguments against the schema.
178
+
179
+ Args:
180
+ arguments: Arguments to validate
181
+
182
+ Returns:
183
+ True if arguments are valid
184
+
185
+ Raises:
186
+ ValueError: If arguments are invalid
187
+ """
188
+ schema = self.get_tool_schema()
189
+ required_fields = schema.get("required", [])
190
+
191
+ # Check required fields
192
+ for field in required_fields:
193
+ if field not in arguments:
194
+ raise ValueError(f"Required field '{field}' is missing")
195
+
196
+ # Validate file_path
197
+ if "file_path" in arguments:
198
+ file_path = arguments["file_path"]
199
+ if not isinstance(file_path, str):
200
+ raise ValueError("file_path must be a string")
201
+ if not file_path.strip():
202
+ raise ValueError("file_path cannot be empty")
203
+
204
+ # Validate optional fields
205
+ if "language" in arguments:
206
+ language = arguments["language"]
207
+ if not isinstance(language, str):
208
+ raise ValueError("language must be a string")
209
+
210
+ if "include_complexity" in arguments:
211
+ include_complexity = arguments["include_complexity"]
212
+ if not isinstance(include_complexity, bool):
213
+ raise ValueError("include_complexity must be a boolean")
214
+
215
+ if "include_details" in arguments:
216
+ include_details = arguments["include_details"]
217
+ if not isinstance(include_details, bool):
218
+ raise ValueError("include_details must be a boolean")
219
+
220
+ return True
221
+
222
+ def get_tool_definition(self) -> Any:
223
+ """
224
+ Get the MCP tool definition for analyze_code_scale.
225
+
226
+ Returns:
227
+ Tool definition object compatible with MCP server
228
+ """
229
+ try:
230
+ from mcp.types import Tool
231
+
232
+ return Tool(
233
+ name="analyze_code_scale",
234
+ description="Analyze code scale, complexity, and structure metrics with CLI-compatible output format",
235
+ inputSchema=self.get_tool_schema(),
236
+ )
237
+ except ImportError:
238
+ # Fallback for when MCP is not available
239
+ return {
240
+ "name": "analyze_code_scale",
241
+ "description": "Analyze code scale, complexity, and structure metrics with CLI-compatible output format",
242
+ "inputSchema": self.get_tool_schema(),
243
+ }
244
+
245
+
246
+ # Tool instance for easy access
247
+ analyze_scale_tool_cli_compatible = AnalyzeScaleToolCLICompatible()