mcli-framework 7.0.0__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 mcli-framework might be problematic. Click here for more details.
- mcli/app/chat_cmd.py +42 -0
- mcli/app/commands_cmd.py +226 -0
- mcli/app/completion_cmd.py +216 -0
- mcli/app/completion_helpers.py +288 -0
- mcli/app/cron_test_cmd.py +697 -0
- mcli/app/logs_cmd.py +419 -0
- mcli/app/main.py +492 -0
- mcli/app/model/model.py +1060 -0
- mcli/app/model_cmd.py +227 -0
- mcli/app/redis_cmd.py +269 -0
- mcli/app/video/video.py +1114 -0
- mcli/app/visual_cmd.py +303 -0
- mcli/chat/chat.py +2409 -0
- mcli/chat/command_rag.py +514 -0
- mcli/chat/enhanced_chat.py +652 -0
- mcli/chat/system_controller.py +1010 -0
- mcli/chat/system_integration.py +1016 -0
- mcli/cli.py +25 -0
- mcli/config.toml +20 -0
- mcli/lib/api/api.py +586 -0
- mcli/lib/api/daemon_client.py +203 -0
- mcli/lib/api/daemon_client_local.py +44 -0
- mcli/lib/api/daemon_decorator.py +217 -0
- mcli/lib/api/mcli_decorators.py +1032 -0
- mcli/lib/auth/auth.py +85 -0
- mcli/lib/auth/aws_manager.py +85 -0
- mcli/lib/auth/azure_manager.py +91 -0
- mcli/lib/auth/credential_manager.py +192 -0
- mcli/lib/auth/gcp_manager.py +93 -0
- mcli/lib/auth/key_manager.py +117 -0
- mcli/lib/auth/mcli_manager.py +93 -0
- mcli/lib/auth/token_manager.py +75 -0
- mcli/lib/auth/token_util.py +1011 -0
- mcli/lib/config/config.py +47 -0
- mcli/lib/discovery/__init__.py +1 -0
- mcli/lib/discovery/command_discovery.py +274 -0
- mcli/lib/erd/erd.py +1345 -0
- mcli/lib/erd/generate_graph.py +453 -0
- mcli/lib/files/files.py +76 -0
- mcli/lib/fs/fs.py +109 -0
- mcli/lib/lib.py +29 -0
- mcli/lib/logger/logger.py +611 -0
- mcli/lib/performance/optimizer.py +409 -0
- mcli/lib/performance/rust_bridge.py +502 -0
- mcli/lib/performance/uvloop_config.py +154 -0
- mcli/lib/pickles/pickles.py +50 -0
- mcli/lib/search/cached_vectorizer.py +479 -0
- mcli/lib/services/data_pipeline.py +460 -0
- mcli/lib/services/lsh_client.py +441 -0
- mcli/lib/services/redis_service.py +387 -0
- mcli/lib/shell/shell.py +137 -0
- mcli/lib/toml/toml.py +33 -0
- mcli/lib/ui/styling.py +47 -0
- mcli/lib/ui/visual_effects.py +634 -0
- mcli/lib/watcher/watcher.py +185 -0
- mcli/ml/api/app.py +215 -0
- mcli/ml/api/middleware.py +224 -0
- mcli/ml/api/routers/admin_router.py +12 -0
- mcli/ml/api/routers/auth_router.py +244 -0
- mcli/ml/api/routers/backtest_router.py +12 -0
- mcli/ml/api/routers/data_router.py +12 -0
- mcli/ml/api/routers/model_router.py +302 -0
- mcli/ml/api/routers/monitoring_router.py +12 -0
- mcli/ml/api/routers/portfolio_router.py +12 -0
- mcli/ml/api/routers/prediction_router.py +267 -0
- mcli/ml/api/routers/trade_router.py +12 -0
- mcli/ml/api/routers/websocket_router.py +76 -0
- mcli/ml/api/schemas.py +64 -0
- mcli/ml/auth/auth_manager.py +425 -0
- mcli/ml/auth/models.py +154 -0
- mcli/ml/auth/permissions.py +302 -0
- mcli/ml/backtesting/backtest_engine.py +502 -0
- mcli/ml/backtesting/performance_metrics.py +393 -0
- mcli/ml/cache.py +400 -0
- mcli/ml/cli/main.py +398 -0
- mcli/ml/config/settings.py +394 -0
- mcli/ml/configs/dvc_config.py +230 -0
- mcli/ml/configs/mlflow_config.py +131 -0
- mcli/ml/configs/mlops_manager.py +293 -0
- mcli/ml/dashboard/app.py +532 -0
- mcli/ml/dashboard/app_integrated.py +738 -0
- mcli/ml/dashboard/app_supabase.py +560 -0
- mcli/ml/dashboard/app_training.py +615 -0
- mcli/ml/dashboard/cli.py +51 -0
- mcli/ml/data_ingestion/api_connectors.py +501 -0
- mcli/ml/data_ingestion/data_pipeline.py +567 -0
- mcli/ml/data_ingestion/stream_processor.py +512 -0
- mcli/ml/database/migrations/env.py +94 -0
- mcli/ml/database/models.py +667 -0
- mcli/ml/database/session.py +200 -0
- mcli/ml/experimentation/ab_testing.py +845 -0
- mcli/ml/features/ensemble_features.py +607 -0
- mcli/ml/features/political_features.py +676 -0
- mcli/ml/features/recommendation_engine.py +809 -0
- mcli/ml/features/stock_features.py +573 -0
- mcli/ml/features/test_feature_engineering.py +346 -0
- mcli/ml/logging.py +85 -0
- mcli/ml/mlops/data_versioning.py +518 -0
- mcli/ml/mlops/experiment_tracker.py +377 -0
- mcli/ml/mlops/model_serving.py +481 -0
- mcli/ml/mlops/pipeline_orchestrator.py +614 -0
- mcli/ml/models/base_models.py +324 -0
- mcli/ml/models/ensemble_models.py +675 -0
- mcli/ml/models/recommendation_models.py +474 -0
- mcli/ml/models/test_models.py +487 -0
- mcli/ml/monitoring/drift_detection.py +676 -0
- mcli/ml/monitoring/metrics.py +45 -0
- mcli/ml/optimization/portfolio_optimizer.py +834 -0
- mcli/ml/preprocessing/data_cleaners.py +451 -0
- mcli/ml/preprocessing/feature_extractors.py +491 -0
- mcli/ml/preprocessing/ml_pipeline.py +382 -0
- mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
- mcli/ml/preprocessing/test_preprocessing.py +294 -0
- mcli/ml/scripts/populate_sample_data.py +200 -0
- mcli/ml/tasks.py +400 -0
- mcli/ml/tests/test_integration.py +429 -0
- mcli/ml/tests/test_training_dashboard.py +387 -0
- mcli/public/oi/oi.py +15 -0
- mcli/public/public.py +4 -0
- mcli/self/self_cmd.py +1246 -0
- mcli/workflow/daemon/api_daemon.py +800 -0
- mcli/workflow/daemon/async_command_database.py +681 -0
- mcli/workflow/daemon/async_process_manager.py +591 -0
- mcli/workflow/daemon/client.py +530 -0
- mcli/workflow/daemon/commands.py +1196 -0
- mcli/workflow/daemon/daemon.py +905 -0
- mcli/workflow/daemon/daemon_api.py +59 -0
- mcli/workflow/daemon/enhanced_daemon.py +571 -0
- mcli/workflow/daemon/process_cli.py +244 -0
- mcli/workflow/daemon/process_manager.py +439 -0
- mcli/workflow/daemon/test_daemon.py +275 -0
- mcli/workflow/dashboard/dashboard_cmd.py +113 -0
- mcli/workflow/docker/docker.py +0 -0
- mcli/workflow/file/file.py +100 -0
- mcli/workflow/gcloud/config.toml +21 -0
- mcli/workflow/gcloud/gcloud.py +58 -0
- mcli/workflow/git_commit/ai_service.py +328 -0
- mcli/workflow/git_commit/commands.py +430 -0
- mcli/workflow/lsh_integration.py +355 -0
- mcli/workflow/model_service/client.py +594 -0
- mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
- mcli/workflow/model_service/lightweight_embedder.py +397 -0
- mcli/workflow/model_service/lightweight_model_server.py +714 -0
- mcli/workflow/model_service/lightweight_test.py +241 -0
- mcli/workflow/model_service/model_service.py +1955 -0
- mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
- mcli/workflow/model_service/pdf_processor.py +386 -0
- mcli/workflow/model_service/test_efficient_runner.py +234 -0
- mcli/workflow/model_service/test_example.py +315 -0
- mcli/workflow/model_service/test_integration.py +131 -0
- mcli/workflow/model_service/test_new_features.py +149 -0
- mcli/workflow/openai/openai.py +99 -0
- mcli/workflow/politician_trading/commands.py +1790 -0
- mcli/workflow/politician_trading/config.py +134 -0
- mcli/workflow/politician_trading/connectivity.py +490 -0
- mcli/workflow/politician_trading/data_sources.py +395 -0
- mcli/workflow/politician_trading/database.py +410 -0
- mcli/workflow/politician_trading/demo.py +248 -0
- mcli/workflow/politician_trading/models.py +165 -0
- mcli/workflow/politician_trading/monitoring.py +413 -0
- mcli/workflow/politician_trading/scrapers.py +966 -0
- mcli/workflow/politician_trading/scrapers_california.py +412 -0
- mcli/workflow/politician_trading/scrapers_eu.py +377 -0
- mcli/workflow/politician_trading/scrapers_uk.py +350 -0
- mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
- mcli/workflow/politician_trading/supabase_functions.py +354 -0
- mcli/workflow/politician_trading/workflow.py +852 -0
- mcli/workflow/registry/registry.py +180 -0
- mcli/workflow/repo/repo.py +223 -0
- mcli/workflow/scheduler/commands.py +493 -0
- mcli/workflow/scheduler/cron_parser.py +238 -0
- mcli/workflow/scheduler/job.py +182 -0
- mcli/workflow/scheduler/monitor.py +139 -0
- mcli/workflow/scheduler/persistence.py +324 -0
- mcli/workflow/scheduler/scheduler.py +679 -0
- mcli/workflow/sync/sync_cmd.py +437 -0
- mcli/workflow/sync/test_cmd.py +314 -0
- mcli/workflow/videos/videos.py +242 -0
- mcli/workflow/wakatime/wakatime.py +11 -0
- mcli/workflow/workflow.py +37 -0
- mcli_framework-7.0.0.dist-info/METADATA +479 -0
- mcli_framework-7.0.0.dist-info/RECORD +186 -0
- mcli_framework-7.0.0.dist-info/WHEEL +5 -0
- mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
- mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
- mcli_framework-7.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
"""
|
|
2
|
+
System Integration for MCLI Chat
|
|
3
|
+
Provides system control capabilities directly within chat conversations
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from typing import Any, Dict, List
|
|
8
|
+
|
|
9
|
+
from mcli.lib.logger.logger import get_logger
|
|
10
|
+
|
|
11
|
+
from .system_controller import (
|
|
12
|
+
change_directory,
|
|
13
|
+
clean_simulator_data,
|
|
14
|
+
control_app,
|
|
15
|
+
execute_shell_command,
|
|
16
|
+
execute_system_command,
|
|
17
|
+
get_current_directory,
|
|
18
|
+
list_directory,
|
|
19
|
+
open_file_or_url,
|
|
20
|
+
open_textedit_and_write,
|
|
21
|
+
system_controller,
|
|
22
|
+
take_screenshot,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = get_logger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ChatSystemIntegration:
|
|
29
|
+
"""Integration layer between chat and system control"""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.system_controller = system_controller
|
|
33
|
+
self.enabled = True
|
|
34
|
+
|
|
35
|
+
# Define available system functions
|
|
36
|
+
self.system_functions = {
|
|
37
|
+
"open_textedit_and_write": {
|
|
38
|
+
"function": open_textedit_and_write,
|
|
39
|
+
"description": "Open TextEdit and write specified text",
|
|
40
|
+
"parameters": {
|
|
41
|
+
"text": "Text to write in TextEdit",
|
|
42
|
+
"filename": "Optional filename to save (will save to Desktop)",
|
|
43
|
+
},
|
|
44
|
+
"examples": [
|
|
45
|
+
"Open TextEdit and write 'Hello, World!'",
|
|
46
|
+
"Write 'My notes' in TextEdit and save as 'notes.txt'",
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
"control_application": {
|
|
50
|
+
"function": control_app,
|
|
51
|
+
"description": "Control system applications (open, close, interact)",
|
|
52
|
+
"parameters": {
|
|
53
|
+
"app_name": "Name of the application (e.g., 'TextEdit', 'Calculator')",
|
|
54
|
+
"action": "Action to perform (open, close, new_document, write_text)",
|
|
55
|
+
"**kwargs": "Additional parameters like text, filename",
|
|
56
|
+
},
|
|
57
|
+
"examples": ["Open Calculator", "Close TextEdit", "Open new document in TextEdit"],
|
|
58
|
+
},
|
|
59
|
+
"execute_command": {
|
|
60
|
+
"function": execute_system_command,
|
|
61
|
+
"description": "Execute shell/terminal commands",
|
|
62
|
+
"parameters": {
|
|
63
|
+
"command": "Shell command to execute",
|
|
64
|
+
"description": "Optional description of what the command does",
|
|
65
|
+
},
|
|
66
|
+
"examples": [
|
|
67
|
+
"List files in current directory",
|
|
68
|
+
"Check system uptime",
|
|
69
|
+
"Create a new folder",
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
"take_screenshot": {
|
|
73
|
+
"function": take_screenshot,
|
|
74
|
+
"description": "Take a screenshot and save to Desktop",
|
|
75
|
+
"parameters": {
|
|
76
|
+
"filename": "Optional filename (will auto-generate if not provided)"
|
|
77
|
+
},
|
|
78
|
+
"examples": ["Take a screenshot", "Take screenshot and save as 'my_screen.png'"],
|
|
79
|
+
},
|
|
80
|
+
"open_file_or_url": {
|
|
81
|
+
"function": open_file_or_url,
|
|
82
|
+
"description": "Open files or URLs with default system application",
|
|
83
|
+
"parameters": {"path_or_url": "File path or URL to open"},
|
|
84
|
+
"examples": [
|
|
85
|
+
"Open https://google.com",
|
|
86
|
+
"Open ~/Documents/file.txt",
|
|
87
|
+
"Open current directory in Finder",
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
"get_system_info": {
|
|
91
|
+
"function": self.system_controller.get_system_info,
|
|
92
|
+
"description": "Get comprehensive system information (CPU, memory, disk, etc.)",
|
|
93
|
+
"parameters": {},
|
|
94
|
+
"examples": [
|
|
95
|
+
"What is my system information?",
|
|
96
|
+
"Show system specs",
|
|
97
|
+
"How much RAM do I have?",
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
"get_system_time": {
|
|
101
|
+
"function": self.system_controller.get_system_time,
|
|
102
|
+
"description": "Get current system time and date",
|
|
103
|
+
"parameters": {},
|
|
104
|
+
"examples": [
|
|
105
|
+
"What time is it?",
|
|
106
|
+
"What is the current time?",
|
|
107
|
+
"Show me the date and time",
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
"get_memory_usage": {
|
|
111
|
+
"function": self.system_controller.get_memory_usage,
|
|
112
|
+
"description": "Get detailed memory usage information",
|
|
113
|
+
"parameters": {},
|
|
114
|
+
"examples": ["How much memory am I using?", "Show memory usage", "Check RAM usage"],
|
|
115
|
+
},
|
|
116
|
+
"get_disk_usage": {
|
|
117
|
+
"function": self.system_controller.get_disk_usage,
|
|
118
|
+
"description": "Get disk space and usage information",
|
|
119
|
+
"parameters": {},
|
|
120
|
+
"examples": [
|
|
121
|
+
"How much disk space do I have?",
|
|
122
|
+
"Show disk usage",
|
|
123
|
+
"Check storage space",
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
"clear_system_caches": {
|
|
127
|
+
"function": self.system_controller.clear_system_caches,
|
|
128
|
+
"description": "Clear system caches and temporary files",
|
|
129
|
+
"parameters": {},
|
|
130
|
+
"examples": ["Clear system caches", "Clean up temporary files", "Free up space"],
|
|
131
|
+
},
|
|
132
|
+
"change_directory": {
|
|
133
|
+
"function": change_directory,
|
|
134
|
+
"description": "Navigate to a directory",
|
|
135
|
+
"parameters": {"path": "Directory path to navigate to"},
|
|
136
|
+
"examples": [
|
|
137
|
+
"Navigate to /System/Volumes/Data",
|
|
138
|
+
"Go to ~/Documents",
|
|
139
|
+
"Change to /tmp",
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
"list_directory": {
|
|
143
|
+
"function": list_directory,
|
|
144
|
+
"description": "List contents of a directory",
|
|
145
|
+
"parameters": {
|
|
146
|
+
"path": "Directory path to list (optional, defaults to current)",
|
|
147
|
+
"show_hidden": "Show hidden files (optional)",
|
|
148
|
+
"detailed": "Show detailed file information (optional)",
|
|
149
|
+
},
|
|
150
|
+
"examples": [
|
|
151
|
+
"List current directory",
|
|
152
|
+
"Show files in /System/Volumes/Data",
|
|
153
|
+
"List all files including hidden ones",
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
"clean_simulator_data": {
|
|
157
|
+
"function": clean_simulator_data,
|
|
158
|
+
"description": "Clean iOS/watchOS simulator cache and temporary data",
|
|
159
|
+
"parameters": {},
|
|
160
|
+
"examples": [
|
|
161
|
+
"Clean simulator data",
|
|
162
|
+
"Remove iOS simulator caches",
|
|
163
|
+
"Free up simulator storage",
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
"execute_shell_command": {
|
|
167
|
+
"function": execute_shell_command,
|
|
168
|
+
"description": "Execute shell commands with full terminal access",
|
|
169
|
+
"parameters": {
|
|
170
|
+
"command": "Shell command to execute",
|
|
171
|
+
"working_directory": "Directory to run command in (optional)",
|
|
172
|
+
},
|
|
173
|
+
"examples": ["Run ls -la", "Execute find command", "Run custom shell scripts"],
|
|
174
|
+
},
|
|
175
|
+
"get_current_directory": {
|
|
176
|
+
"function": get_current_directory,
|
|
177
|
+
"description": "Get current working directory",
|
|
178
|
+
"parameters": {},
|
|
179
|
+
"examples": ["Where am I?", "Show current directory", "What's my current path?"],
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
def handle_system_request(self, request: str) -> Dict[str, Any]:
|
|
184
|
+
"""
|
|
185
|
+
Analyze user request and execute appropriate system function
|
|
186
|
+
This is the main entry point for chat system integration
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
if not self.enabled:
|
|
190
|
+
return {
|
|
191
|
+
"success": False,
|
|
192
|
+
"error": "System control is disabled",
|
|
193
|
+
"suggestion": "Enable system control to use this feature",
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Parse the request and determine action
|
|
197
|
+
request_lower = request.lower()
|
|
198
|
+
|
|
199
|
+
# System information requests
|
|
200
|
+
if any(
|
|
201
|
+
phrase in request_lower
|
|
202
|
+
for phrase in ["what time", "current time", "system time", "what is the time"]
|
|
203
|
+
):
|
|
204
|
+
return self._handle_system_time_request(request)
|
|
205
|
+
|
|
206
|
+
elif any(
|
|
207
|
+
phrase in request_lower
|
|
208
|
+
for phrase in ["system info", "system information", "system specs", "hardware info"]
|
|
209
|
+
):
|
|
210
|
+
return self._handle_system_info_request(request)
|
|
211
|
+
|
|
212
|
+
# Hardware devices requests
|
|
213
|
+
elif any(
|
|
214
|
+
phrase in request_lower
|
|
215
|
+
for phrase in [
|
|
216
|
+
"hardware devices",
|
|
217
|
+
"connected devices",
|
|
218
|
+
"list hardware",
|
|
219
|
+
"show devices",
|
|
220
|
+
"connected hardware",
|
|
221
|
+
]
|
|
222
|
+
):
|
|
223
|
+
return self._handle_hardware_devices_request(request)
|
|
224
|
+
|
|
225
|
+
elif any(
|
|
226
|
+
phrase in request_lower
|
|
227
|
+
for phrase in [
|
|
228
|
+
"memory usage",
|
|
229
|
+
"ram usage",
|
|
230
|
+
"how much memory",
|
|
231
|
+
"how much ram",
|
|
232
|
+
"memory info",
|
|
233
|
+
]
|
|
234
|
+
):
|
|
235
|
+
return self._handle_memory_request(request)
|
|
236
|
+
|
|
237
|
+
elif any(
|
|
238
|
+
phrase in request_lower
|
|
239
|
+
for phrase in [
|
|
240
|
+
"disk usage",
|
|
241
|
+
"disk space",
|
|
242
|
+
"storage space",
|
|
243
|
+
"how much space",
|
|
244
|
+
"free space",
|
|
245
|
+
]
|
|
246
|
+
):
|
|
247
|
+
return self._handle_disk_request(request)
|
|
248
|
+
|
|
249
|
+
elif any(
|
|
250
|
+
phrase in request_lower
|
|
251
|
+
for phrase in [
|
|
252
|
+
"clear cache",
|
|
253
|
+
"clean cache",
|
|
254
|
+
"clear temp",
|
|
255
|
+
"free up space",
|
|
256
|
+
"clean system",
|
|
257
|
+
"clear system cache",
|
|
258
|
+
]
|
|
259
|
+
):
|
|
260
|
+
return self._handle_cache_clear_request(request)
|
|
261
|
+
|
|
262
|
+
# Navigation requests
|
|
263
|
+
elif any(
|
|
264
|
+
phrase in request_lower
|
|
265
|
+
for phrase in ["navigate to", "go to", "change to", "cd to", "move to"]
|
|
266
|
+
):
|
|
267
|
+
return self._handle_navigation_request(request)
|
|
268
|
+
|
|
269
|
+
# Directory listing requests (more specific to avoid false positives)
|
|
270
|
+
elif any(
|
|
271
|
+
phrase in request_lower
|
|
272
|
+
for phrase in ["list files", "list directory", "show files", "ls", "dir", "what's in"]
|
|
273
|
+
):
|
|
274
|
+
return self._handle_directory_listing_request(request)
|
|
275
|
+
|
|
276
|
+
# Simulator cleanup requests
|
|
277
|
+
elif any(
|
|
278
|
+
phrase in request_lower
|
|
279
|
+
for phrase in ["clean simulator", "simulator data", "clean ios", "clean watchos"]
|
|
280
|
+
):
|
|
281
|
+
return self._handle_simulator_cleanup_request(request)
|
|
282
|
+
|
|
283
|
+
# Shell command requests
|
|
284
|
+
elif any(
|
|
285
|
+
phrase in request_lower for phrase in ["run command", "execute", "shell", "terminal"]
|
|
286
|
+
):
|
|
287
|
+
return self._handle_shell_command_request(request)
|
|
288
|
+
|
|
289
|
+
# Current directory requests
|
|
290
|
+
elif any(
|
|
291
|
+
phrase in request_lower
|
|
292
|
+
for phrase in ["where am i", "current directory", "pwd", "current path"]
|
|
293
|
+
):
|
|
294
|
+
return self._handle_current_directory_request(request)
|
|
295
|
+
|
|
296
|
+
# TextEdit operations
|
|
297
|
+
elif "textedit" in request_lower and ("write" in request_lower or "type" in request_lower):
|
|
298
|
+
return self._handle_textedit_request(request)
|
|
299
|
+
|
|
300
|
+
# Application control
|
|
301
|
+
elif any(word in request_lower for word in ["open", "close", "launch", "quit"]):
|
|
302
|
+
return self._handle_app_control_request(request)
|
|
303
|
+
|
|
304
|
+
# Screenshot
|
|
305
|
+
elif "screenshot" in request_lower or "screen capture" in request_lower:
|
|
306
|
+
return self._handle_screenshot_request(request)
|
|
307
|
+
|
|
308
|
+
# File/URL opening
|
|
309
|
+
elif "open" in request_lower and (
|
|
310
|
+
"file" in request_lower or "url" in request_lower or "http" in request_lower
|
|
311
|
+
):
|
|
312
|
+
return self._handle_open_request(request)
|
|
313
|
+
|
|
314
|
+
# Command execution
|
|
315
|
+
elif any(word in request_lower for word in ["run", "execute", "command", "terminal"]):
|
|
316
|
+
return self._handle_command_request(request)
|
|
317
|
+
|
|
318
|
+
else:
|
|
319
|
+
return {
|
|
320
|
+
"success": False,
|
|
321
|
+
"error": "Could not understand system request",
|
|
322
|
+
"available_functions": list(self.system_functions.keys()),
|
|
323
|
+
"suggestion": "Try: 'Open TextEdit and write Hello World' or 'Take a screenshot'",
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
def _handle_textedit_request(self, request: str) -> Dict[str, Any]:
|
|
327
|
+
"""Handle TextEdit-specific requests"""
|
|
328
|
+
try:
|
|
329
|
+
# Extract text to write
|
|
330
|
+
text = "Hello, World!" # default
|
|
331
|
+
filename = None
|
|
332
|
+
|
|
333
|
+
# Simple text extraction patterns
|
|
334
|
+
if '"' in request:
|
|
335
|
+
# Extract text in quotes
|
|
336
|
+
parts = request.split('"')
|
|
337
|
+
if len(parts) >= 2:
|
|
338
|
+
text = parts[1]
|
|
339
|
+
elif "write " in request.lower():
|
|
340
|
+
# Extract text after "write"
|
|
341
|
+
parts = request.lower().split("write ")
|
|
342
|
+
if len(parts) > 1:
|
|
343
|
+
text_part = parts[1]
|
|
344
|
+
# Remove common words
|
|
345
|
+
for word in ["in textedit", "to textedit", "and save", "then save"]:
|
|
346
|
+
text_part = text_part.replace(word, "")
|
|
347
|
+
text = text_part.strip()
|
|
348
|
+
|
|
349
|
+
# Extract filename if mentioned
|
|
350
|
+
if "save as" in request.lower():
|
|
351
|
+
parts = request.lower().split("save as")
|
|
352
|
+
if len(parts) > 1:
|
|
353
|
+
filename_part = parts[1].strip()
|
|
354
|
+
# Extract filename (remove quotes and common words)
|
|
355
|
+
filename = filename_part.replace('"', "").replace("'", "").split()[0]
|
|
356
|
+
if not filename.endswith(".txt"):
|
|
357
|
+
filename += ".txt"
|
|
358
|
+
|
|
359
|
+
result = open_textedit_and_write(text, filename)
|
|
360
|
+
|
|
361
|
+
if result["success"]:
|
|
362
|
+
message = f"โ
Opened TextEdit and wrote: '{text}'"
|
|
363
|
+
if filename:
|
|
364
|
+
message += f" (saved as {filename})"
|
|
365
|
+
result["message"] = message
|
|
366
|
+
|
|
367
|
+
return result
|
|
368
|
+
|
|
369
|
+
except Exception as e:
|
|
370
|
+
return {
|
|
371
|
+
"success": False,
|
|
372
|
+
"error": f"Error handling TextEdit request: {e}",
|
|
373
|
+
"request": request,
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
def _handle_app_control_request(self, request: str) -> Dict[str, Any]:
|
|
377
|
+
"""Handle application control requests"""
|
|
378
|
+
try:
|
|
379
|
+
request_lower = request.lower()
|
|
380
|
+
|
|
381
|
+
# Determine action
|
|
382
|
+
if "open" in request_lower or "launch" in request_lower:
|
|
383
|
+
action = "open"
|
|
384
|
+
elif "close" in request_lower or "quit" in request_lower:
|
|
385
|
+
action = "close"
|
|
386
|
+
elif "new document" in request_lower:
|
|
387
|
+
action = "new_document"
|
|
388
|
+
else:
|
|
389
|
+
action = "open" # default
|
|
390
|
+
|
|
391
|
+
# Extract app name
|
|
392
|
+
app_name = "TextEdit" # default
|
|
393
|
+
|
|
394
|
+
common_apps = {
|
|
395
|
+
"textedit": "TextEdit",
|
|
396
|
+
"calculator": "Calculator",
|
|
397
|
+
"finder": "Finder",
|
|
398
|
+
"safari": "Safari",
|
|
399
|
+
"chrome": "Google Chrome",
|
|
400
|
+
"firefox": "Firefox",
|
|
401
|
+
"terminal": "Terminal",
|
|
402
|
+
"preview": "Preview",
|
|
403
|
+
"notes": "Notes",
|
|
404
|
+
"mail": "Mail",
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
for app_key, app_value in common_apps.items():
|
|
408
|
+
if app_key in request_lower:
|
|
409
|
+
app_name = app_value
|
|
410
|
+
break
|
|
411
|
+
|
|
412
|
+
result = control_app(app_name, action)
|
|
413
|
+
|
|
414
|
+
if result["success"]:
|
|
415
|
+
result["message"] = f"โ
{action.title()} {app_name}"
|
|
416
|
+
|
|
417
|
+
return result
|
|
418
|
+
|
|
419
|
+
except Exception as e:
|
|
420
|
+
return {
|
|
421
|
+
"success": False,
|
|
422
|
+
"error": f"Error handling app control request: {e}",
|
|
423
|
+
"request": request,
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
def _handle_screenshot_request(self, request: str) -> Dict[str, Any]:
|
|
427
|
+
"""Handle screenshot requests"""
|
|
428
|
+
try:
|
|
429
|
+
filename = None
|
|
430
|
+
|
|
431
|
+
# Extract filename if specified
|
|
432
|
+
if "save as" in request.lower() or "name" in request.lower():
|
|
433
|
+
# Simple filename extraction
|
|
434
|
+
words = request.split()
|
|
435
|
+
for i, word in enumerate(words):
|
|
436
|
+
if word.lower() in ["as", "name"] and i < len(words) - 1:
|
|
437
|
+
filename = words[i + 1].replace('"', "").replace("'", "")
|
|
438
|
+
if not filename.endswith(".png"):
|
|
439
|
+
filename += ".png"
|
|
440
|
+
break
|
|
441
|
+
|
|
442
|
+
result = take_screenshot(filename)
|
|
443
|
+
|
|
444
|
+
if result["success"]:
|
|
445
|
+
path = result.get("screenshot_path", "Desktop")
|
|
446
|
+
result["message"] = f"โ
Screenshot saved to: {path}"
|
|
447
|
+
|
|
448
|
+
return result
|
|
449
|
+
|
|
450
|
+
except Exception as e:
|
|
451
|
+
return {"success": False, "error": f"Error taking screenshot: {e}", "request": request}
|
|
452
|
+
|
|
453
|
+
def _handle_open_request(self, request: str) -> Dict[str, Any]:
|
|
454
|
+
"""Handle file/URL opening requests"""
|
|
455
|
+
try:
|
|
456
|
+
# Extract URL or file path
|
|
457
|
+
words = request.split()
|
|
458
|
+
path_or_url = None
|
|
459
|
+
|
|
460
|
+
for word in words:
|
|
461
|
+
if word.startswith("http") or word.startswith("www.") or "/" in word:
|
|
462
|
+
path_or_url = word
|
|
463
|
+
break
|
|
464
|
+
|
|
465
|
+
if not path_or_url:
|
|
466
|
+
# Look for common patterns
|
|
467
|
+
if "google" in request.lower():
|
|
468
|
+
path_or_url = "https://google.com"
|
|
469
|
+
elif "current directory" in request.lower() or "this folder" in request.lower():
|
|
470
|
+
path_or_url = "."
|
|
471
|
+
else:
|
|
472
|
+
return {
|
|
473
|
+
"success": False,
|
|
474
|
+
"error": "Could not determine what to open",
|
|
475
|
+
"suggestion": "Specify a URL (like https://google.com) or file path",
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
result = open_file_or_url(path_or_url)
|
|
479
|
+
|
|
480
|
+
if result["success"]:
|
|
481
|
+
result["message"] = f"โ
Opened: {path_or_url}"
|
|
482
|
+
|
|
483
|
+
return result
|
|
484
|
+
|
|
485
|
+
except Exception as e:
|
|
486
|
+
return {"success": False, "error": f"Error opening file/URL: {e}", "request": request}
|
|
487
|
+
|
|
488
|
+
def _handle_command_request(self, request: str) -> Dict[str, Any]:
|
|
489
|
+
"""Handle command execution requests"""
|
|
490
|
+
try:
|
|
491
|
+
# Extract command (this is simplified - in practice you'd want more security)
|
|
492
|
+
command = None
|
|
493
|
+
|
|
494
|
+
if "run " in request.lower():
|
|
495
|
+
parts = request.lower().split("run ")
|
|
496
|
+
if len(parts) > 1:
|
|
497
|
+
command = parts[1].strip()
|
|
498
|
+
elif "execute " in request.lower():
|
|
499
|
+
parts = request.lower().split("execute ")
|
|
500
|
+
if len(parts) > 1:
|
|
501
|
+
command = parts[1].strip()
|
|
502
|
+
|
|
503
|
+
if not command:
|
|
504
|
+
return {
|
|
505
|
+
"success": False,
|
|
506
|
+
"error": "Could not extract command to execute",
|
|
507
|
+
"suggestion": "Try: 'Run ls' or 'Execute date'",
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# Basic security check (you'd want more comprehensive checks)
|
|
511
|
+
dangerous_commands = ["rm -rf", "sudo", "format", "del /", "> /dev"]
|
|
512
|
+
if any(dangerous in command.lower() for dangerous in dangerous_commands):
|
|
513
|
+
return {
|
|
514
|
+
"success": False,
|
|
515
|
+
"error": "Command blocked for security reasons",
|
|
516
|
+
"command": command,
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
result = execute_system_command(command, f"User requested: {command}")
|
|
520
|
+
|
|
521
|
+
if result["success"]:
|
|
522
|
+
result["message"] = f"โ
Executed: {command}"
|
|
523
|
+
|
|
524
|
+
return result
|
|
525
|
+
|
|
526
|
+
except Exception as e:
|
|
527
|
+
return {"success": False, "error": f"Error executing command: {e}", "request": request}
|
|
528
|
+
|
|
529
|
+
def _handle_system_time_request(self, request: str) -> Dict[str, Any]:
|
|
530
|
+
"""Handle system time requests"""
|
|
531
|
+
try:
|
|
532
|
+
result = self.system_controller.get_system_time()
|
|
533
|
+
|
|
534
|
+
if result["success"]:
|
|
535
|
+
time_data = result["data"]
|
|
536
|
+
result["message"] = (
|
|
537
|
+
f"โฐ Current time: {time_data['current_time']} ({time_data['timezone'][0]})"
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
return result
|
|
541
|
+
|
|
542
|
+
except Exception as e:
|
|
543
|
+
return {
|
|
544
|
+
"success": False,
|
|
545
|
+
"error": f"Error getting system time: {e}",
|
|
546
|
+
"request": request,
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
def _handle_system_info_request(self, request: str) -> Dict[str, Any]:
|
|
550
|
+
"""Handle system information requests"""
|
|
551
|
+
try:
|
|
552
|
+
result = self.system_controller.get_system_info()
|
|
553
|
+
|
|
554
|
+
if result["success"]:
|
|
555
|
+
info_data = result["data"]
|
|
556
|
+
summary = [
|
|
557
|
+
f"๐ป System: {info_data['system']} {info_data['machine']}",
|
|
558
|
+
f"๐ง CPU: {info_data['cpu']['logical_cores']} cores, {info_data['cpu']['cpu_usage_percent']}% usage",
|
|
559
|
+
f"๐พ RAM: {info_data['memory']['used_gb']:.1f}GB used / {info_data['memory']['total_gb']:.1f}GB total ({info_data['memory']['usage_percent']}%)",
|
|
560
|
+
f"โฐ Uptime: {info_data['uptime_hours']:.1f} hours",
|
|
561
|
+
]
|
|
562
|
+
result["message"] = "\n".join(summary)
|
|
563
|
+
|
|
564
|
+
return result
|
|
565
|
+
|
|
566
|
+
except Exception as e:
|
|
567
|
+
return {
|
|
568
|
+
"success": False,
|
|
569
|
+
"error": f"Error getting system information: {e}",
|
|
570
|
+
"request": request,
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
def _handle_hardware_devices_request(self, request: str) -> Dict[str, Any]:
|
|
574
|
+
"""Handle hardware devices listing requests"""
|
|
575
|
+
try:
|
|
576
|
+
# Use shell command to get hardware information
|
|
577
|
+
import subprocess
|
|
578
|
+
|
|
579
|
+
summary = ["๐ Connected Hardware Devices:"]
|
|
580
|
+
|
|
581
|
+
try:
|
|
582
|
+
# Get USB devices
|
|
583
|
+
result = subprocess.run(
|
|
584
|
+
["system_profiler", "SPUSBDataType"], capture_output=True, text=True, timeout=10
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
if result.returncode == 0:
|
|
588
|
+
usb_lines = result.stdout.split("\n")
|
|
589
|
+
usb_devices = []
|
|
590
|
+
for line in usb_lines:
|
|
591
|
+
line = line.strip()
|
|
592
|
+
if ":" in line and not line.startswith("USB") and len(line) < 100:
|
|
593
|
+
if any(
|
|
594
|
+
keyword in line.lower()
|
|
595
|
+
for keyword in [
|
|
596
|
+
"mouse",
|
|
597
|
+
"keyboard",
|
|
598
|
+
"disk",
|
|
599
|
+
"camera",
|
|
600
|
+
"audio",
|
|
601
|
+
"hub",
|
|
602
|
+
]
|
|
603
|
+
):
|
|
604
|
+
device_name = line.split(":")[0].strip()
|
|
605
|
+
if device_name and len(device_name) > 3:
|
|
606
|
+
usb_devices.append(device_name)
|
|
607
|
+
|
|
608
|
+
if usb_devices:
|
|
609
|
+
summary.append("๐พ USB Devices:")
|
|
610
|
+
for device in usb_devices[:8]: # Limit to 8 devices
|
|
611
|
+
summary.append(f" โข {device}")
|
|
612
|
+
|
|
613
|
+
except Exception:
|
|
614
|
+
pass
|
|
615
|
+
|
|
616
|
+
try:
|
|
617
|
+
# Get network interfaces
|
|
618
|
+
result = subprocess.run(
|
|
619
|
+
["ifconfig", "-a"], capture_output=True, text=True, timeout=5
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
if result.returncode == 0:
|
|
623
|
+
interfaces = []
|
|
624
|
+
for line in result.stdout.split("\n"):
|
|
625
|
+
if line and not line.startswith("\t") and not line.startswith(" "):
|
|
626
|
+
interface_name = line.split(":")[0].strip()
|
|
627
|
+
if interface_name and interface_name not in ["lo0", "gif0", "stf0"]:
|
|
628
|
+
interfaces.append(interface_name)
|
|
629
|
+
|
|
630
|
+
if interfaces:
|
|
631
|
+
summary.append("๐ Network Interfaces:")
|
|
632
|
+
for interface in interfaces[:6]: # Limit to 6 interfaces
|
|
633
|
+
summary.append(f" โข {interface}")
|
|
634
|
+
|
|
635
|
+
except Exception:
|
|
636
|
+
pass
|
|
637
|
+
|
|
638
|
+
try:
|
|
639
|
+
# Get audio devices
|
|
640
|
+
result = subprocess.run(
|
|
641
|
+
["system_profiler", "SPAudioDataType"],
|
|
642
|
+
capture_output=True,
|
|
643
|
+
text=True,
|
|
644
|
+
timeout=5,
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
if result.returncode == 0:
|
|
648
|
+
audio_devices = []
|
|
649
|
+
for line in result.stdout.split("\n"):
|
|
650
|
+
line = line.strip()
|
|
651
|
+
if ":" in line and (
|
|
652
|
+
"Built-in" in line or "USB" in line or "Bluetooth" in line
|
|
653
|
+
):
|
|
654
|
+
device_name = line.split(":")[0].strip()
|
|
655
|
+
if device_name and len(device_name) > 3:
|
|
656
|
+
audio_devices.append(device_name)
|
|
657
|
+
|
|
658
|
+
if audio_devices:
|
|
659
|
+
summary.append("๐ Audio Devices:")
|
|
660
|
+
for device in audio_devices[:4]: # Limit to 4 devices
|
|
661
|
+
summary.append(f" โข {device}")
|
|
662
|
+
|
|
663
|
+
except Exception:
|
|
664
|
+
pass
|
|
665
|
+
|
|
666
|
+
if len(summary) == 1: # Only has header
|
|
667
|
+
summary.append("โน๏ธ No specific hardware devices detected via system profiler")
|
|
668
|
+
summary.append("๐ก Try: 'system info' for general hardware information")
|
|
669
|
+
|
|
670
|
+
return {
|
|
671
|
+
"success": True,
|
|
672
|
+
"message": "\n".join(summary),
|
|
673
|
+
"description": "List connected hardware devices",
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
except Exception as e:
|
|
677
|
+
return {
|
|
678
|
+
"success": False,
|
|
679
|
+
"error": f"Error getting hardware devices: {e}",
|
|
680
|
+
"suggestion": "Try 'system info' for general hardware information",
|
|
681
|
+
"request": request,
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
def _handle_memory_request(self, request: str) -> Dict[str, Any]:
|
|
685
|
+
"""Handle memory usage requests"""
|
|
686
|
+
try:
|
|
687
|
+
result = self.system_controller.get_memory_usage()
|
|
688
|
+
|
|
689
|
+
if result["success"]:
|
|
690
|
+
memory_data = result["data"]
|
|
691
|
+
vm = memory_data["virtual_memory"]
|
|
692
|
+
swap = memory_data["swap_memory"]
|
|
693
|
+
|
|
694
|
+
summary = [
|
|
695
|
+
f"๐พ Memory Usage:",
|
|
696
|
+
f" RAM: {vm['used_gb']:.1f}GB used / {vm['total_gb']:.1f}GB total ({vm['usage_percent']}%)",
|
|
697
|
+
f" Available: {vm['available_gb']:.1f}GB",
|
|
698
|
+
f" Swap: {swap['used_gb']:.1f}GB used / {swap['total_gb']:.1f}GB total ({swap['usage_percent']}%)",
|
|
699
|
+
]
|
|
700
|
+
|
|
701
|
+
# Add recommendations if any
|
|
702
|
+
if memory_data["recommendations"]:
|
|
703
|
+
summary.append("๐ Recommendations:")
|
|
704
|
+
for rec in memory_data["recommendations"]:
|
|
705
|
+
summary.append(f" โข {rec}")
|
|
706
|
+
|
|
707
|
+
result["message"] = "\n".join(summary)
|
|
708
|
+
|
|
709
|
+
return result
|
|
710
|
+
|
|
711
|
+
except Exception as e:
|
|
712
|
+
return {
|
|
713
|
+
"success": False,
|
|
714
|
+
"error": f"Error getting memory usage: {e}",
|
|
715
|
+
"request": request,
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
def _handle_disk_request(self, request: str) -> Dict[str, Any]:
|
|
719
|
+
"""Handle disk usage requests"""
|
|
720
|
+
try:
|
|
721
|
+
result = self.system_controller.get_disk_usage()
|
|
722
|
+
|
|
723
|
+
if result["success"]:
|
|
724
|
+
disk_data = result["data"]
|
|
725
|
+
|
|
726
|
+
summary = [f"๐ฝ Disk Usage:"]
|
|
727
|
+
|
|
728
|
+
# Show main disk first
|
|
729
|
+
if disk_data["total_disk_gb"] > 0:
|
|
730
|
+
usage_pct = (disk_data["total_used_gb"] / disk_data["total_disk_gb"]) * 100
|
|
731
|
+
summary.append(
|
|
732
|
+
f" Main: {disk_data['total_used_gb']:.1f}GB used / {disk_data['total_disk_gb']:.1f}GB total ({usage_pct:.1f}%)"
|
|
733
|
+
)
|
|
734
|
+
summary.append(f" Free: {disk_data['total_free_gb']:.1f}GB available")
|
|
735
|
+
|
|
736
|
+
# Show other partitions
|
|
737
|
+
if len(disk_data["partitions"]) > 1:
|
|
738
|
+
summary.append(" Other partitions:")
|
|
739
|
+
for partition in disk_data["partitions"]:
|
|
740
|
+
if partition["mountpoint"] not in ["/", "C:\\"]:
|
|
741
|
+
summary.append(
|
|
742
|
+
f" {partition['mountpoint']}: {partition['used_gb']:.1f}GB / {partition['total_gb']:.1f}GB ({partition['usage_percent']}%)"
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
# Add recommendations if any
|
|
746
|
+
if disk_data["recommendations"]:
|
|
747
|
+
summary.append("๐ Recommendations:")
|
|
748
|
+
for rec in disk_data["recommendations"]:
|
|
749
|
+
summary.append(f" โข {rec}")
|
|
750
|
+
|
|
751
|
+
result["message"] = "\n".join(summary)
|
|
752
|
+
|
|
753
|
+
return result
|
|
754
|
+
|
|
755
|
+
except Exception as e:
|
|
756
|
+
return {"success": False, "error": f"Error getting disk usage: {e}", "request": request}
|
|
757
|
+
|
|
758
|
+
def _handle_cache_clear_request(self, request: str) -> Dict[str, Any]:
|
|
759
|
+
"""Handle cache clearing requests"""
|
|
760
|
+
try:
|
|
761
|
+
result = self.system_controller.clear_system_caches()
|
|
762
|
+
|
|
763
|
+
if result["success"]:
|
|
764
|
+
cache_data = result["data"]
|
|
765
|
+
|
|
766
|
+
summary = [f"๐งน Cache Cleanup Results:"]
|
|
767
|
+
|
|
768
|
+
if cache_data["cleared_items"]:
|
|
769
|
+
for item in cache_data["cleared_items"]:
|
|
770
|
+
summary.append(f" โ
{item}")
|
|
771
|
+
else:
|
|
772
|
+
summary.append(" โน๏ธ No cache items found to clear")
|
|
773
|
+
|
|
774
|
+
if cache_data["total_freed_mb"] > 0:
|
|
775
|
+
summary.append(f"๐พ Total space freed: {cache_data['total_freed_mb']:.1f} MB")
|
|
776
|
+
|
|
777
|
+
result["message"] = "\n".join(summary)
|
|
778
|
+
|
|
779
|
+
return result
|
|
780
|
+
|
|
781
|
+
except Exception as e:
|
|
782
|
+
return {"success": False, "error": f"Error clearing caches: {e}", "request": request}
|
|
783
|
+
|
|
784
|
+
def _handle_navigation_request(self, request: str) -> Dict[str, Any]:
|
|
785
|
+
"""Handle directory navigation requests"""
|
|
786
|
+
try:
|
|
787
|
+
# Extract path from request
|
|
788
|
+
request_lower = request.lower()
|
|
789
|
+
path = None
|
|
790
|
+
|
|
791
|
+
# Common patterns to extract path
|
|
792
|
+
if "navigate to " in request_lower:
|
|
793
|
+
path = request[request_lower.find("navigate to ") + 12 :].strip()
|
|
794
|
+
elif "go to " in request_lower:
|
|
795
|
+
path = request[request_lower.find("go to ") + 6 :].strip()
|
|
796
|
+
elif "change to " in request_lower:
|
|
797
|
+
path = request[request_lower.find("change to ") + 10 :].strip()
|
|
798
|
+
elif "cd to " in request_lower:
|
|
799
|
+
path = request[request_lower.find("cd to ") + 6 :].strip()
|
|
800
|
+
elif "move to " in request_lower:
|
|
801
|
+
path = request[request_lower.find("move to ") + 8 :].strip()
|
|
802
|
+
|
|
803
|
+
if not path:
|
|
804
|
+
return {
|
|
805
|
+
"success": False,
|
|
806
|
+
"error": "Could not extract directory path from request",
|
|
807
|
+
"suggestion": "Try: 'navigate to /path/to/directory' or 'cd to ~/Documents'",
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
# Clean up path (remove quotes, extra text)
|
|
811
|
+
path = path.replace('"', "").replace("'", "")
|
|
812
|
+
if ":" in path and not path.startswith("/"):
|
|
813
|
+
# Handle "navigate to /path:" format
|
|
814
|
+
path = path.split(":")[0]
|
|
815
|
+
|
|
816
|
+
result = change_directory(path)
|
|
817
|
+
|
|
818
|
+
if result["success"]:
|
|
819
|
+
# Also list the directory contents after navigation
|
|
820
|
+
list_result = list_directory()
|
|
821
|
+
if list_result["success"]:
|
|
822
|
+
entries = list_result["entries"]
|
|
823
|
+
entry_summary = []
|
|
824
|
+
dirs = [e for e in entries if e["type"] == "directory"]
|
|
825
|
+
files = [e for e in entries if e["type"] == "file"]
|
|
826
|
+
|
|
827
|
+
if dirs:
|
|
828
|
+
entry_summary.append(f"{len(dirs)} directories")
|
|
829
|
+
if files:
|
|
830
|
+
entry_summary.append(f"{len(files)} files")
|
|
831
|
+
|
|
832
|
+
result["message"] = (
|
|
833
|
+
f"โ
{result['message']}\n๐ Contains: {', '.join(entry_summary)}"
|
|
834
|
+
)
|
|
835
|
+
result["directory_contents"] = entries[:10] # Show first 10 items
|
|
836
|
+
|
|
837
|
+
return result
|
|
838
|
+
|
|
839
|
+
except Exception as e:
|
|
840
|
+
return {"success": False, "error": f"Navigation error: {e}", "request": request}
|
|
841
|
+
|
|
842
|
+
def _handle_directory_listing_request(self, request: str) -> Dict[str, Any]:
|
|
843
|
+
"""Handle directory listing requests"""
|
|
844
|
+
try:
|
|
845
|
+
request_lower = request.lower()
|
|
846
|
+
|
|
847
|
+
# Extract path if specified
|
|
848
|
+
path = None
|
|
849
|
+
show_hidden = False
|
|
850
|
+
detailed = False
|
|
851
|
+
|
|
852
|
+
if "list " in request_lower:
|
|
853
|
+
after_list = request[request_lower.find("list ") + 5 :].strip()
|
|
854
|
+
if after_list and not after_list.startswith(("current", "this", "files")):
|
|
855
|
+
path = after_list
|
|
856
|
+
elif "show files in " in request_lower:
|
|
857
|
+
path = request[request_lower.find("show files in ") + 14 :].strip()
|
|
858
|
+
elif "what's in " in request_lower:
|
|
859
|
+
path = request[request_lower.find("what's in ") + 10 :].strip()
|
|
860
|
+
|
|
861
|
+
if "hidden" in request_lower or "all files" in request_lower:
|
|
862
|
+
show_hidden = True
|
|
863
|
+
if "detailed" in request_lower or "details" in request_lower:
|
|
864
|
+
detailed = True
|
|
865
|
+
|
|
866
|
+
# Clean up path
|
|
867
|
+
if path:
|
|
868
|
+
path = path.replace('"', "").replace("'", "")
|
|
869
|
+
if path.endswith(":"):
|
|
870
|
+
path = path[:-1]
|
|
871
|
+
|
|
872
|
+
result = list_directory(path, show_hidden, detailed)
|
|
873
|
+
|
|
874
|
+
if result["success"]:
|
|
875
|
+
entries = result["entries"]
|
|
876
|
+
dirs = [e for e in entries if e["type"] == "directory"]
|
|
877
|
+
files = [e for e in entries if e["type"] == "file"]
|
|
878
|
+
|
|
879
|
+
summary = []
|
|
880
|
+
if dirs:
|
|
881
|
+
summary.append(f"๐ {len(dirs)} directories")
|
|
882
|
+
if files:
|
|
883
|
+
summary.append(f"๐ {len(files)} files")
|
|
884
|
+
|
|
885
|
+
result["message"] = f"๐ {result['path']}\n{', '.join(summary)}"
|
|
886
|
+
|
|
887
|
+
# Format entries for display
|
|
888
|
+
display_entries = []
|
|
889
|
+
for entry in entries[:20]: # Show first 20
|
|
890
|
+
if entry["type"] == "directory":
|
|
891
|
+
display_entries.append(f"๐ {entry['name']}/")
|
|
892
|
+
else:
|
|
893
|
+
size_str = ""
|
|
894
|
+
if entry.get("size") is not None:
|
|
895
|
+
size_kb = entry["size"] / 1024
|
|
896
|
+
if size_kb < 1024:
|
|
897
|
+
size_str = f" ({size_kb:.1f} KB)"
|
|
898
|
+
else:
|
|
899
|
+
size_str = f" ({size_kb/1024:.1f} MB)"
|
|
900
|
+
display_entries.append(f"๐ {entry['name']}{size_str}")
|
|
901
|
+
|
|
902
|
+
if display_entries:
|
|
903
|
+
result["display_entries"] = display_entries
|
|
904
|
+
if len(entries) > 20:
|
|
905
|
+
result["message"] += f"\n(showing first 20 of {len(entries)} items)"
|
|
906
|
+
|
|
907
|
+
return result
|
|
908
|
+
|
|
909
|
+
except Exception as e:
|
|
910
|
+
return {"success": False, "error": f"Directory listing error: {e}", "request": request}
|
|
911
|
+
|
|
912
|
+
def _handle_simulator_cleanup_request(self, request: str) -> Dict[str, Any]:
|
|
913
|
+
"""Handle iOS/watchOS simulator cleanup requests"""
|
|
914
|
+
try:
|
|
915
|
+
result = clean_simulator_data()
|
|
916
|
+
|
|
917
|
+
if result["success"]:
|
|
918
|
+
data = result["data"]
|
|
919
|
+
result["message"] = (
|
|
920
|
+
f"๐งน Simulator cleanup completed!\n๐พ Freed {data['total_freed_mb']} MB of storage"
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
if data["cleaned_items"]:
|
|
924
|
+
result["cleaned_summary"] = data["cleaned_items"][:5] # Show first 5 items
|
|
925
|
+
|
|
926
|
+
return result
|
|
927
|
+
|
|
928
|
+
except Exception as e:
|
|
929
|
+
return {"success": False, "error": f"Simulator cleanup error: {e}", "request": request}
|
|
930
|
+
|
|
931
|
+
def _handle_shell_command_request(self, request: str) -> Dict[str, Any]:
|
|
932
|
+
"""Handle shell command execution requests"""
|
|
933
|
+
try:
|
|
934
|
+
request_lower = request.lower()
|
|
935
|
+
|
|
936
|
+
# Extract command
|
|
937
|
+
command = None
|
|
938
|
+
if "run command " in request_lower:
|
|
939
|
+
command = request[request_lower.find("run command ") + 12 :].strip()
|
|
940
|
+
elif "execute " in request_lower:
|
|
941
|
+
command = request[request_lower.find("execute ") + 8 :].strip()
|
|
942
|
+
elif "shell " in request_lower:
|
|
943
|
+
command = request[request_lower.find("shell ") + 6 :].strip()
|
|
944
|
+
elif "terminal " in request_lower:
|
|
945
|
+
command = request[request_lower.find("terminal ") + 9 :].strip()
|
|
946
|
+
|
|
947
|
+
if not command:
|
|
948
|
+
return {
|
|
949
|
+
"success": False,
|
|
950
|
+
"error": "Could not extract command from request",
|
|
951
|
+
"suggestion": "Try: 'run command ls -la' or 'execute find /path -name pattern'",
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
# Basic security check
|
|
955
|
+
dangerous_commands = ["rm -rf /", "sudo rm", "format", "mkfs", "> /dev/null"]
|
|
956
|
+
if any(dangerous in command.lower() for dangerous in dangerous_commands):
|
|
957
|
+
return {
|
|
958
|
+
"success": False,
|
|
959
|
+
"error": "Command blocked for security reasons",
|
|
960
|
+
"command": command,
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
result = execute_shell_command(command)
|
|
964
|
+
|
|
965
|
+
if result["success"]:
|
|
966
|
+
result["message"] = f"โ
Executed: {command}"
|
|
967
|
+
if result.get("output"):
|
|
968
|
+
# Truncate long output
|
|
969
|
+
output = result["output"]
|
|
970
|
+
if len(output) > 2000:
|
|
971
|
+
result["output"] = output[:2000] + "\n... (output truncated)"
|
|
972
|
+
|
|
973
|
+
return result
|
|
974
|
+
|
|
975
|
+
except Exception as e:
|
|
976
|
+
return {"success": False, "error": f"Shell command error: {e}", "request": request}
|
|
977
|
+
|
|
978
|
+
def _handle_current_directory_request(self, request: str) -> Dict[str, Any]:
|
|
979
|
+
"""Handle current directory requests"""
|
|
980
|
+
try:
|
|
981
|
+
current_dir = get_current_directory()
|
|
982
|
+
|
|
983
|
+
return {
|
|
984
|
+
"success": True,
|
|
985
|
+
"current_directory": current_dir,
|
|
986
|
+
"message": f"๐ Current directory: {current_dir}",
|
|
987
|
+
"description": "Get current directory",
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
except Exception as e:
|
|
991
|
+
return {"success": False, "error": f"Current directory error: {e}", "request": request}
|
|
992
|
+
|
|
993
|
+
def get_capabilities(self) -> Dict[str, Any]:
|
|
994
|
+
"""Get information about available system capabilities"""
|
|
995
|
+
return {
|
|
996
|
+
"enabled": self.enabled,
|
|
997
|
+
"system": self.system_controller.system,
|
|
998
|
+
"functions": {
|
|
999
|
+
name: {"description": info["description"], "examples": info["examples"]}
|
|
1000
|
+
for name, info in self.system_functions.items()
|
|
1001
|
+
},
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
# Global instance for use in chat
|
|
1006
|
+
chat_system_integration = ChatSystemIntegration()
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
def handle_system_request(request: str) -> Dict[str, Any]:
|
|
1010
|
+
"""Main function for handling system requests from chat"""
|
|
1011
|
+
return chat_system_integration.handle_system_request(request)
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
def get_system_capabilities() -> Dict[str, Any]:
|
|
1015
|
+
"""Get available system capabilities"""
|
|
1016
|
+
return chat_system_integration.get_capabilities()
|