mcli-framework 7.8.4__py3-none-any.whl → 7.9.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.

Files changed (81) hide show
  1. mcli/__init__.py +160 -0
  2. mcli/__main__.py +14 -0
  3. mcli/app/__init__.py +23 -0
  4. mcli/app/main.py +10 -17
  5. mcli/app/model/__init__.py +0 -0
  6. mcli/app/model_cmd.py +57 -472
  7. mcli/app/video/__init__.py +5 -0
  8. mcli/chat/__init__.py +34 -0
  9. mcli/lib/__init__.py +0 -0
  10. mcli/lib/api/__init__.py +0 -0
  11. mcli/lib/auth/__init__.py +1 -0
  12. mcli/lib/config/__init__.py +1 -0
  13. mcli/lib/erd/__init__.py +25 -0
  14. mcli/lib/files/__init__.py +0 -0
  15. mcli/lib/fs/__init__.py +1 -0
  16. mcli/lib/lib.py +8 -1
  17. mcli/lib/logger/__init__.py +3 -0
  18. mcli/lib/performance/__init__.py +17 -0
  19. mcli/lib/pickles/__init__.py +1 -0
  20. mcli/lib/secrets/__init__.py +10 -0
  21. mcli/lib/secrets/commands.py +185 -0
  22. mcli/lib/secrets/manager.py +213 -0
  23. mcli/lib/secrets/repl.py +297 -0
  24. mcli/lib/secrets/store.py +246 -0
  25. mcli/lib/shell/__init__.py +0 -0
  26. mcli/lib/toml/__init__.py +1 -0
  27. mcli/lib/watcher/__init__.py +0 -0
  28. mcli/ml/__init__.py +16 -0
  29. mcli/ml/api/__init__.py +30 -0
  30. mcli/ml/api/routers/__init__.py +27 -0
  31. mcli/ml/auth/__init__.py +41 -0
  32. mcli/ml/backtesting/__init__.py +33 -0
  33. mcli/ml/cli/__init__.py +5 -0
  34. mcli/ml/config/__init__.py +33 -0
  35. mcli/ml/configs/__init__.py +16 -0
  36. mcli/ml/dashboard/__init__.py +12 -0
  37. mcli/ml/dashboard/components/__init__.py +7 -0
  38. mcli/ml/dashboard/pages/__init__.py +6 -0
  39. mcli/ml/data_ingestion/__init__.py +29 -0
  40. mcli/ml/database/__init__.py +40 -0
  41. mcli/ml/experimentation/__init__.py +29 -0
  42. mcli/ml/features/__init__.py +39 -0
  43. mcli/ml/mlops/__init__.py +19 -0
  44. mcli/ml/models/__init__.py +90 -0
  45. mcli/ml/monitoring/__init__.py +25 -0
  46. mcli/ml/optimization/__init__.py +27 -0
  47. mcli/ml/predictions/__init__.py +5 -0
  48. mcli/ml/preprocessing/__init__.py +24 -0
  49. mcli/ml/scripts/__init__.py +1 -0
  50. mcli/ml/trading/__init__.py +63 -0
  51. mcli/ml/training/__init__.py +7 -0
  52. mcli/mygroup/__init__.py +3 -0
  53. mcli/public/__init__.py +1 -0
  54. mcli/public/commands/__init__.py +2 -0
  55. mcli/self/__init__.py +3 -0
  56. mcli/self/self_cmd.py +8 -0
  57. mcli/self/zsh_cmd.py +259 -0
  58. mcli/workflow/__init__.py +0 -0
  59. mcli/workflow/daemon/__init__.py +15 -0
  60. mcli/workflow/dashboard/__init__.py +5 -0
  61. mcli/workflow/docker/__init__.py +0 -0
  62. mcli/workflow/file/__init__.py +0 -0
  63. mcli/workflow/gcloud/__init__.py +1 -0
  64. mcli/workflow/git_commit/__init__.py +0 -0
  65. mcli/workflow/interview/__init__.py +0 -0
  66. mcli/workflow/politician_trading/__init__.py +4 -0
  67. mcli/workflow/registry/__init__.py +0 -0
  68. mcli/workflow/repo/__init__.py +0 -0
  69. mcli/workflow/scheduler/__init__.py +25 -0
  70. mcli/workflow/search/__init__.py +0 -0
  71. mcli/workflow/sync/__init__.py +5 -0
  72. mcli/workflow/videos/__init__.py +1 -0
  73. mcli/workflow/wakatime/__init__.py +80 -0
  74. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/METADATA +2 -1
  75. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/RECORD +79 -12
  76. mcli/app/chat_cmd.py +0 -42
  77. mcli/test/test_cmd.py +0 -20
  78. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/WHEEL +0 -0
  79. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/entry_points.txt +0 -0
  80. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/licenses/LICENSE +0 -0
  81. {mcli_framework-7.8.4.dist-info → mcli_framework-7.9.0.dist-info}/top_level.txt +0 -0
mcli/app/model_cmd.py CHANGED
@@ -1,481 +1,66 @@
1
- """Model management commands for MCLI."""
1
+ """
2
+ Model command stub - redirects to workflow command in ~/.mcli/commands/model.json
3
+
4
+ This stub exists for backwards compatibility with tests and imports.
5
+ The actual model command implementation is now in ~/.mcli/commands/model.json
6
+ """
2
7
 
3
- import os
4
- import subprocess
5
8
  import sys
6
9
  from pathlib import Path
7
- from typing import Optional
8
-
9
- import click
10
- import psutil
11
-
12
- from mcli.lib.logger.logger import get_logger
13
- from mcli.workflow.model_service.lightweight_model_server import (
14
- LIGHTWEIGHT_MODELS,
15
- LightweightModelServer,
16
- )
17
-
18
- logger = get_logger(__name__)
19
-
20
-
21
- def _start_openai_server(server, host: str, port: int, api_key: Optional[str], model: str):
22
- """Start FastAPI server with OpenAI compatibility"""
23
- try:
24
- import uvicorn
25
- from fastapi import FastAPI
26
- from fastapi.middleware.cors import CORSMiddleware
27
-
28
- from mcli.workflow.model_service.openai_adapter import create_openai_adapter
29
-
30
- # Create FastAPI app
31
- app = FastAPI(
32
- title="MCLI Model Service (OpenAI Compatible)",
33
- description="OpenAI-compatible API for MCLI lightweight models",
34
- version="1.0.0",
35
- )
36
-
37
- # Add CORS middleware
38
- app.add_middleware(
39
- CORSMiddleware,
40
- allow_origins=["*"],
41
- allow_credentials=True,
42
- allow_methods=["*"],
43
- allow_headers=["*"],
44
- )
45
-
46
- # Create OpenAI adapter
47
- require_auth = api_key is not None
48
- adapter = create_openai_adapter(server, require_auth=require_auth)
49
-
50
- # Add API key if provided
51
- if api_key:
52
- adapter.api_key_manager.add_key(api_key, name="default")
53
- click.echo(f"🔐 API key authentication enabled")
54
-
55
- # Include OpenAI routes
56
- app.include_router(adapter.router)
57
-
58
- # Add health check endpoint
59
- @app.get("/health")
60
- async def health():
61
- return {"status": "healthy", "model": model}
62
-
63
- # Display server info
64
- click.echo(f"\n📝 Server running at:")
65
- click.echo(f" - Base URL: http://{host}:{port}")
66
- click.echo(f" - OpenAI API: http://{host}:{port}/v1")
67
- click.echo(f" - Models: http://{host}:{port}/v1/models")
68
- click.echo(f" - Chat: http://{host}:{port}/v1/chat/completions")
69
- click.echo(f" - Health: http://{host}:{port}/health")
70
-
71
- if require_auth:
72
- click.echo(f"\n🔐 Authentication: Required")
73
- click.echo(f" Use: Authorization: Bearer {api_key}")
74
- else:
75
- click.echo(f"\n⚠️ Authentication: Disabled (not recommended for public access)")
76
-
77
- if host == "0.0.0.0":
78
- click.echo(f"\n⚠️ Server is publicly accessible on all interfaces!")
79
-
80
- click.echo(f"\n📚 For aider, use:")
81
- if require_auth:
82
- click.echo(f" export OPENAI_API_KEY={api_key}")
83
- click.echo(f" export OPENAI_API_BASE=http://{host}:{port}/v1")
84
- click.echo(f" aider --model {model}")
85
-
86
- click.echo(f"\n Press Ctrl+C to stop the server")
87
-
88
- # Start server
89
- uvicorn.run(app, host=host, port=port, log_level="info")
90
-
91
- except ImportError as e:
92
- click.echo(f"❌ Missing dependencies for OpenAI-compatible server: {e}")
93
- click.echo(f" Install with: pip install fastapi uvicorn")
94
- sys.exit(1)
95
- except Exception as e:
96
- click.echo(f"❌ Failed to start OpenAI-compatible server: {e}")
97
- logger.error(f"Server error: {e}", exc_info=True)
98
- sys.exit(1)
99
-
100
-
101
- @click.group()
102
- def model():
103
- """Model management commands for offline and online model usage."""
104
- pass
105
-
106
-
107
- @model.command()
108
- @click.option("--list-available", "-l", is_flag=True, help="List all available lightweight models")
109
- @click.option("--list-downloaded", "-d", is_flag=True, help="List downloaded models")
110
- @click.option(
111
- "--system-info", "-s", is_flag=True, help="Show system information and recommendations"
112
- )
113
- def list(list_available: bool, list_downloaded: bool, system_info: bool):
114
- """List available and downloaded models."""
115
- server = LightweightModelServer()
116
-
117
- if system_info:
118
- info = server.get_system_info()
119
- click.echo("🖥️ System Information:")
120
- click.echo(f" CPU Cores: {info['cpu_count']}")
121
- click.echo(f" RAM: {info['memory_gb']:.1f} GB")
122
- click.echo(f" Free Disk: {info['disk_free_gb']:.1f} GB")
123
- recommended = server.recommend_model()
124
- click.echo(f" Recommended Model: {recommended}")
125
- click.echo("")
126
-
127
- if list_available or (not list_downloaded and not system_info):
128
- click.echo("📋 Available Lightweight Models:")
129
- click.echo("=" * 50)
130
-
131
- downloaded_models = server.downloader.get_downloaded_models()
132
-
133
- for key, info in LIGHTWEIGHT_MODELS.items():
134
- status = "✅ Downloaded" if key in downloaded_models else "⏳ Available"
135
- click.echo(f"{status} - {info['name']} ({info['parameters']})")
136
- click.echo(
137
- f" Size: {info['size_mb']} MB | Efficiency: {info['efficiency_score']}/10"
138
- )
139
- click.echo(f" Type: {info['model_type']} | Tags: {', '.join(info['tags'])}")
140
- click.echo()
141
-
142
- if list_downloaded:
143
- downloaded_models = server.downloader.get_downloaded_models()
144
- if downloaded_models:
145
- click.echo("📦 Downloaded Models:")
146
- click.echo("=" * 30)
147
- for model in downloaded_models:
148
- info = LIGHTWEIGHT_MODELS.get(model, {})
149
- name = info.get("name", model)
150
- params = info.get("parameters", "Unknown")
151
- click.echo(f"✅ {name} ({params})")
152
- else:
153
- click.echo(
154
- "No models downloaded yet. Use 'mcli model download <model>' to download a model."
155
- )
156
-
157
-
158
- @model.command()
159
- @click.argument("model_name")
160
- def download(model_name: str):
161
- """Download a specific lightweight model."""
162
- if model_name not in LIGHTWEIGHT_MODELS:
163
- click.echo(f"❌ Model '{model_name}' not found.")
164
- click.echo("Available models:")
165
- for key in LIGHTWEIGHT_MODELS.keys():
166
- click.echo(f" • {key}")
167
- sys.exit(1)
168
-
169
- server = LightweightModelServer()
170
-
171
- click.echo(f"Downloading model: {model_name}")
172
- success = server.download_and_load_model(model_name)
173
-
174
- if success:
175
- click.echo(f"✅ Successfully downloaded {model_name}")
176
- else:
177
- click.echo(f"❌ Failed to download {model_name}")
178
- sys.exit(1)
179
-
180
-
181
- @model.command()
182
- @click.option("--model", "-m", help="Specific model to use")
183
- @click.option(
184
- "--port", "-p", default=None, help="Port to run server on (default: from config or 51234)"
185
- )
186
- @click.option(
187
- "--host", "-h", default="localhost", help="Host to bind to (use 0.0.0.0 for public access)"
188
- )
189
- @click.option(
190
- "--auto-download",
191
- is_flag=True,
192
- default=True,
193
- help="Automatically download model if not available",
194
- )
195
- @click.option(
196
- "--openai-compatible",
197
- is_flag=True,
198
- default=False,
199
- help="Enable OpenAI-compatible API endpoints",
200
- )
201
- @click.option(
202
- "--api-key",
203
- default=None,
204
- help="API key for authentication (if not set, auth is disabled)",
205
- )
206
- def start(
207
- model: Optional[str],
208
- port: Optional[int],
209
- host: str,
210
- auto_download: bool,
211
- openai_compatible: bool,
212
- api_key: Optional[str],
213
- ):
214
- """Start the lightweight model server."""
215
- # Load port from config if not specified
216
- if port is None:
217
- try:
218
- from mcli.lib.config.config import load_config
219
-
220
- config = load_config()
221
- port = config.get("model", {}).get("server_port", 51234)
222
- except Exception:
223
- port = 51234 # Default ephemeral port
224
-
225
- server = LightweightModelServer(port=port)
226
-
227
- # Determine which model to use
228
- if not model:
229
- model = server.recommend_model()
230
- click.echo(f"🎯 Using recommended model: {model}")
231
- elif model not in LIGHTWEIGHT_MODELS:
232
- click.echo(f"❌ Model '{model}' not found.")
233
- click.echo("Available models:")
234
- for key in LIGHTWEIGHT_MODELS.keys():
235
- click.echo(f" • {key}")
236
- sys.exit(1)
237
10
 
238
- # Check if model is downloaded, download if needed
239
- downloaded_models = server.downloader.get_downloaded_models()
240
- if model not in downloaded_models:
241
- if auto_download:
242
- click.echo(f"📥 Model {model} not found locally, downloading...")
243
- success = server.download_and_load_model(model)
244
- if not success:
245
- click.echo(f"❌ Failed to download {model}")
246
- sys.exit(1)
11
+ # Try to load the model command from the workflow system
12
+ try:
13
+ from mcli.lib.custom_commands import load_command_from_file
14
+
15
+ # Load model command from ~/.mcli/commands/model.json
16
+ model_json_path = Path.home() / ".mcli" / "commands" / "model.json"
17
+
18
+ if model_json_path.exists():
19
+ # Load the command from the JSON file
20
+ import json
21
+
22
+ with open(model_json_path, "r") as f:
23
+ command_data = json.load(f)
24
+
25
+ # Execute the code to get the app (model command group)
26
+ code = command_data.get("code", "")
27
+ namespace = {}
28
+ exec(code, namespace)
29
+
30
+ # Extract the app (model command group) and individual commands
31
+ app = namespace.get("app")
32
+ if app:
33
+ # The model group command
34
+ model = app
35
+
36
+ # Extract individual subcommands from the model group
37
+ if hasattr(model, "commands"):
38
+ commands = model.commands
39
+ list = commands.get("list")
40
+ download = commands.get("download")
41
+ start = commands.get("start")
42
+ recommend = commands.get("recommend")
43
+ status = commands.get("status")
44
+ stop = commands.get("stop")
45
+ pull = commands.get("pull")
46
+ delete = commands.get("delete")
47
+ else:
48
+ # Fallback if commands aren't available
49
+ list = download = start = recommend = status = stop = pull = delete = None
247
50
  else:
248
- click.echo(
249
- f"❌ Model {model} not found locally. Use --auto-download to download automatically."
250
- )
251
- sys.exit(1)
51
+ # If app is not found, create empty placeholders
52
+ model = list = download = start = recommend = status = stop = pull = delete = None
252
53
  else:
253
- # Load the already downloaded model
254
- success = server.download_and_load_model(model)
255
- if not success:
256
- click.echo(f"❌ Failed to load {model}")
257
- sys.exit(1)
54
+ # If the JSON file doesn't exist, create empty placeholders
55
+ print(f"Warning: {model_json_path} not found", file=sys.stderr)
56
+ model = list = download = start = recommend = status = stop = pull = delete = None
258
57
 
259
- # Start server with OpenAI compatibility if requested
260
- if openai_compatible:
261
- click.echo(f"🚀 Starting OpenAI-compatible server on {host}:{port}...")
262
- _start_openai_server(server, host, port, api_key, model)
263
- else:
264
- click.echo(f"🚀 Starting lightweight server on {host}:{port}...")
265
- server.start_server()
266
-
267
- click.echo(f"\n📝 Server running at:")
268
- click.echo(f" - API: http://{host}:{port}")
269
- click.echo(f" - Health: http://{host}:{port}/health")
270
- click.echo(f" - Models: http://{host}:{port}/models")
271
-
272
- if host == "0.0.0.0":
273
- click.echo(f"\n⚠️ Server is publicly accessible!")
274
- click.echo(f" Consider using --openai-compatible with --api-key for security")
275
-
276
- click.echo(f"\n Press Ctrl+C to stop the server")
277
-
278
- try:
279
- # Keep server running
280
- import time
281
-
282
- while True:
283
- time.sleep(1)
284
- except KeyboardInterrupt:
285
- click.echo("\n🛑 Server stopped")
286
-
287
-
288
- @model.command()
289
- def recommend():
290
- """Get model recommendation based on system capabilities."""
291
- server = LightweightModelServer()
292
- recommended = server.recommend_model()
293
-
294
- info = server.get_system_info()
295
- click.echo("🔍 System Analysis:")
296
- click.echo(f" CPU Cores: {info['cpu_count']}")
297
- click.echo(f" RAM: {info['memory_gb']:.1f} GB")
298
- click.echo(f" Free Disk: {info['disk_free_gb']:.1f} GB")
299
- click.echo("")
300
-
301
- model_info = LIGHTWEIGHT_MODELS[recommended]
302
- click.echo(f"🎯 Recommended Model: {recommended}")
303
- click.echo(f" Name: {model_info['name']}")
304
- click.echo(f" Description: {model_info['description']}")
305
- click.echo(f" Parameters: {model_info['parameters']}")
306
- click.echo(f" Size: {model_info['size_mb']} MB")
307
- click.echo(f" Efficiency Score: {model_info['efficiency_score']}/10")
308
-
309
- downloaded_models = server.downloader.get_downloaded_models()
310
- if recommended not in downloaded_models:
311
- click.echo(f"\n💡 To download: mcli model download {recommended}")
312
- else:
313
- click.echo(f"\n✅ Model already downloaded")
314
-
315
-
316
- @model.command()
317
- @click.option(
318
- "--port",
319
- "-p",
320
- default=None,
321
- help="Port where server is running (default: from config or 51234)",
322
- )
323
- def status(port: Optional[int]):
324
- """Check status of the lightweight model server."""
325
- # Load port from config if not specified
326
- if port is None:
327
- try:
328
- from mcli.lib.config.config import load_config
329
-
330
- config = load_config()
331
- port = config.get("model", {}).get("server_port", 51234)
332
- except Exception:
333
- port = 51234 # Default ephemeral port
334
-
335
- import requests
336
-
337
- try:
338
- response = requests.get(f"http://localhost:{port}/health", timeout=5)
339
- if response.status_code == 200:
340
- click.echo(f"✅ Server is running on port {port}")
341
-
342
- # Get loaded models
343
- models_response = requests.get(f"http://localhost:{port}/models", timeout=5)
344
- if models_response.status_code == 200:
345
- models_data = models_response.json()
346
- models = models_data.get("models", [])
347
- if models:
348
- click.echo(f"🤖 Loaded models ({len(models)}):")
349
- for model in models:
350
- click.echo(f" - {model['name']} ({model['parameters']})")
351
- else:
352
- click.echo("⚠️ No models currently loaded")
353
- else:
354
- click.echo(f"❌ Server responded with status {response.status_code}")
355
-
356
- except requests.exceptions.ConnectionError:
357
- click.echo(f"❌ No server running on port {port}")
358
- except requests.exceptions.Timeout:
359
- click.echo(f"⏰ Server on port {port} is not responding")
360
- except Exception as e:
361
- click.echo(f"❌ Error checking server: {e}")
362
-
363
-
364
- @model.command()
365
- @click.option(
366
- "--port",
367
- "-p",
368
- default=None,
369
- help="Port where server is running (default: from config or 51234)",
370
- )
371
- def stop(port: Optional[int]):
372
- """Stop the lightweight model server."""
373
- # Load port from config if not specified
374
- if port is None:
375
- try:
376
- from mcli.lib.config.config import load_config
377
-
378
- config = load_config()
379
- port = config.get("model", {}).get("server_port", 51234)
380
- except Exception:
381
- port = 51234 # Default ephemeral port
382
-
383
- import psutil
384
- import requests
385
-
386
- try:
387
- # First check if server is running
388
- try:
389
- response = requests.get(f"http://localhost:{port}/health", timeout=2)
390
- if response.status_code != 200:
391
- click.echo(f"❌ No server running on port {port}")
392
- return
393
- except requests.exceptions.ConnectionError:
394
- click.echo(f"❌ No server running on port {port}")
395
- return
396
-
397
- # Find and kill the process using the port
398
- for proc in psutil.process_iter(["pid", "name", "connections"]):
399
- try:
400
- connections = proc.info.get("connections")
401
- if connections:
402
- for conn in connections:
403
- if hasattr(conn, "laddr") and conn.laddr.port == port:
404
- click.echo(f"🛑 Stopping server (PID: {proc.pid})...")
405
- proc.terminate()
406
- proc.wait(timeout=5)
407
- click.echo("✅ Server stopped successfully")
408
- return
409
- except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
410
- continue
411
-
412
- click.echo("⚠️ Could not find server process")
413
-
414
- except Exception as e:
415
- click.echo(f"❌ Error stopping server: {e}")
416
-
417
-
418
- @model.command()
419
- @click.argument("model_name")
420
- def pull(model_name: str):
421
- """Pull (download) a specific lightweight model."""
422
- if model_name not in LIGHTWEIGHT_MODELS:
423
- click.echo(f"❌ Model '{model_name}' not found.")
424
- click.echo("Available models:")
425
- for key in LIGHTWEIGHT_MODELS.keys():
426
- click.echo(f" • {key}")
427
- sys.exit(1)
428
-
429
- server = LightweightModelServer()
430
-
431
- click.echo(f"Pulling model: {model_name}")
432
- success = server.download_and_load_model(model_name)
433
-
434
- if success:
435
- click.echo(f"✅ Successfully pulled {model_name}")
436
- else:
437
- click.echo(f"❌ Failed to pull {model_name}")
438
- sys.exit(1)
439
-
440
-
441
- @model.command()
442
- @click.argument("model_name")
443
- @click.option("--force", "-f", is_flag=True, help="Force deletion without confirmation")
444
- def delete(model_name: str, force: bool):
445
- """Delete a downloaded lightweight model."""
446
- server = LightweightModelServer()
447
- downloaded_models = server.downloader.get_downloaded_models()
448
-
449
- if model_name not in downloaded_models:
450
- click.echo(f"❌ Model '{model_name}' not found.")
451
- click.echo("Downloaded models:")
452
- if downloaded_models:
453
- for model in downloaded_models:
454
- click.echo(f" • {model}")
455
- else:
456
- click.echo(" (none)")
457
- sys.exit(1)
458
-
459
- # Confirm deletion unless --force is used
460
- if not force:
461
- model_info = LIGHTWEIGHT_MODELS.get(model_name, {})
462
- name = model_info.get("name", model_name)
463
- size = model_info.get("size_mb", "unknown")
464
- click.echo(f"⚠️ About to delete:")
465
- click.echo(f" Model: {name}")
466
- click.echo(f" Size: {size} MB")
467
- if not click.confirm("Are you sure you want to delete this model?"):
468
- click.echo("❌ Deletion cancelled")
469
- return
470
-
471
- success = server.delete_model(model_name)
472
-
473
- if success:
474
- click.echo(f"✅ Successfully deleted {model_name}")
475
- else:
476
- click.echo(f"❌ Failed to delete {model_name}")
477
- sys.exit(1)
58
+ except Exception as e:
59
+ print(f"Error loading model command from workflow: {e}", file=sys.stderr)
60
+ import traceback
478
61
 
62
+ traceback.print_exc()
63
+ model = list = download = start = recommend = status = stop = pull = delete = None
479
64
 
480
- if __name__ == "__main__":
481
- model()
65
+ # Export the commands for backwards compatibility
66
+ __all__ = ["model", "list", "download", "start", "recommend", "status", "stop", "pull", "delete"]
@@ -0,0 +1,5 @@
1
+ """
2
+ Video processing commands for mcli.
3
+ """
4
+
5
+ from .video import *
mcli/chat/__init__.py ADDED
@@ -0,0 +1,34 @@
1
+ """
2
+ MCLI Chat System
3
+ Real-time system control and interaction capabilities for MCLI chat
4
+ """
5
+
6
+ from .system_controller import (
7
+ SystemController,
8
+ control_app,
9
+ execute_system_command,
10
+ open_file_or_url,
11
+ open_textedit_and_write,
12
+ system_controller,
13
+ take_screenshot,
14
+ )
15
+ from .system_integration import (
16
+ ChatSystemIntegration,
17
+ chat_system_integration,
18
+ get_system_capabilities,
19
+ handle_system_request,
20
+ )
21
+
22
+ __all__ = [
23
+ "SystemController",
24
+ "system_controller",
25
+ "ChatSystemIntegration",
26
+ "chat_system_integration",
27
+ "handle_system_request",
28
+ "get_system_capabilities",
29
+ "open_textedit_and_write",
30
+ "control_app",
31
+ "execute_system_command",
32
+ "take_screenshot",
33
+ "open_file_or_url",
34
+ ]
mcli/lib/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1 @@
1
+ from .auth import *
@@ -0,0 +1 @@
1
+ from .config import *
@@ -0,0 +1,25 @@
1
+ """
2
+ Entity Relationship Diagram (ERD) package.
3
+
4
+ This package provides utilities for generating Entity Relationship Diagrams from MCLI type metadata.
5
+ """
6
+
7
+ # Import and export all public functions from erd.py
8
+ from .erd import (
9
+ analyze_graph_for_hierarchical_exports,
10
+ create_merged_erd,
11
+ do_erd,
12
+ find_top_nodes_in_graph,
13
+ generate_erd_for_top_nodes,
14
+ generate_merged_erd_for_types,
15
+ )
16
+
17
+ # Define __all__ to control exports
18
+ __all__ = [
19
+ "do_erd",
20
+ "create_merged_erd",
21
+ "generate_merged_erd_for_types",
22
+ "find_top_nodes_in_graph",
23
+ "generate_erd_for_top_nodes",
24
+ "analyze_graph_for_hierarchical_exports",
25
+ ]
File without changes
@@ -0,0 +1 @@
1
+ from .fs import *
mcli/lib/lib.py CHANGED
@@ -3,6 +3,8 @@ import sys
3
3
 
4
4
  import click
5
5
 
6
+ from mcli.lib.secrets.commands import secrets_group
7
+
6
8
 
7
9
  def import_public_module(module_name: str):
8
10
  prefix = "mcli.public."
@@ -20,10 +22,15 @@ def import_public_module(module_name: str):
20
22
  return module
21
23
 
22
24
 
23
- @click.group(name="lib")
25
+ @click.group(name="lib", help="Library utilities and secrets management")
24
26
  def lib():
27
+ """Library utilities and management commands."""
25
28
  pass
26
29
 
27
30
 
31
+ # Add secrets as a subcommand
32
+ lib.add_command(secrets_group)
33
+
34
+
28
35
  if __name__ == "__main__":
29
36
  lib()
@@ -0,0 +1,3 @@
1
+ from .logger import get_logger
2
+
3
+ __all__ = ["get_logger"]
@@ -0,0 +1,17 @@
1
+ """
2
+ Performance optimization utilities for mcli
3
+ """
4
+
5
+ from .uvloop_config import (
6
+ configure_event_loop_for_performance,
7
+ get_event_loop_info,
8
+ install_uvloop,
9
+ should_use_uvloop,
10
+ )
11
+
12
+ __all__ = [
13
+ "install_uvloop",
14
+ "should_use_uvloop",
15
+ "get_event_loop_info",
16
+ "configure_event_loop_for_performance",
17
+ ]
@@ -0,0 +1 @@
1
+ from .pickles import ObjectCache
@@ -0,0 +1,10 @@
1
+ """
2
+ Secrets management module for MCLI.
3
+
4
+ Provides secure storage and retrieval of secrets with git-based synchronization.
5
+ """
6
+
7
+ from .manager import SecretsManager
8
+ from .store import SecretsStore
9
+
10
+ __all__ = ["SecretsManager", "SecretsStore"]