skydeckai-code 0.1.23__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/__init__.py +11 -0
- aidd/cli.py +141 -0
- aidd/server.py +54 -0
- aidd/tools/__init__.py +155 -0
- aidd/tools/base.py +18 -0
- aidd/tools/code_analysis.py +703 -0
- aidd/tools/code_execution.py +321 -0
- aidd/tools/directory_tools.py +289 -0
- aidd/tools/file_tools.py +784 -0
- aidd/tools/get_active_apps_tool.py +455 -0
- aidd/tools/get_available_windows_tool.py +395 -0
- aidd/tools/git_tools.py +687 -0
- aidd/tools/image_tools.py +127 -0
- aidd/tools/path_tools.py +86 -0
- aidd/tools/screenshot_tool.py +1029 -0
- aidd/tools/state.py +47 -0
- aidd/tools/system_tools.py +190 -0
- skydeckai_code-0.1.23.dist-info/METADATA +628 -0
- skydeckai_code-0.1.23.dist-info/RECORD +22 -0
- skydeckai_code-0.1.23.dist-info/WHEEL +4 -0
- skydeckai_code-0.1.23.dist-info/entry_points.txt +3 -0
- skydeckai_code-0.1.23.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,395 @@
|
|
1
|
+
import json
|
2
|
+
import platform
|
3
|
+
import subprocess
|
4
|
+
from typing import Any, Dict, List
|
5
|
+
import importlib.util
|
6
|
+
|
7
|
+
from mcp import types
|
8
|
+
|
9
|
+
# Use importlib.util.find_spec to check for availability of optional packages
|
10
|
+
def is_package_available(package_name):
|
11
|
+
"""Check if a package is available using importlib.util.find_spec."""
|
12
|
+
return importlib.util.find_spec(package_name) is not None
|
13
|
+
|
14
|
+
# Check for PyGetWindow
|
15
|
+
PYGETWINDOW_AVAILABLE = is_package_available("pygetwindow")
|
16
|
+
|
17
|
+
# Check for macOS-specific Quartz framework
|
18
|
+
QUARTZ_AVAILABLE = False
|
19
|
+
if platform.system().lower() == "darwin":
|
20
|
+
QUARTZ_AVAILABLE = is_package_available("Quartz")
|
21
|
+
if QUARTZ_AVAILABLE:
|
22
|
+
from Quartz import (
|
23
|
+
CGWindowListCopyWindowInfo,
|
24
|
+
kCGNullWindowID,
|
25
|
+
kCGWindowListOptionOnScreenOnly,
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
def get_available_windows_tool():
|
30
|
+
"""Define the get_available_windows tool."""
|
31
|
+
return {
|
32
|
+
"name": "get_available_windows",
|
33
|
+
"description": "Get detailed information about all available windows currently displayed on the user's screen. "
|
34
|
+
"WHEN TO USE: When you need to know exactly what windows are visible to the user, find a specific "
|
35
|
+
"window by title, provide guidance related to something the user is viewing, or need window-level "
|
36
|
+
"context that's more detailed than application-level information. Useful for referencing specific "
|
37
|
+
"content the user can see on their screen. "
|
38
|
+
"WHEN NOT TO USE: When application-level information is sufficient (use get_active_apps instead), "
|
39
|
+
"when you need to capture what's on screen (use capture_screenshot instead), or when window "
|
40
|
+
"context isn't relevant to the task at hand. "
|
41
|
+
"RETURNS: JSON object containing platform information, success status, count of windows, and an "
|
42
|
+
"array of window objects. Each window object includes title, application owner, visibility status, "
|
43
|
+
"and platform-specific details like window IDs. Works on macOS, Windows, and Linux, with "
|
44
|
+
"platform-specific implementation details.",
|
45
|
+
"inputSchema": {
|
46
|
+
"type": "object",
|
47
|
+
"properties": {},
|
48
|
+
"required": []
|
49
|
+
},
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
def _get_windows_macos() -> List[Dict[str, Any]]:
|
54
|
+
"""
|
55
|
+
Get information about all available windows on macOS.
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
List of dictionaries containing window information
|
59
|
+
"""
|
60
|
+
windows = []
|
61
|
+
|
62
|
+
if not QUARTZ_AVAILABLE:
|
63
|
+
print("Quartz framework not available. Unable to list windows on macOS.")
|
64
|
+
return windows
|
65
|
+
|
66
|
+
try:
|
67
|
+
# Get the list of windows from Quartz
|
68
|
+
window_list = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID)
|
69
|
+
|
70
|
+
for window in window_list:
|
71
|
+
window_id = window.get('kCGWindowNumber', 0)
|
72
|
+
owner = window.get('kCGWindowOwnerName', '')
|
73
|
+
name = window.get('kCGWindowName', '')
|
74
|
+
layer = window.get('kCGWindowLayer', 0)
|
75
|
+
alpha = window.get('kCGWindowAlpha', 1.0)
|
76
|
+
|
77
|
+
# Create the window info dictionary
|
78
|
+
window_info = {
|
79
|
+
"id": window_id,
|
80
|
+
"title": name,
|
81
|
+
"app": owner,
|
82
|
+
"visible": layer <= 0 and alpha > 0.1,
|
83
|
+
}
|
84
|
+
|
85
|
+
windows.append(window_info)
|
86
|
+
|
87
|
+
# Sort windows by application name and then by window title
|
88
|
+
windows.sort(key=lambda w: (w.get("app", "").lower(), w.get("title", "").lower()))
|
89
|
+
|
90
|
+
except Exception as e:
|
91
|
+
print(f"Error getting windows on macOS: {str(e)}")
|
92
|
+
|
93
|
+
return windows
|
94
|
+
|
95
|
+
|
96
|
+
def _get_windows_windows() -> List[Dict[str, Any]]:
|
97
|
+
"""
|
98
|
+
Get information about all available windows on Windows.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
List of dictionaries containing window information
|
102
|
+
"""
|
103
|
+
windows = []
|
104
|
+
|
105
|
+
# Try using PyGetWindow if available
|
106
|
+
if PYGETWINDOW_AVAILABLE:
|
107
|
+
try:
|
108
|
+
import pygetwindow as gw
|
109
|
+
all_windows = gw.getAllWindows()
|
110
|
+
|
111
|
+
for window in all_windows:
|
112
|
+
# Skip windows with empty titles
|
113
|
+
if not window.title:
|
114
|
+
continue
|
115
|
+
|
116
|
+
# Try to determine the application name from the window title
|
117
|
+
# This is an approximation and may not be accurate for all applications
|
118
|
+
app_name = ""
|
119
|
+
title_parts = window.title.split(' - ')
|
120
|
+
if len(title_parts) > 1:
|
121
|
+
app_name = title_parts[-1]
|
122
|
+
|
123
|
+
# Create the window info dictionary
|
124
|
+
window_info = {
|
125
|
+
"title": window.title,
|
126
|
+
"visible": window.visible,
|
127
|
+
"active": window.isActive
|
128
|
+
}
|
129
|
+
|
130
|
+
# Add app name if we were able to determine it
|
131
|
+
if app_name:
|
132
|
+
window_info["app"] = app_name
|
133
|
+
|
134
|
+
windows.append(window_info)
|
135
|
+
|
136
|
+
# Sort windows by application name and then by window title
|
137
|
+
windows.sort(key=lambda w: (w.get("app", "").lower() if "app" in w else "", w.get("title", "").lower()))
|
138
|
+
|
139
|
+
except Exception as e:
|
140
|
+
print(f"Error getting windows with PyGetWindow: {str(e)}")
|
141
|
+
|
142
|
+
# If PyGetWindow failed or isn't available, try using PowerShell
|
143
|
+
if not windows:
|
144
|
+
try:
|
145
|
+
script = '''
|
146
|
+
Add-Type @"
|
147
|
+
using System;
|
148
|
+
using System.Runtime.InteropServices;
|
149
|
+
using System.Text;
|
150
|
+
|
151
|
+
public class Window {
|
152
|
+
[DllImport("user32.dll")]
|
153
|
+
[return: MarshalAs(UnmanagedType.Bool)]
|
154
|
+
public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
|
155
|
+
|
156
|
+
[DllImport("user32.dll")]
|
157
|
+
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
158
|
+
|
159
|
+
[DllImport("user32.dll")]
|
160
|
+
public static extern bool IsWindowVisible(IntPtr hWnd);
|
161
|
+
|
162
|
+
[DllImport("user32.dll", SetLastError=true)]
|
163
|
+
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
164
|
+
|
165
|
+
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
166
|
+
}
|
167
|
+
"@
|
168
|
+
|
169
|
+
$windows = @()
|
170
|
+
|
171
|
+
$enumWindowsCallback = {
|
172
|
+
param($hwnd, $lParam)
|
173
|
+
|
174
|
+
# Get the window title
|
175
|
+
$sb = New-Object System.Text.StringBuilder(256)
|
176
|
+
[void][Window]::GetWindowText($hwnd, $sb, $sb.Capacity)
|
177
|
+
$title = $sb.ToString()
|
178
|
+
|
179
|
+
# Only process windows with titles
|
180
|
+
if($title -and $title -ne "") {
|
181
|
+
# Check if the window is visible
|
182
|
+
$visible = [Window]::IsWindowVisible($hwnd)
|
183
|
+
|
184
|
+
# Get process ID and name
|
185
|
+
$processId = 0
|
186
|
+
[void][Window]::GetWindowThreadProcessId($hwnd, [ref]$processId)
|
187
|
+
$process = Get-Process -Id $processId -ErrorAction SilentlyContinue
|
188
|
+
$processName = if($process) { $process.ProcessName } else { "Unknown" }
|
189
|
+
|
190
|
+
# Create the window object
|
191
|
+
$window = @{
|
192
|
+
title = $title
|
193
|
+
app = $processName
|
194
|
+
visible = $visible
|
195
|
+
}
|
196
|
+
|
197
|
+
$windows += $window
|
198
|
+
}
|
199
|
+
|
200
|
+
# Continue enumeration
|
201
|
+
return $true
|
202
|
+
}
|
203
|
+
|
204
|
+
# Enumerate all windows
|
205
|
+
[void][Window]::EnumWindows($enumWindowsCallback, [IntPtr]::Zero)
|
206
|
+
|
207
|
+
# Sort the windows
|
208
|
+
$windows = $windows | Sort-Object -Property @{Expression="app"}, @{Expression="title"}
|
209
|
+
|
210
|
+
# Convert to JSON
|
211
|
+
$windows | ConvertTo-Json -Depth 3
|
212
|
+
'''
|
213
|
+
|
214
|
+
cmd = ["powershell", "-Command", script]
|
215
|
+
process = subprocess.run(cmd, capture_output=True, text=True)
|
216
|
+
|
217
|
+
if process.returncode == 0 and process.stdout.strip():
|
218
|
+
try:
|
219
|
+
windows_data = json.loads(process.stdout)
|
220
|
+
# Handle single item (not in a list)
|
221
|
+
if isinstance(windows_data, dict):
|
222
|
+
windows_data = [windows_data]
|
223
|
+
|
224
|
+
windows = windows_data
|
225
|
+
except json.JSONDecodeError:
|
226
|
+
print("Failed to parse JSON from PowerShell output")
|
227
|
+
|
228
|
+
except Exception as e:
|
229
|
+
print(f"Error getting windows with PowerShell: {str(e)}")
|
230
|
+
|
231
|
+
return windows
|
232
|
+
|
233
|
+
|
234
|
+
def _get_windows_linux() -> List[Dict[str, Any]]:
|
235
|
+
"""
|
236
|
+
Get information about all available windows on Linux.
|
237
|
+
|
238
|
+
Returns:
|
239
|
+
List of dictionaries containing window information
|
240
|
+
"""
|
241
|
+
windows = []
|
242
|
+
|
243
|
+
# Try using wmctrl if available
|
244
|
+
try:
|
245
|
+
# Check if wmctrl is installed
|
246
|
+
check_process = subprocess.run(["which", "wmctrl"], capture_output=True)
|
247
|
+
if check_process.returncode == 0:
|
248
|
+
# Get the list of windows
|
249
|
+
wmctrl_process = subprocess.run(["wmctrl", "-l"], capture_output=True, text=True)
|
250
|
+
|
251
|
+
if wmctrl_process.returncode == 0:
|
252
|
+
window_data = wmctrl_process.stdout.strip().split('\n')
|
253
|
+
|
254
|
+
for line in window_data:
|
255
|
+
if not line:
|
256
|
+
continue
|
257
|
+
|
258
|
+
parts = line.split(None, 3)
|
259
|
+
if len(parts) < 4:
|
260
|
+
continue
|
261
|
+
|
262
|
+
window_id, desktop, owner, *title_parts = parts
|
263
|
+
title = title_parts[0] if title_parts else ""
|
264
|
+
|
265
|
+
# Create the window info dictionary
|
266
|
+
window_info = {
|
267
|
+
"id": window_id,
|
268
|
+
"title": title,
|
269
|
+
"app": owner,
|
270
|
+
"desktop": desktop,
|
271
|
+
"visible": True # wmctrl -l only shows visible windows
|
272
|
+
}
|
273
|
+
|
274
|
+
windows.append(window_info)
|
275
|
+
|
276
|
+
# Sort windows by application name and then by window title
|
277
|
+
windows.sort(key=lambda w: (w.get("app", "").lower(), w.get("title", "").lower()))
|
278
|
+
except Exception as e:
|
279
|
+
print(f"Error getting windows with wmctrl: {str(e)}")
|
280
|
+
|
281
|
+
# If wmctrl failed, try using xwininfo and xprop
|
282
|
+
if not windows:
|
283
|
+
try:
|
284
|
+
# Get the list of window IDs
|
285
|
+
xwininfo_process = subprocess.run(["xwininfo", "-root", "-children"], capture_output=True, text=True)
|
286
|
+
|
287
|
+
if xwininfo_process.returncode == 0:
|
288
|
+
lines = xwininfo_process.stdout.strip().split('\n')
|
289
|
+
|
290
|
+
# Parse the output to find window IDs
|
291
|
+
window_ids = []
|
292
|
+
for line in lines:
|
293
|
+
# Look for lines with window IDs in hexadecimal format
|
294
|
+
if "0x" in line and "child" in line.lower():
|
295
|
+
parts = line.split()
|
296
|
+
for part in parts:
|
297
|
+
if part.startswith("0x"):
|
298
|
+
window_ids.append(part)
|
299
|
+
break
|
300
|
+
|
301
|
+
# Get information for each window
|
302
|
+
for window_id in window_ids:
|
303
|
+
# Get window name
|
304
|
+
xprop_name_process = subprocess.run(["xprop", "-id", window_id, "WM_NAME"], capture_output=True, text=True)
|
305
|
+
|
306
|
+
# Get window class (application)
|
307
|
+
xprop_class_process = subprocess.run(["xprop", "-id", window_id, "WM_CLASS"], capture_output=True, text=True)
|
308
|
+
|
309
|
+
# Extract the window title
|
310
|
+
title = ""
|
311
|
+
if xprop_name_process.returncode == 0:
|
312
|
+
output = xprop_name_process.stdout.strip()
|
313
|
+
if "=" in output:
|
314
|
+
title = output.split("=", 1)[1].strip().strip('"')
|
315
|
+
|
316
|
+
# Extract the application name
|
317
|
+
app_name = ""
|
318
|
+
if xprop_class_process.returncode == 0:
|
319
|
+
output = xprop_class_process.stdout.strip()
|
320
|
+
if "=" in output:
|
321
|
+
classes = output.split("=", 1)[1].strip().strip('"').split('", "')
|
322
|
+
app_name = classes[-1] if classes else ""
|
323
|
+
|
324
|
+
# Create the window info dictionary
|
325
|
+
window_info = {
|
326
|
+
"id": window_id,
|
327
|
+
"title": title,
|
328
|
+
"app": app_name,
|
329
|
+
"visible": True # Assuming all retrieved windows are visible
|
330
|
+
}
|
331
|
+
|
332
|
+
windows.append(window_info)
|
333
|
+
|
334
|
+
# Sort windows by application name and then by window title
|
335
|
+
windows.sort(key=lambda w: (w.get("app", "").lower(), w.get("title", "").lower()))
|
336
|
+
except Exception as e:
|
337
|
+
print(f"Error getting windows with xwininfo/xprop: {str(e)}")
|
338
|
+
|
339
|
+
return windows
|
340
|
+
|
341
|
+
|
342
|
+
def get_available_windows() -> Dict[str, Any]:
|
343
|
+
"""
|
344
|
+
Get detailed information about all available windows currently displayed on screen.
|
345
|
+
|
346
|
+
Returns:
|
347
|
+
Dictionary with platform, success status, and list of windows
|
348
|
+
"""
|
349
|
+
system_name = platform.system().lower()
|
350
|
+
|
351
|
+
# Get windows based on platform
|
352
|
+
if system_name == "darwin" or system_name == "macos":
|
353
|
+
windows = _get_windows_macos()
|
354
|
+
elif system_name == "windows":
|
355
|
+
windows = _get_windows_windows()
|
356
|
+
elif system_name == "linux":
|
357
|
+
windows = _get_windows_linux()
|
358
|
+
else:
|
359
|
+
return {
|
360
|
+
"success": False,
|
361
|
+
"platform": system_name,
|
362
|
+
"error": f"Unsupported platform: {system_name}. This tool currently supports macOS, Windows, and Linux.",
|
363
|
+
"windows": []
|
364
|
+
}
|
365
|
+
|
366
|
+
# If no windows were found, provide a descriptive error message
|
367
|
+
if not windows:
|
368
|
+
error_message = "No windows could be detected on your screen. "
|
369
|
+
if system_name == "darwin":
|
370
|
+
error_message += "This might be due to missing screen recording permissions. Please check System Settings > Privacy & Security > Screen Recording."
|
371
|
+
elif system_name == "windows":
|
372
|
+
error_message += "This might be due to insufficient permissions or no windows being displayed."
|
373
|
+
elif system_name == "linux":
|
374
|
+
error_message += "This might be due to wmctrl or xwininfo not being installed or no windows being displayed."
|
375
|
+
|
376
|
+
return {
|
377
|
+
"success": False,
|
378
|
+
"platform": system_name,
|
379
|
+
"error": error_message,
|
380
|
+
"windows": []
|
381
|
+
}
|
382
|
+
|
383
|
+
return {
|
384
|
+
"success": True,
|
385
|
+
"platform": system_name,
|
386
|
+
"count": len(windows),
|
387
|
+
"windows": windows
|
388
|
+
}
|
389
|
+
|
390
|
+
|
391
|
+
async def handle_get_available_windows(arguments: dict) -> List[types.TextContent]:
|
392
|
+
"""Handle getting available windows."""
|
393
|
+
result = get_available_windows()
|
394
|
+
|
395
|
+
return [types.TextContent(type="text", text=json.dumps(result, indent=2))]
|