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,530 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
import uuid
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
# Import the daemon classes
|
|
14
|
+
from .commands import Command, CommandDatabase, CommandExecutor
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group()
|
|
18
|
+
def client():
|
|
19
|
+
"""Client CLI for daemon commands."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DaemonClient:
|
|
24
|
+
"""Client interface for interacting with the daemon service"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, timeout: int = 30):
|
|
27
|
+
self.db = CommandDatabase()
|
|
28
|
+
self.executor = CommandExecutor()
|
|
29
|
+
self.timeout = timeout # Default timeout for operations
|
|
30
|
+
self._validate_connection()
|
|
31
|
+
|
|
32
|
+
def _validate_connection(self):
|
|
33
|
+
"""Verify connection to the daemon service"""
|
|
34
|
+
try:
|
|
35
|
+
self.db.get_all_commands() # Simple query to test connection
|
|
36
|
+
except Exception as e:
|
|
37
|
+
raise ConnectionError(f"Failed to connect to daemon: {str(e)}") from e
|
|
38
|
+
|
|
39
|
+
def add_command_from_file(
|
|
40
|
+
self,
|
|
41
|
+
name: str,
|
|
42
|
+
file_path: str,
|
|
43
|
+
description: Optional[str] = None,
|
|
44
|
+
language: str = "python",
|
|
45
|
+
group: Optional[str] = None,
|
|
46
|
+
tags: Optional[List[str]] = None,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""Add a command from a file"""
|
|
49
|
+
# Read the file
|
|
50
|
+
with open(file_path, "r") as f:
|
|
51
|
+
code = f.read()
|
|
52
|
+
|
|
53
|
+
# Detect language from file extension if not specified
|
|
54
|
+
if language == "auto":
|
|
55
|
+
ext = Path(file_path).suffix.lower()
|
|
56
|
+
language_map = {
|
|
57
|
+
".py": "python",
|
|
58
|
+
".js": "node",
|
|
59
|
+
".lua": "lua",
|
|
60
|
+
".sh": "shell",
|
|
61
|
+
".bash": "shell",
|
|
62
|
+
}
|
|
63
|
+
language = language_map.get(ext, "python")
|
|
64
|
+
|
|
65
|
+
# Create command
|
|
66
|
+
command = Command(
|
|
67
|
+
id=str(uuid.uuid4()),
|
|
68
|
+
name=name,
|
|
69
|
+
description=description or f"Command from {file_path}",
|
|
70
|
+
code=code,
|
|
71
|
+
language=language,
|
|
72
|
+
group=group,
|
|
73
|
+
tags=tags or [],
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Add to database
|
|
77
|
+
return self.db.add_command(command)
|
|
78
|
+
|
|
79
|
+
def add_command_from_stdin(
|
|
80
|
+
self,
|
|
81
|
+
name: str,
|
|
82
|
+
description: Optional[str] = None,
|
|
83
|
+
language: str = "python",
|
|
84
|
+
group: Optional[str] = None,
|
|
85
|
+
tags: Optional[List[str]] = None,
|
|
86
|
+
) -> str:
|
|
87
|
+
"""Add a command from stdin"""
|
|
88
|
+
click.echo("Enter your code (Ctrl+D when done):")
|
|
89
|
+
|
|
90
|
+
# Read from stdin
|
|
91
|
+
lines = []
|
|
92
|
+
try:
|
|
93
|
+
while True:
|
|
94
|
+
line = input()
|
|
95
|
+
lines.append(line)
|
|
96
|
+
except EOFError:
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
code = "\n".join(lines)
|
|
100
|
+
|
|
101
|
+
if not code.strip():
|
|
102
|
+
raise ValueError("No code provided")
|
|
103
|
+
|
|
104
|
+
# Create command
|
|
105
|
+
command = Command(
|
|
106
|
+
id=str(uuid.uuid4()),
|
|
107
|
+
name=name,
|
|
108
|
+
description=description or f"Command from stdin",
|
|
109
|
+
code=code,
|
|
110
|
+
language=language,
|
|
111
|
+
group=group,
|
|
112
|
+
tags=tags or [],
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Add to database
|
|
116
|
+
return self.db.add_command(command)
|
|
117
|
+
|
|
118
|
+
def add_command_interactive(self) -> Optional[str]:
|
|
119
|
+
"""Interactive command creation"""
|
|
120
|
+
# Get command name
|
|
121
|
+
name = click.prompt("Command name", type=str)
|
|
122
|
+
|
|
123
|
+
# Check if name already exists
|
|
124
|
+
existing = self.db.search_commands(name, limit=1)
|
|
125
|
+
if existing and existing[0].name == name:
|
|
126
|
+
if not click.confirm(f"Command '{name}' already exists. Overwrite?"):
|
|
127
|
+
return None
|
|
128
|
+
|
|
129
|
+
# Get description
|
|
130
|
+
description = click.prompt("Description (optional)", type=str, default="")
|
|
131
|
+
|
|
132
|
+
# Get language
|
|
133
|
+
language = click.prompt(
|
|
134
|
+
"Language", type=click.Choice(["python", "node", "lua", "shell"]), default="python"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Get group
|
|
138
|
+
group = click.prompt("Group (optional)", type=str, default="")
|
|
139
|
+
if not group:
|
|
140
|
+
group = None
|
|
141
|
+
|
|
142
|
+
# Get tags
|
|
143
|
+
tags_input = click.prompt("Tags (comma-separated, optional)", type=str, default="")
|
|
144
|
+
tags = [tag.strip() for tag in tags_input.split(",")] if tags_input else []
|
|
145
|
+
|
|
146
|
+
# Get code source
|
|
147
|
+
source = click.prompt(
|
|
148
|
+
"Code source", type=click.Choice(["file", "stdin", "paste"]), default="paste"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if source == "file":
|
|
152
|
+
file_path = click.prompt("File path", type=click.Path(exists=True))
|
|
153
|
+
return self.add_command_from_file(name, file_path, description, language, group, tags)
|
|
154
|
+
elif source == "stdin":
|
|
155
|
+
return self.add_command_from_stdin(name, description, language, group, tags)
|
|
156
|
+
else: # paste
|
|
157
|
+
click.echo("Paste your code below (Ctrl+D when done):")
|
|
158
|
+
lines = []
|
|
159
|
+
try:
|
|
160
|
+
while True:
|
|
161
|
+
line = input()
|
|
162
|
+
lines.append(line)
|
|
163
|
+
except EOFError:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
code = "\n".join(lines)
|
|
167
|
+
|
|
168
|
+
if not code.strip():
|
|
169
|
+
raise ValueError("No code provided")
|
|
170
|
+
|
|
171
|
+
# Create command
|
|
172
|
+
command = Command(
|
|
173
|
+
id=str(uuid.uuid4()),
|
|
174
|
+
name=name,
|
|
175
|
+
description=description or f"Command from paste",
|
|
176
|
+
code=code,
|
|
177
|
+
language=language,
|
|
178
|
+
group=group,
|
|
179
|
+
tags=tags,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Add to database
|
|
183
|
+
return self.db.add_command(command)
|
|
184
|
+
|
|
185
|
+
def execute_command(self, command_id: str, args: List[str] = None) -> Dict[str, Any]:
|
|
186
|
+
"""Execute a command"""
|
|
187
|
+
command = self.db.get_command(command_id)
|
|
188
|
+
if not command:
|
|
189
|
+
raise ValueError(f"Command '{command_id}' not found")
|
|
190
|
+
|
|
191
|
+
# Execute
|
|
192
|
+
result = self.executor.execute_command(command, args or [])
|
|
193
|
+
|
|
194
|
+
# Record execution
|
|
195
|
+
self.db.record_execution(
|
|
196
|
+
command_id=command_id,
|
|
197
|
+
status=result["status"],
|
|
198
|
+
output=result.get("output", ""),
|
|
199
|
+
error=result.get("error", ""),
|
|
200
|
+
execution_time_ms=result.get("execution_time_ms", 0),
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return result
|
|
204
|
+
|
|
205
|
+
def search_commands(self, query: str, limit: int = 10) -> List[Command]:
|
|
206
|
+
"""Search for commands"""
|
|
207
|
+
return self.db.search_commands(query, limit)
|
|
208
|
+
|
|
209
|
+
def find_similar_commands(self, query: str, limit: int = 5) -> List[tuple]:
|
|
210
|
+
"""Find similar commands using cosine similarity"""
|
|
211
|
+
return self.db.find_similar_commands(query, limit)
|
|
212
|
+
|
|
213
|
+
def get_all_commands(self) -> List[Command]:
|
|
214
|
+
"""Get all commands"""
|
|
215
|
+
return self.db.get_all_commands()
|
|
216
|
+
|
|
217
|
+
def get_command(self, command_id: str) -> Optional[Command]:
|
|
218
|
+
"""Get a command by ID"""
|
|
219
|
+
return self.db.get_command(command_id)
|
|
220
|
+
|
|
221
|
+
def update_command(self, command: Command) -> bool:
|
|
222
|
+
"""Update a command"""
|
|
223
|
+
return self.db.update_command(command)
|
|
224
|
+
|
|
225
|
+
def delete_command(self, command_id: str) -> bool:
|
|
226
|
+
"""Delete a command"""
|
|
227
|
+
return self.db.delete_command(command_id)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# CLI Commands - these will be subcommands under the daemon group
|
|
231
|
+
@client.command()
|
|
232
|
+
@click.argument("name")
|
|
233
|
+
@click.argument("file_path", type=click.Path(exists=True))
|
|
234
|
+
@click.option("--description", help="Command description")
|
|
235
|
+
@click.option(
|
|
236
|
+
"--language",
|
|
237
|
+
type=click.Choice(["python", "node", "lua", "shell", "auto"]),
|
|
238
|
+
default="auto",
|
|
239
|
+
help="Programming language",
|
|
240
|
+
)
|
|
241
|
+
@click.option("--group", help="Command group")
|
|
242
|
+
@click.option("--tags", help="Comma-separated tags")
|
|
243
|
+
def add_file(name: str, file_path: str, description: str, language: str, group: str, tags: str):
|
|
244
|
+
"""Add a command from a file"""
|
|
245
|
+
client = DaemonClient()
|
|
246
|
+
|
|
247
|
+
# Parse tags
|
|
248
|
+
tag_list = [tag.strip() for tag in tags.split(",")] if tags else []
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
command_id = client.add_command_from_file(
|
|
252
|
+
name=name,
|
|
253
|
+
file_path=file_path,
|
|
254
|
+
description=description,
|
|
255
|
+
language=language,
|
|
256
|
+
group=group,
|
|
257
|
+
tags=tag_list,
|
|
258
|
+
)
|
|
259
|
+
click.echo(f"✅ Command '{name}' added with ID: {command_id}")
|
|
260
|
+
except Exception as e:
|
|
261
|
+
click.echo(f"❌ Error adding command: {e}", err=True)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@client.command()
|
|
265
|
+
@click.argument("name")
|
|
266
|
+
@click.option("--description", help="Command description")
|
|
267
|
+
@click.option(
|
|
268
|
+
"--language",
|
|
269
|
+
type=click.Choice(["python", "node", "lua", "shell"]),
|
|
270
|
+
default="python",
|
|
271
|
+
help="Programming language",
|
|
272
|
+
)
|
|
273
|
+
@click.option("--group", help="Command group")
|
|
274
|
+
@click.option("--tags", help="Comma-separated tags")
|
|
275
|
+
def add_stdin(name: str, description: str, language: str, group: str, tags: str):
|
|
276
|
+
"""Add a command from stdin"""
|
|
277
|
+
client = DaemonClient()
|
|
278
|
+
|
|
279
|
+
# Parse tags
|
|
280
|
+
tag_list = [tag.strip() for tag in tags.split(",")] if tags else []
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
command_id = client.add_command_from_stdin(
|
|
284
|
+
name=name, description=description, language=language, group=group, tags=tag_list
|
|
285
|
+
)
|
|
286
|
+
click.echo(f"✅ Command '{name}' added with ID: {command_id}")
|
|
287
|
+
except Exception as e:
|
|
288
|
+
click.echo(f"❌ Error adding command: {e}", err=True)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@client.command()
|
|
292
|
+
def add_interactive():
|
|
293
|
+
"""Add a command interactively"""
|
|
294
|
+
client = DaemonClient()
|
|
295
|
+
|
|
296
|
+
try:
|
|
297
|
+
command_id = client.add_command_interactive()
|
|
298
|
+
if command_id:
|
|
299
|
+
click.echo(f"✅ Command added with ID: {command_id}")
|
|
300
|
+
else:
|
|
301
|
+
click.echo("Command creation cancelled")
|
|
302
|
+
except Exception as e:
|
|
303
|
+
click.echo(f"❌ Error adding command: {e}", err=True)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@client.command()
|
|
307
|
+
@click.argument("command_id")
|
|
308
|
+
@click.argument("args", nargs=-1)
|
|
309
|
+
def execute(command_id: str, args: List[str]):
|
|
310
|
+
"""Execute a command"""
|
|
311
|
+
client = DaemonClient()
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
result = client.execute_command(command_id, list(args))
|
|
315
|
+
|
|
316
|
+
if result["success"]:
|
|
317
|
+
click.echo("✅ Command executed successfully")
|
|
318
|
+
if result["output"]:
|
|
319
|
+
click.echo("Output:")
|
|
320
|
+
click.echo(result["output"])
|
|
321
|
+
else:
|
|
322
|
+
click.echo("❌ Command execution failed")
|
|
323
|
+
if result["error"]:
|
|
324
|
+
click.echo(f"Error: {result['error']}")
|
|
325
|
+
|
|
326
|
+
click.echo(f"Execution time: {result.get('execution_time_ms', 0)}ms")
|
|
327
|
+
|
|
328
|
+
except Exception as e:
|
|
329
|
+
click.echo(f"❌ Error executing command: {e}", err=True)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
@client.command()
|
|
333
|
+
@click.argument("query")
|
|
334
|
+
@click.option("--limit", default=10, help="Maximum number of results")
|
|
335
|
+
@click.option("--similar", is_flag=True, help="Use similarity search")
|
|
336
|
+
def search(query: str, limit: int, similar: bool):
|
|
337
|
+
"""Search for commands"""
|
|
338
|
+
client = DaemonClient()
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
if similar:
|
|
342
|
+
results = client.find_similar_commands(query, limit)
|
|
343
|
+
if results:
|
|
344
|
+
click.echo(f"Found {len(results)} similar command(s):")
|
|
345
|
+
for cmd, similarity in results:
|
|
346
|
+
click.echo(f" {cmd.name} ({cmd.language}) - {cmd.description}")
|
|
347
|
+
click.echo(f" Similarity: {similarity:.3f}")
|
|
348
|
+
if cmd.tags:
|
|
349
|
+
click.echo(f" Tags: {', '.join(cmd.tags)}")
|
|
350
|
+
click.echo()
|
|
351
|
+
else:
|
|
352
|
+
click.echo("No similar commands found")
|
|
353
|
+
else:
|
|
354
|
+
commands = client.search_commands(query, limit)
|
|
355
|
+
if commands:
|
|
356
|
+
click.echo(f"Found {len(commands)} command(s):")
|
|
357
|
+
for cmd in commands:
|
|
358
|
+
click.echo(f" {cmd.name} ({cmd.language}) - {cmd.description}")
|
|
359
|
+
if cmd.tags:
|
|
360
|
+
click.echo(f" Tags: {', '.join(cmd.tags)}")
|
|
361
|
+
click.echo()
|
|
362
|
+
else:
|
|
363
|
+
click.echo("No commands found")
|
|
364
|
+
|
|
365
|
+
except Exception as e:
|
|
366
|
+
click.echo(f"❌ Error searching commands: {e}", err=True)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
@client.command()
|
|
370
|
+
@click.option("--group", help="Filter by group")
|
|
371
|
+
@click.option("--language", help="Filter by language")
|
|
372
|
+
def list(group: str, language: str):
|
|
373
|
+
"""List all commands"""
|
|
374
|
+
client = DaemonClient()
|
|
375
|
+
|
|
376
|
+
try:
|
|
377
|
+
commands = client.get_all_commands()
|
|
378
|
+
|
|
379
|
+
# Apply filters
|
|
380
|
+
if group:
|
|
381
|
+
commands = [cmd for cmd in commands if cmd.group == group]
|
|
382
|
+
if language:
|
|
383
|
+
commands = [cmd for cmd in commands if cmd.language == language]
|
|
384
|
+
|
|
385
|
+
if not commands:
|
|
386
|
+
click.echo("No commands found")
|
|
387
|
+
return
|
|
388
|
+
|
|
389
|
+
click.echo(f"Found {len(commands)} command(s):")
|
|
390
|
+
for cmd in commands:
|
|
391
|
+
click.echo(f" {cmd.name} ({cmd.language}) - {cmd.description}")
|
|
392
|
+
if cmd.group:
|
|
393
|
+
click.echo(f" Group: {cmd.group}")
|
|
394
|
+
if cmd.tags:
|
|
395
|
+
click.echo(f" Tags: {', '.join(cmd.tags)}")
|
|
396
|
+
click.echo(f" Executed {cmd.execution_count} times")
|
|
397
|
+
click.echo()
|
|
398
|
+
|
|
399
|
+
except Exception as e:
|
|
400
|
+
click.echo(f"❌ Error listing commands: {e}", err=True)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
@client.command()
|
|
404
|
+
@click.argument("command_id")
|
|
405
|
+
def show(command_id: str):
|
|
406
|
+
"""Show command details"""
|
|
407
|
+
client = DaemonClient()
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
command = client.get_command(command_id)
|
|
411
|
+
if not command:
|
|
412
|
+
click.echo(f"Command '{command_id}' not found")
|
|
413
|
+
return
|
|
414
|
+
|
|
415
|
+
click.echo(f"Command: {command.name}")
|
|
416
|
+
click.echo(f"ID: {command.id}")
|
|
417
|
+
click.echo(f"Description: {command.description}")
|
|
418
|
+
click.echo(f"Language: {command.language}")
|
|
419
|
+
if command.group:
|
|
420
|
+
click.echo(f"Group: {command.group}")
|
|
421
|
+
if command.tags:
|
|
422
|
+
click.echo(f"Tags: {', '.join(command.tags)}")
|
|
423
|
+
click.echo(f"Created: {command.created_at}")
|
|
424
|
+
click.echo(f"Updated: {command.updated_at}")
|
|
425
|
+
click.echo(f"Executed: {command.execution_count} times")
|
|
426
|
+
if command.last_executed:
|
|
427
|
+
click.echo(f"Last executed: {command.last_executed}")
|
|
428
|
+
click.echo()
|
|
429
|
+
click.echo("Code:")
|
|
430
|
+
click.echo("=" * 50)
|
|
431
|
+
click.echo(command.code)
|
|
432
|
+
click.echo("=" * 50)
|
|
433
|
+
|
|
434
|
+
except Exception as e:
|
|
435
|
+
click.echo(f"❌ Error showing command: {e}", err=True)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
@client.command()
|
|
439
|
+
@click.argument("command_id")
|
|
440
|
+
def delete(command_id: str):
|
|
441
|
+
"""Delete a command"""
|
|
442
|
+
client = DaemonClient()
|
|
443
|
+
|
|
444
|
+
try:
|
|
445
|
+
command = client.get_command(command_id)
|
|
446
|
+
if not command:
|
|
447
|
+
click.echo(f"Command '{command_id}' not found")
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
if click.confirm(f"Are you sure you want to delete command '{command.name}'?"):
|
|
451
|
+
if client.delete_command(command_id):
|
|
452
|
+
click.echo(f"✅ Command '{command.name}' deleted")
|
|
453
|
+
else:
|
|
454
|
+
click.echo(f"❌ Error deleting command '{command.name}'")
|
|
455
|
+
else:
|
|
456
|
+
click.echo("Deletion cancelled")
|
|
457
|
+
|
|
458
|
+
except Exception as e:
|
|
459
|
+
click.echo(f"❌ Error deleting command: {e}", err=True)
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
@client.command()
|
|
463
|
+
@click.argument("command_id")
|
|
464
|
+
@click.option("--name", help="New name")
|
|
465
|
+
@click.option("--description", help="New description")
|
|
466
|
+
@click.option("--group", help="New group")
|
|
467
|
+
@click.option("--tags", help="New tags (comma-separated)")
|
|
468
|
+
def edit(command_id: str, name: str, description: str, group: str, tags: str):
|
|
469
|
+
"""Edit a command"""
|
|
470
|
+
client = DaemonClient()
|
|
471
|
+
|
|
472
|
+
try:
|
|
473
|
+
command = client.get_command(command_id)
|
|
474
|
+
if not command:
|
|
475
|
+
click.echo(f"Command '{command_id}' not found")
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
# Update fields if provided
|
|
479
|
+
if name:
|
|
480
|
+
command.name = name
|
|
481
|
+
if description:
|
|
482
|
+
command.description = description
|
|
483
|
+
if group:
|
|
484
|
+
command.group = group
|
|
485
|
+
if tags:
|
|
486
|
+
command.tags = [tag.strip() for tag in tags.split(",")]
|
|
487
|
+
|
|
488
|
+
command.updated_at = datetime.now()
|
|
489
|
+
|
|
490
|
+
if client.update_command(command):
|
|
491
|
+
click.echo(f"✅ Command '{command.name}' updated")
|
|
492
|
+
else:
|
|
493
|
+
click.echo(f"❌ Error updating command '{command.name}'")
|
|
494
|
+
|
|
495
|
+
except Exception as e:
|
|
496
|
+
click.echo(f"❌ Error editing command: {e}", err=True)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
@client.command()
|
|
500
|
+
def groups():
|
|
501
|
+
"""List all command groups"""
|
|
502
|
+
client = DaemonClient()
|
|
503
|
+
|
|
504
|
+
try:
|
|
505
|
+
commands = client.get_all_commands()
|
|
506
|
+
groups = {}
|
|
507
|
+
|
|
508
|
+
for cmd in commands:
|
|
509
|
+
group = cmd.group or "ungrouped"
|
|
510
|
+
if group not in groups:
|
|
511
|
+
groups[group] = []
|
|
512
|
+
groups[group].append(cmd)
|
|
513
|
+
|
|
514
|
+
if not groups:
|
|
515
|
+
click.echo("No groups found")
|
|
516
|
+
return
|
|
517
|
+
|
|
518
|
+
click.echo("Command groups:")
|
|
519
|
+
for group_name, group_commands in groups.items():
|
|
520
|
+
click.echo(f" {group_name} ({len(group_commands)} commands)")
|
|
521
|
+
for cmd in group_commands:
|
|
522
|
+
click.echo(f" - {cmd.name} ({cmd.language})")
|
|
523
|
+
click.echo()
|
|
524
|
+
|
|
525
|
+
except Exception as e:
|
|
526
|
+
click.echo(f"❌ Error listing groups: {e}", err=True)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
if __name__ == "__main__":
|
|
530
|
+
client()
|