skydeckai-code 0.1.30__py3-none-any.whl → 0.1.32__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.
- aidd/tools/file_tools.py +34 -4
- aidd/tools/lint_tools.py +150 -9
- {skydeckai_code-0.1.30.dist-info → skydeckai_code-0.1.32.dist-info}/METADATA +11 -1
- {skydeckai_code-0.1.30.dist-info → skydeckai_code-0.1.32.dist-info}/RECORD +7 -7
- {skydeckai_code-0.1.30.dist-info → skydeckai_code-0.1.32.dist-info}/WHEEL +0 -0
- {skydeckai_code-0.1.30.dist-info → skydeckai_code-0.1.32.dist-info}/entry_points.txt +0 -0
- {skydeckai_code-0.1.30.dist-info → skydeckai_code-0.1.32.dist-info}/licenses/LICENSE +0 -0
aidd/tools/file_tools.py
CHANGED
@@ -822,11 +822,41 @@ async def apply_file_edits(file_path: str, edits: List[dict], dry_run: bool = Fa
|
|
822
822
|
start, end, confidence = find_best_match(working_content, search_text, partial_match)
|
823
823
|
|
824
824
|
if confidence >= 0.8:
|
825
|
-
#
|
825
|
+
# Fix indentation while preserving relative structure
|
826
826
|
if start >= 0:
|
827
|
-
|
828
|
-
|
829
|
-
|
827
|
+
# Get the indentation of the first line of the matched text
|
828
|
+
base_indent = re.match(r'^\s*', modified_content[start:].splitlines()[0]).group(0)
|
829
|
+
|
830
|
+
# Split the new text into lines
|
831
|
+
new_lines = new_text.splitlines()
|
832
|
+
|
833
|
+
# If there are multiple lines, adjust indentation while preserving structure
|
834
|
+
if len(new_lines) > 1:
|
835
|
+
# Find the minimum indentation level in the new text (ignoring empty lines)
|
836
|
+
non_empty_lines = [line for line in new_lines if line.strip()]
|
837
|
+
if non_empty_lines:
|
838
|
+
min_indent_length = min(len(re.match(r'^\s*', line).group(0)) for line in non_empty_lines)
|
839
|
+
else:
|
840
|
+
min_indent_length = 0
|
841
|
+
|
842
|
+
# Process each line to preserve relative indentation
|
843
|
+
processed_lines = []
|
844
|
+
for line in new_lines:
|
845
|
+
if line.strip(): # If line is not empty
|
846
|
+
# Get current indentation
|
847
|
+
current_indent = re.match(r'^\s*', line).group(0)
|
848
|
+
# Calculate relative indentation
|
849
|
+
relative_indent = len(current_indent) - min_indent_length
|
850
|
+
# Apply base indent plus relative indent
|
851
|
+
processed_lines.append(base_indent + ' ' * relative_indent + line.lstrip())
|
852
|
+
else:
|
853
|
+
# For empty lines, just use base indentation
|
854
|
+
processed_lines.append(base_indent)
|
855
|
+
|
856
|
+
replacement = '\n'.join(processed_lines)
|
857
|
+
else:
|
858
|
+
# Single line - just use base indentation
|
859
|
+
replacement = base_indent + new_text.lstrip()
|
830
860
|
else:
|
831
861
|
replacement = new_text
|
832
862
|
|
aidd/tools/lint_tools.py
CHANGED
@@ -18,12 +18,13 @@ def check_lint_tool():
|
|
18
18
|
"when you need detailed code analysis with custom rules, or for compiled languages where linting may not apply. "
|
19
19
|
"RETURNS: A detailed report of linting issues found in the codebase, including file paths, line numbers, "
|
20
20
|
"issue descriptions, and severity levels. Issues are grouped by file and sorted by severity. "
|
21
|
-
"Note: Respects config files like .pylintrc, .flake8, and .
|
21
|
+
"Note: Respects config files like .pylintrc, .flake8, .eslintrc, and analysis_options.yaml if present.\n\n"
|
22
22
|
"EXAMPLES:\n"
|
23
23
|
"- Basic usage: {\"path\": \"src\"}\n"
|
24
24
|
"- Python with custom line length: {\"path\": \"src\", \"linters\": {\"flake8\": \"--max-line-length=120 --ignore=E501,E302\"}}\n"
|
25
25
|
"- Disable specific pylint checks: {\"linters\": {\"pylint\": \"--disable=missing-docstring,invalid-name\"}}\n"
|
26
26
|
"- TypeScript only: {\"path\": \"src\", \"languages\": [\"typescript\"], \"linters\": {\"eslint\": \"--no-eslintrc --config .eslintrc.custom.js\"}}\n"
|
27
|
+
"- Dart only: {\"path\": \"lib\", \"languages\": [\"dart\"], \"linters\": {\"dart_analyze\": \"--fatal-infos\"}}\n"
|
27
28
|
"- Disable a linter: {\"linters\": {\"flake8\": false}, \"max_issues\": 50}\n"
|
28
29
|
"- Single file check: {\"path\": \"src/main.py\"}",
|
29
30
|
"inputSchema": {
|
@@ -41,12 +42,12 @@ def check_lint_tool():
|
|
41
42
|
"type": "string"
|
42
43
|
},
|
43
44
|
"description": "List of languages to lint. If empty, will auto-detect based on file extensions. "
|
44
|
-
"Supported languages include: 'python', 'javascript', 'typescript'.",
|
45
|
+
"Supported languages include: 'python', 'javascript', 'typescript', 'dart'.",
|
45
46
|
"default": []
|
46
47
|
},
|
47
48
|
"linters": {
|
48
49
|
"type": "object",
|
49
|
-
"description": "Configuration for specific linters. Each key is a linter name ('pylint', 'flake8', 'eslint') "
|
50
|
+
"description": "Configuration for specific linters. Each key is a linter name ('pylint', 'flake8', 'eslint', 'dart_analyze') "
|
50
51
|
"and the value is either a boolean to enable/disable or a string with CLI arguments.",
|
51
52
|
"properties": {
|
52
53
|
"pylint": {
|
@@ -60,16 +61,21 @@ def check_lint_tool():
|
|
60
61
|
"eslint": {
|
61
62
|
"type": ["boolean", "string"],
|
62
63
|
"description": "Whether to use eslint or custom eslint arguments."
|
64
|
+
},
|
65
|
+
"dart_analyze": {
|
66
|
+
"type": ["boolean", "string"],
|
67
|
+
"description": "Whether to use 'dart analyze' or custom dart analyze arguments."
|
63
68
|
}
|
64
69
|
},
|
65
70
|
"default": {}
|
66
71
|
},
|
67
72
|
"max_issues": {
|
68
73
|
"type": "integer",
|
69
|
-
"description": "Maximum number of
|
74
|
+
"description": "Maximum number of issues to return. Set to 0 for unlimited.",
|
70
75
|
"default": 100
|
71
76
|
}
|
72
|
-
}
|
77
|
+
},
|
78
|
+
"required": []
|
73
79
|
}
|
74
80
|
}
|
75
81
|
|
@@ -108,8 +114,15 @@ async def handle_check_lint(arguments: dict) -> List[TextContent]:
|
|
108
114
|
language = _detect_language_from_file(full_path)
|
109
115
|
if language:
|
110
116
|
languages = [language]
|
117
|
+
else:
|
118
|
+
# If we can't detect a supported language for the file
|
119
|
+
_, ext = os.path.splitext(full_path)
|
120
|
+
return [TextContent(
|
121
|
+
type="text",
|
122
|
+
text=f"Unsupported file type: {ext}\nThe check_lint tool only supports: .py, .js, .jsx, .ts, .tsx, .dart files.\nSupported languages are: python, javascript, typescript, dart."
|
123
|
+
)]
|
111
124
|
else:
|
112
|
-
languages = ["python", "javascript", "typescript"] # Default to common languages
|
125
|
+
languages = ["python", "javascript", "typescript", "dart"] # Default to common languages
|
113
126
|
|
114
127
|
# Prepare linter configurations with defaults
|
115
128
|
linter_defaults = {
|
@@ -122,9 +135,41 @@ async def handle_check_lint(arguments: dict) -> List[TextContent]:
|
|
122
135
|
},
|
123
136
|
"typescript": {
|
124
137
|
"eslint": True
|
138
|
+
},
|
139
|
+
"dart": {
|
140
|
+
"dart_analyze": True
|
125
141
|
}
|
126
142
|
}
|
127
143
|
|
144
|
+
# Validate languages if explicitly specified
|
145
|
+
if languages and os.path.isfile(full_path):
|
146
|
+
_, ext = os.path.splitext(full_path)
|
147
|
+
ext_language_map = {
|
148
|
+
'.py': 'python',
|
149
|
+
'.js': 'javascript',
|
150
|
+
'.jsx': 'javascript',
|
151
|
+
'.ts': 'typescript',
|
152
|
+
'.tsx': 'typescript',
|
153
|
+
'.dart': 'dart',
|
154
|
+
'.flutter': 'dart'
|
155
|
+
}
|
156
|
+
detected_language = ext_language_map.get(ext.lower())
|
157
|
+
|
158
|
+
# If we have a mismatch between specified language and file extension
|
159
|
+
if detected_language and not any(lang == detected_language for lang in languages):
|
160
|
+
return [TextContent(
|
161
|
+
type="text",
|
162
|
+
text=f"Language mismatch: File has {ext} extension but you specified {languages}.\n"
|
163
|
+
f"For this file extension, please use: {detected_language}"
|
164
|
+
)]
|
165
|
+
|
166
|
+
# If file type is not supported at all
|
167
|
+
if not detected_language:
|
168
|
+
return [TextContent(
|
169
|
+
type="text",
|
170
|
+
text=f"Unsupported file type: {ext}\nThe check_lint tool only supports: .py, .js, .jsx, .ts, .tsx, .dart files.\nSupported languages are: python, javascript, typescript, dart."
|
171
|
+
)]
|
172
|
+
|
128
173
|
# Process each language
|
129
174
|
all_issues = []
|
130
175
|
|
@@ -378,18 +423,105 @@ async def _run_linter(linter_name: str, path: str, custom_args: str = None) -> L
|
|
378
423
|
# Silently fail if eslint is not installed
|
379
424
|
pass
|
380
425
|
|
426
|
+
elif linter_name == "dart_analyze":
|
427
|
+
try:
|
428
|
+
# Build the command
|
429
|
+
cmd = ["dart", "analyze", "--format=json"]
|
430
|
+
|
431
|
+
if custom_args:
|
432
|
+
cmd.extend(custom_args.split())
|
433
|
+
|
434
|
+
# Add target path
|
435
|
+
cmd.append(path)
|
436
|
+
|
437
|
+
# Run dart analyze
|
438
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
439
|
+
|
440
|
+
if result.stdout.strip():
|
441
|
+
# Parse Dart Analyze JSON output
|
442
|
+
try:
|
443
|
+
dart_results = json.loads(result.stdout)
|
444
|
+
for file_result in dart_results.get("issues", []):
|
445
|
+
# Get file path and ensure it's absolute
|
446
|
+
file_path = file_result.get("path", "")
|
447
|
+
if not os.path.isabs(file_path):
|
448
|
+
file_path = os.path.abspath(os.path.join(os.path.dirname(path), file_path))
|
449
|
+
|
450
|
+
# Security check for file path and exclude system directories
|
451
|
+
if not file_path.startswith(state.allowed_directory) or _is_excluded_system_directory(file_path):
|
452
|
+
continue
|
453
|
+
|
454
|
+
issues.append({
|
455
|
+
"file": os.path.relpath(file_path, state.allowed_directory),
|
456
|
+
"line": file_result.get("location", {}).get("startLine", 0),
|
457
|
+
"column": file_result.get("location", {}).get("startColumn", 0),
|
458
|
+
"message": file_result.get("message", ""),
|
459
|
+
"severity": _map_dart_severity(file_result.get("severity", "")),
|
460
|
+
"source": "dart",
|
461
|
+
"code": file_result.get("code", "")
|
462
|
+
})
|
463
|
+
except json.JSONDecodeError:
|
464
|
+
# Try parsing Flutter-specific error format (from compilation errors)
|
465
|
+
try:
|
466
|
+
# For flutter/dart compilation errors which might not be in JSON format
|
467
|
+
dart_issues = []
|
468
|
+
for line in result.stdout.splitlines() + result.stderr.splitlines():
|
469
|
+
# Check if line contains a compilation error pattern
|
470
|
+
error_match = re.search(r'(.*?):(\d+):(\d+):\s+(error|warning|info):\s+(.*)', line)
|
471
|
+
if error_match:
|
472
|
+
file_path, line_num, col, severity, message = error_match.groups()
|
473
|
+
|
474
|
+
# Ensure path is absolute for security check
|
475
|
+
if not os.path.isabs(file_path):
|
476
|
+
file_path = os.path.abspath(os.path.join(os.path.dirname(path), file_path))
|
477
|
+
|
478
|
+
# Security check for file path
|
479
|
+
if not file_path.startswith(state.allowed_directory) or _is_excluded_system_directory(file_path):
|
480
|
+
continue
|
481
|
+
|
482
|
+
dart_issues.append({
|
483
|
+
"file": os.path.relpath(file_path, state.allowed_directory),
|
484
|
+
"line": int(line_num),
|
485
|
+
"column": int(col),
|
486
|
+
"message": message,
|
487
|
+
"severity": severity,
|
488
|
+
"source": "dart",
|
489
|
+
"code": "compilation-error"
|
490
|
+
})
|
491
|
+
|
492
|
+
# If we found compilation errors, add them
|
493
|
+
issues.extend(dart_issues)
|
494
|
+
except Exception:
|
495
|
+
# Handle any parsing errors
|
496
|
+
if result.stderr:
|
497
|
+
issues.append({
|
498
|
+
"file": path if os.path.isfile(path) else "",
|
499
|
+
"line": 1,
|
500
|
+
"column": 1,
|
501
|
+
"message": f"Error running dart analyze: {result.stderr}",
|
502
|
+
"severity": "error",
|
503
|
+
"source": "dart",
|
504
|
+
"code": "tool-error"
|
505
|
+
})
|
506
|
+
except (subprocess.SubprocessError, FileNotFoundError):
|
507
|
+
# Silently fail if dart is not installed
|
508
|
+
pass
|
509
|
+
|
381
510
|
return issues
|
382
511
|
|
383
512
|
def _detect_language_from_file(file_path: str) -> Optional[str]:
|
384
|
-
"""Detect programming language based on file extension."""
|
385
|
-
ext = os.path.splitext(file_path)
|
513
|
+
"""Detect the programming language based on file extension."""
|
514
|
+
_, ext = os.path.splitext(file_path)
|
515
|
+
ext = ext.lower()
|
386
516
|
|
387
517
|
language_map = {
|
388
518
|
'.py': 'python',
|
389
519
|
'.js': 'javascript',
|
390
|
-
'.ts': 'typescript',
|
391
520
|
'.jsx': 'javascript',
|
521
|
+
'.ts': 'typescript',
|
392
522
|
'.tsx': 'typescript',
|
523
|
+
'.dart': 'dart',
|
524
|
+
'.flutter': 'dart'
|
393
525
|
}
|
394
526
|
|
395
527
|
return language_map.get(ext)
|
@@ -414,6 +546,15 @@ def _map_eslint_severity(severity: int) -> str:
|
|
414
546
|
else:
|
415
547
|
return "info"
|
416
548
|
|
549
|
+
def _map_dart_severity(severity_type: str) -> str:
|
550
|
+
"""Map dart severity levels to standard severity levels."""
|
551
|
+
severity_map = {
|
552
|
+
"info": "info",
|
553
|
+
"warning": "warning",
|
554
|
+
"error": "error",
|
555
|
+
}
|
556
|
+
return severity_map.get(severity_type.lower(), "info")
|
557
|
+
|
417
558
|
def _format_lint_results(issues: List[Dict[str, Any]]) -> str:
|
418
559
|
"""Format linting issues into a readable text output."""
|
419
560
|
if not issues:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: skydeckai-code
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.32
|
4
4
|
Summary: This MCP server provides a comprehensive set of tools for AI-driven Development workflows including file operations, code analysis, code linting, multi-language execution, Git operations, web content fetching with HTML-to-markdown conversion, multi-engine web search, code content searching, and system information retrieval.
|
5
5
|
Project-URL: Homepage, https://github.com/skydeckai/skydeckai-code
|
6
6
|
Project-URL: Repository, https://github.com/skydeckai/skydeckai-code
|
@@ -312,6 +312,7 @@ A detailed report of linting issues found in the codebase, including file paths,
|
|
312
312
|
|
313
313
|
- Python: pylint, flake8 (automatically uses what's available)
|
314
314
|
- JavaScript/TypeScript: ESLint
|
315
|
+
- Dart/Flutter: dart_analyze (also reports compilation errors)
|
315
316
|
|
316
317
|
**Example Usage:**
|
317
318
|
|
@@ -335,6 +336,15 @@ skydeckai-code-cli --tool check_lint --args '{
|
|
335
336
|
"flake8": false
|
336
337
|
}
|
337
338
|
}'
|
339
|
+
|
340
|
+
# Check Dart/Flutter files for linting and compilation errors
|
341
|
+
skydeckai-code-cli --tool check_lint --args '{
|
342
|
+
"path": "lib",
|
343
|
+
"languages": ["dart"],
|
344
|
+
"linters": {
|
345
|
+
"dart_analyze": "--fatal-infos"
|
346
|
+
}
|
347
|
+
}'
|
338
348
|
```
|
339
349
|
|
340
350
|
#### search_code
|
@@ -7,20 +7,20 @@ aidd/tools/code_analysis.py,sha256=fDpm2o_If5PsngXzHN2-ezSkPVT0ZxivLuzmHrOAmVU,3
|
|
7
7
|
aidd/tools/code_execution.py,sha256=dIPxHBtclsetDZY4jGlSBrw_t-7VlIVrK8mflnZ6c4w,13176
|
8
8
|
aidd/tools/code_tools.py,sha256=3CgkQ78iVKMd5j8aLmolLp4c59seD42Qw6VbdUcg2wA,12628
|
9
9
|
aidd/tools/directory_tools.py,sha256=Hxzge_ziYw_FsjYb5yF0R0dHEdvuWRsg7WsdYDG0AUg,12971
|
10
|
-
aidd/tools/file_tools.py,sha256
|
10
|
+
aidd/tools/file_tools.py,sha256=-OQHFCL_r1TI16-xBrwKfhzHKFgG965Jr0tAmZ9mKbI,44137
|
11
11
|
aidd/tools/get_active_apps_tool.py,sha256=BjLF7iXSDgyAmm_gfFgAul2Gn3iX-CNVYHM7Sh4jTAI,19427
|
12
12
|
aidd/tools/get_available_windows_tool.py,sha256=OVIYhItTn9u_DftOr3vPCT-R0DOFvMEEJXA6tD6gqWQ,15952
|
13
13
|
aidd/tools/git_tools.py,sha256=AgolgrZnpN2NALV7SfIwc6D7U7tdPrPTSFmU2WjPfVE,39846
|
14
14
|
aidd/tools/image_tools.py,sha256=wT3EcJAfZWcM0IsXdDfbTNjgFhKZM9nu2wHN6Mk_TTQ,5970
|
15
|
-
aidd/tools/lint_tools.py,sha256=
|
15
|
+
aidd/tools/lint_tools.py,sha256=0RYE-cXSbfw1VV_03GiFgYhC9ElhdWc4ecEjfMd9Els,25831
|
16
16
|
aidd/tools/other_tools.py,sha256=iG3Sd2FP0M0pRv5esPBAUMvlwxTyAMDUdS77IqA_f5s,10822
|
17
17
|
aidd/tools/path_tools.py,sha256=RGoOhqP69eHJzM8tEgn_5-GRaR0gp25fd0XZIJ_RnQE,4045
|
18
18
|
aidd/tools/screenshot_tool.py,sha256=NMO5B4UG8qfMEOMRd2YoOjtwz_oQ2y1UAGU22jV1yGU,46337
|
19
19
|
aidd/tools/state.py,sha256=RWSw0Jfsui8FqC0xsI7Ik07tAg35hRwLHa5xGBVbiI4,1493
|
20
20
|
aidd/tools/system_tools.py,sha256=H4_qveKC2HA7SIbi-j4vxA0W4jYh2wfu9A6ni5wkZyA,7249
|
21
21
|
aidd/tools/web_tools.py,sha256=gdsj2DEVYb_oYChItK5I1ugt2w25U7IAa5kEw9q6MVg,35534
|
22
|
-
skydeckai_code-0.1.
|
23
|
-
skydeckai_code-0.1.
|
24
|
-
skydeckai_code-0.1.
|
25
|
-
skydeckai_code-0.1.
|
26
|
-
skydeckai_code-0.1.
|
22
|
+
skydeckai_code-0.1.32.dist-info/METADATA,sha256=A71M20kCKentREoEa3YfXrpJF6m9repm6y4g--ua1QE,32850
|
23
|
+
skydeckai_code-0.1.32.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
24
|
+
skydeckai_code-0.1.32.dist-info/entry_points.txt,sha256=cT-IHh3_ioGLk3kwIeqj1X6Li1dnJinX9qKWUl7nOLg,80
|
25
|
+
skydeckai_code-0.1.32.dist-info/licenses/LICENSE,sha256=uHse04vmI6ZjW7TblegFl30X-sDyyF0-QvH8ItPca3c,10865
|
26
|
+
skydeckai_code-0.1.32.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|