mcli-framework 7.11.4__py3-none-any.whl → 7.12.1__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 (82) hide show
  1. mcli/__init__.py +160 -0
  2. mcli/__main__.py +14 -0
  3. mcli/app/__init__.py +23 -0
  4. mcli/app/commands_cmd.py +18 -823
  5. mcli/app/init_cmd.py +391 -0
  6. mcli/app/lock_cmd.py +288 -0
  7. mcli/app/main.py +39 -42
  8. mcli/app/model/__init__.py +0 -0
  9. mcli/app/store_cmd.py +448 -0
  10. mcli/app/video/__init__.py +5 -0
  11. mcli/chat/__init__.py +34 -0
  12. mcli/lib/__init__.py +0 -0
  13. mcli/lib/api/__init__.py +0 -0
  14. mcli/lib/auth/__init__.py +1 -0
  15. mcli/lib/config/__init__.py +1 -0
  16. mcli/lib/custom_commands.py +3 -3
  17. mcli/lib/erd/__init__.py +25 -0
  18. mcli/lib/files/__init__.py +0 -0
  19. mcli/lib/fs/__init__.py +1 -0
  20. mcli/lib/logger/__init__.py +3 -0
  21. mcli/lib/optional_deps.py +1 -3
  22. mcli/lib/performance/__init__.py +17 -0
  23. mcli/lib/pickles/__init__.py +1 -0
  24. mcli/lib/secrets/__init__.py +10 -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/serving/__init__.py +1 -0
  51. mcli/ml/trading/__init__.py +63 -0
  52. mcli/ml/training/__init__.py +7 -0
  53. mcli/mygroup/__init__.py +3 -0
  54. mcli/public/__init__.py +1 -0
  55. mcli/public/commands/__init__.py +2 -0
  56. mcli/self/__init__.py +3 -0
  57. mcli/self/migrate_cmd.py +209 -76
  58. mcli/self/self_cmd.py +52 -0
  59. mcli/workflow/__init__.py +0 -0
  60. mcli/workflow/daemon/__init__.py +15 -0
  61. mcli/workflow/dashboard/__init__.py +5 -0
  62. mcli/workflow/docker/__init__.py +0 -0
  63. mcli/workflow/file/__init__.py +0 -0
  64. mcli/workflow/gcloud/__init__.py +1 -0
  65. mcli/workflow/git_commit/__init__.py +0 -0
  66. mcli/workflow/interview/__init__.py +0 -0
  67. mcli/workflow/notebook/__init__.py +16 -0
  68. mcli/workflow/registry/__init__.py +0 -0
  69. mcli/workflow/repo/__init__.py +0 -0
  70. mcli/workflow/scheduler/__init__.py +25 -0
  71. mcli/workflow/search/__init__.py +0 -0
  72. mcli/workflow/secrets/__init__.py +5 -0
  73. mcli/workflow/secrets/secrets_cmd.py +1 -2
  74. mcli/workflow/sync/__init__.py +5 -0
  75. mcli/workflow/videos/__init__.py +1 -0
  76. mcli/workflow/wakatime/__init__.py +80 -0
  77. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/METADATA +10 -10
  78. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/RECORD +82 -13
  79. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/WHEEL +0 -0
  80. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/entry_points.txt +0 -0
  81. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/licenses/LICENSE +0 -0
  82. {mcli_framework-7.11.4.dist-info → mcli_framework-7.12.1.dist-info}/top_level.txt +0 -0
mcli/app/main.py CHANGED
@@ -326,6 +326,42 @@ class LazyGroup(click.Group):
326
326
 
327
327
  def _add_lazy_commands(app: click.Group):
328
328
  """Add command groups with lazy loading."""
329
+ # Top-level init command
330
+ try:
331
+ from mcli.app.init_cmd import init
332
+
333
+ app.add_command(init, name="init")
334
+ logger.debug("Added init command")
335
+ except ImportError as e:
336
+ logger.debug(f"Could not load init command: {e}")
337
+
338
+ # Top-level teardown command
339
+ try:
340
+ from mcli.app.init_cmd import teardown
341
+
342
+ app.add_command(teardown, name="teardown")
343
+ logger.debug("Added teardown command")
344
+ except ImportError as e:
345
+ logger.debug(f"Could not load teardown command: {e}")
346
+
347
+ # Top-level lock group
348
+ try:
349
+ from mcli.app.lock_cmd import lock
350
+
351
+ app.add_command(lock, name="lock")
352
+ logger.debug("Added lock group")
353
+ except ImportError as e:
354
+ logger.debug(f"Could not load lock group: {e}")
355
+
356
+ # Top-level store group
357
+ try:
358
+ from mcli.app.store_cmd import store
359
+
360
+ app.add_command(store, name="store")
361
+ logger.debug("Added store group")
362
+ except ImportError as e:
363
+ logger.debug(f"Could not load store group: {e}")
364
+
329
365
  # Workflow management - load immediately for fast access (renamed from 'commands')
330
366
  try:
331
367
  from mcli.app.commands_cmd import workflow
@@ -350,6 +386,7 @@ def _add_lazy_commands(app: click.Group):
350
386
  # Add workflows group directly (not lazy-loaded) to preserve -g/--global option
351
387
  try:
352
388
  from mcli.workflow.workflow import workflows as workflows_group
389
+
353
390
  app.add_command(workflows_group, name="workflows")
354
391
  logger.debug("Added workflows group with -g/--global support")
355
392
  except ImportError as e:
@@ -430,54 +467,14 @@ def create_app() -> click.Group:
430
467
 
431
468
  app = click.Group(name="mcli")
432
469
 
433
- # Clean top-level commands
434
- @app.command()
435
- @click.option("--verbose", "-v", is_flag=True, help="Show additional system information")
436
- def version(verbose: bool):
437
- """Show mcli version and system information"""
438
- message = get_version_info(verbose)
439
- logger.info(message)
440
- info(message)
441
-
470
+ # Version command moved to self group (mcli self version)
442
471
  # Add lazy-loaded command groups
443
472
  _add_lazy_commands(app)
444
473
 
445
474
  return app
446
475
 
447
476
 
448
- @lru_cache()
449
- def get_version_info(verbose: bool = False) -> str:
450
- """Get version info, cached to prevent multiple calls."""
451
- try:
452
- # Try mcli-framework first (PyPI package name), then mcli (local dev)
453
- mcli_version = None
454
- meta = None
455
-
456
- for pkg_name in ["mcli-framework", "mcli"]:
457
- try:
458
- mcli_version = version(pkg_name)
459
- meta = metadata(pkg_name)
460
- break
461
- except Exception:
462
- continue
463
-
464
- if mcli_version is None:
465
- return "Could not determine version: Package metadata not found"
466
-
467
- info = [f"mcli version {mcli_version}"]
468
-
469
- if verbose:
470
- info.extend(
471
- [
472
- f"\nPython: {sys.version.split()[0]}",
473
- f"Platform: {platform.platform()}",
474
- f"Description: {meta.get('Summary', 'Not available')}",
475
- f"Author: {meta.get('Author', 'Not available')}",
476
- ]
477
- )
478
- return "\n".join(info)
479
- except Exception as e:
480
- return f"Could not determine version: {e}"
477
+ # get_version_info moved to self_cmd.py
481
478
 
482
479
 
483
480
  def main():
File without changes
mcli/app/store_cmd.py ADDED
@@ -0,0 +1,448 @@
1
+ """
2
+ Top-level store management commands for MCLI.
3
+ Manages command store - sync ~/.mcli/commands/ to git.
4
+ """
5
+ import shutil
6
+ import subprocess
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+
10
+ import click
11
+
12
+ from mcli.lib.logger.logger import get_logger
13
+ from mcli.lib.ui.styling import error, info, success, warning
14
+
15
+ logger = get_logger(__name__)
16
+
17
+ # Command store configuration
18
+ DEFAULT_STORE_PATH = Path.home() / "repos" / "mcli-commands"
19
+ COMMANDS_PATH = Path.home() / ".mcli" / "commands"
20
+
21
+
22
+ def _get_store_path() -> Path:
23
+ """Get store path from config or default"""
24
+ config_file = Path.home() / ".mcli" / "store.conf"
25
+
26
+ if config_file.exists():
27
+ store_path = Path(config_file.read_text().strip())
28
+ if store_path.exists():
29
+ return store_path
30
+
31
+ # Use default
32
+ return DEFAULT_STORE_PATH
33
+
34
+
35
+ @click.group(name="store")
36
+ def store():
37
+ """Manage command store - sync ~/.mcli/commands/ to git"""
38
+ pass
39
+
40
+
41
+ @store.command(name="init")
42
+ @click.option("--path", "-p", type=click.Path(), help=f"Store path (default: {DEFAULT_STORE_PATH})")
43
+ @click.option("--remote", "-r", help="Git remote URL (optional)")
44
+ def init_store(path, remote):
45
+ """Initialize command store with git"""
46
+ store_path = Path(path) if path else DEFAULT_STORE_PATH
47
+
48
+ try:
49
+ # Create store directory
50
+ store_path.mkdir(parents=True, exist_ok=True)
51
+
52
+ # Initialize git if not already initialized
53
+ git_dir = store_path / ".git"
54
+ if not git_dir.exists():
55
+ subprocess.run(["git", "init"], cwd=store_path, check=True, capture_output=True)
56
+ success(f"Initialized git repository at {store_path}")
57
+
58
+ # Create .gitignore
59
+ gitignore = store_path / ".gitignore"
60
+ gitignore.write_text("*.backup\n.DS_Store\n")
61
+
62
+ # Create README
63
+ readme = store_path / "README.md"
64
+ readme.write_text(
65
+ f"""# MCLI Commands Store
66
+
67
+ Personal workflow commands for mcli framework.
68
+
69
+ ## Usage
70
+
71
+ Push commands:
72
+ ```bash
73
+ mcli store push
74
+ ```
75
+
76
+ Pull commands:
77
+ ```bash
78
+ mcli store pull
79
+ ```
80
+
81
+ Sync (bidirectional):
82
+ ```bash
83
+ mcli store sync
84
+ ```
85
+
86
+ ## Structure
87
+
88
+ All JSON command files from `~/.mcli/commands/` are stored here and version controlled.
89
+
90
+ Last updated: {datetime.now().isoformat()}
91
+ """
92
+ )
93
+
94
+ # Add remote if provided
95
+ if remote:
96
+ subprocess.run(
97
+ ["git", "remote", "add", "origin", remote], cwd=store_path, check=True
98
+ )
99
+ success(f"Added remote: {remote}")
100
+ else:
101
+ info(f"Git repository already exists at {store_path}")
102
+
103
+ # Save store path to config
104
+ config_file = Path.home() / ".mcli" / "store.conf"
105
+ config_file.parent.mkdir(parents=True, exist_ok=True)
106
+ config_file.write_text(str(store_path))
107
+
108
+ success(f"Command store initialized at {store_path}")
109
+ info(f"Store path saved to {config_file}")
110
+
111
+ except subprocess.CalledProcessError as e:
112
+ error(f"Git command failed: {e}")
113
+ logger.error(f"Git init failed: {e}")
114
+ except Exception as e:
115
+ error(f"Failed to initialize store: {e}")
116
+ logger.exception(e)
117
+
118
+
119
+ @store.command(name="push")
120
+ @click.option("--message", "-m", help="Commit message")
121
+ @click.option("--all", "-a", is_flag=True, help="Push all files (including backups)")
122
+ @click.option(
123
+ "--global", "-g", "is_global", is_flag=True, help="Push global commands instead of local"
124
+ )
125
+ def push_commands(message, all, is_global):
126
+ """
127
+ Push commands to git store.
128
+
129
+ By default pushes local commands (if in git repo), use --global/-g for global commands.
130
+ """
131
+ try:
132
+ store_path = _get_store_path()
133
+ from mcli.lib.paths import get_custom_commands_dir
134
+
135
+ COMMANDS_PATH = get_custom_commands_dir(global_mode=is_global)
136
+
137
+ # Copy commands to store
138
+ info(f"Copying commands from {COMMANDS_PATH} to {store_path}...")
139
+
140
+ copied_count = 0
141
+ for item in COMMANDS_PATH.glob("*"):
142
+ # Skip backups unless --all specified
143
+ if not all and item.name.endswith(".backup"):
144
+ continue
145
+
146
+ dest = store_path / item.name
147
+ if item.is_file():
148
+ shutil.copy2(item, dest)
149
+ copied_count += 1
150
+ elif item.is_dir():
151
+ shutil.copytree(item, dest, dirs_exist_ok=True)
152
+ copied_count += 1
153
+
154
+ success(f"Copied {copied_count} items to store")
155
+
156
+ # Git add, commit, push
157
+ subprocess.run(["git", "add", "."], cwd=store_path, check=True)
158
+
159
+ # Check if there are changes
160
+ result = subprocess.run(
161
+ ["git", "status", "--porcelain"], cwd=store_path, capture_output=True, text=True
162
+ )
163
+
164
+ if not result.stdout.strip():
165
+ info("No changes to commit")
166
+ return
167
+
168
+ # Commit with message
169
+ commit_msg = message or f"Update commands {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
170
+ subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True)
171
+ success(f"Committed changes: {commit_msg}")
172
+
173
+ # Push to remote if configured
174
+ try:
175
+ subprocess.run(["git", "push"], cwd=store_path, check=True, capture_output=True)
176
+ success("Pushed to remote")
177
+ except subprocess.CalledProcessError:
178
+ warning("No remote configured or push failed. Commands committed locally.")
179
+
180
+ except Exception as e:
181
+ error(f"Failed to push commands: {e}")
182
+ logger.exception(e)
183
+
184
+
185
+ @store.command(name="pull")
186
+ @click.option("--force", "-f", is_flag=True, help="Overwrite local commands without backup")
187
+ @click.option(
188
+ "--global", "-g", "is_global", is_flag=True, help="Pull to global commands instead of local"
189
+ )
190
+ def pull_commands(force, is_global):
191
+ """
192
+ Pull commands from git store.
193
+
194
+ By default pulls to local commands (if in git repo), use --global/-g for global commands.
195
+ """
196
+ try:
197
+ store_path = _get_store_path()
198
+ from mcli.lib.paths import get_custom_commands_dir
199
+
200
+ COMMANDS_PATH = get_custom_commands_dir(global_mode=is_global)
201
+
202
+ # Pull from remote
203
+ try:
204
+ subprocess.run(["git", "pull"], cwd=store_path, check=True)
205
+ success("Pulled latest changes from remote")
206
+ except subprocess.CalledProcessError:
207
+ warning("No remote configured or pull failed. Using local store.")
208
+
209
+ # Backup existing commands if not force
210
+ if not force and COMMANDS_PATH.exists():
211
+ backup_dir = (
212
+ COMMANDS_PATH.parent / f"commands_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
213
+ )
214
+ shutil.copytree(COMMANDS_PATH, backup_dir)
215
+ info(f"Backed up existing commands to {backup_dir}")
216
+
217
+ # Copy from store to commands directory
218
+ info(f"Copying commands from {store_path} to {COMMANDS_PATH}...")
219
+
220
+ COMMANDS_PATH.mkdir(parents=True, exist_ok=True)
221
+
222
+ copied_count = 0
223
+ for item in store_path.glob("*"):
224
+ # Skip git directory and README
225
+ if item.name in [".git", "README.md", ".gitignore"]:
226
+ continue
227
+
228
+ dest = COMMANDS_PATH / item.name
229
+ if item.is_file():
230
+ shutil.copy2(item, dest)
231
+ copied_count += 1
232
+ elif item.is_dir():
233
+ shutil.copytree(item, dest, dirs_exist_ok=True)
234
+ copied_count += 1
235
+
236
+ success(f"Pulled {copied_count} items from store")
237
+
238
+ except Exception as e:
239
+ error(f"Failed to pull commands: {e}")
240
+ logger.exception(e)
241
+
242
+
243
+ @store.command(name="sync")
244
+ @click.option("--message", "-m", help="Commit message if pushing")
245
+ @click.option(
246
+ "--global", "-g", "is_global", is_flag=True, help="Sync global commands instead of local"
247
+ )
248
+ def sync_commands(message, is_global):
249
+ """
250
+ Sync commands bidirectionally (pull then push if changes).
251
+
252
+ By default syncs local commands (if in git repo), use --global/-g for global commands.
253
+ """
254
+ try:
255
+ store_path = _get_store_path()
256
+ from mcli.lib.paths import get_custom_commands_dir
257
+
258
+ COMMANDS_PATH = get_custom_commands_dir(global_mode=is_global)
259
+
260
+ # First pull
261
+ info("Pulling latest changes...")
262
+ try:
263
+ subprocess.run(["git", "pull"], cwd=store_path, check=True, capture_output=True)
264
+ success("Pulled from remote")
265
+ except subprocess.CalledProcessError:
266
+ warning("No remote or pull failed")
267
+
268
+ # Then push local changes
269
+ info("Pushing local changes...")
270
+
271
+ # Copy commands
272
+ for item in COMMANDS_PATH.glob("*"):
273
+ if item.name.endswith(".backup"):
274
+ continue
275
+ dest = store_path / item.name
276
+ if item.is_file():
277
+ shutil.copy2(item, dest)
278
+ elif item.is_dir():
279
+ shutil.copytree(item, dest, dirs_exist_ok=True)
280
+
281
+ # Check for changes
282
+ result = subprocess.run(
283
+ ["git", "status", "--porcelain"], cwd=store_path, capture_output=True, text=True
284
+ )
285
+
286
+ if not result.stdout.strip():
287
+ success("Everything in sync!")
288
+ return
289
+
290
+ # Commit and push
291
+ subprocess.run(["git", "add", "."], cwd=store_path, check=True)
292
+ commit_msg = message or f"Sync commands {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
293
+ subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True)
294
+
295
+ try:
296
+ subprocess.run(["git", "push"], cwd=store_path, check=True, capture_output=True)
297
+ success("Synced and pushed to remote")
298
+ except subprocess.CalledProcessError:
299
+ success("Synced locally (no remote configured)")
300
+
301
+ except Exception as e:
302
+ error(f"Sync failed: {e}")
303
+ logger.exception(e)
304
+
305
+
306
+ @store.command(name="status")
307
+ def store_status():
308
+ """Show git status of command store"""
309
+ try:
310
+ store_path = _get_store_path()
311
+
312
+ click.echo(f"\n📦 Store: {store_path}\n")
313
+
314
+ # Git status
315
+ result = subprocess.run(
316
+ ["git", "status", "--short", "--branch"], cwd=store_path, capture_output=True, text=True
317
+ )
318
+
319
+ if result.stdout:
320
+ click.echo(result.stdout)
321
+
322
+ # Show remote
323
+ result = subprocess.run(
324
+ ["git", "remote", "-v"], cwd=store_path, capture_output=True, text=True
325
+ )
326
+
327
+ if result.stdout:
328
+ click.echo("\n🌐 Remotes:")
329
+ click.echo(result.stdout)
330
+ else:
331
+ info("\nNo remote configured")
332
+
333
+ click.echo()
334
+
335
+ except Exception as e:
336
+ error(f"Failed to get status: {e}")
337
+ logger.exception(e)
338
+
339
+
340
+ @store.command(name="config")
341
+ @click.option("--remote", "-r", help="Set git remote URL")
342
+ @click.option("--path", "-p", type=click.Path(), help="Change store path")
343
+ def configure_store(remote, path):
344
+ """Configure store settings"""
345
+ try:
346
+ store_path = _get_store_path()
347
+
348
+ if path:
349
+ new_path = Path(path).expanduser().resolve()
350
+ config_file = Path.home() / ".mcli" / "store.conf"
351
+ config_file.write_text(str(new_path))
352
+ success(f"Store path updated to: {new_path}")
353
+ return
354
+
355
+ if remote:
356
+ # Check if remote exists
357
+ result = subprocess.run(
358
+ ["git", "remote"], cwd=store_path, capture_output=True, text=True
359
+ )
360
+
361
+ if "origin" in result.stdout:
362
+ subprocess.run(
363
+ ["git", "remote", "set-url", "origin", remote], cwd=store_path, check=True
364
+ )
365
+ success(f"Updated remote URL: {remote}")
366
+ else:
367
+ subprocess.run(
368
+ ["git", "remote", "add", "origin", remote], cwd=store_path, check=True
369
+ )
370
+ success(f"Added remote URL: {remote}")
371
+
372
+ except Exception as e:
373
+ error(f"Configuration failed: {e}")
374
+ logger.exception(e)
375
+
376
+
377
+ @store.command(name="list")
378
+ @click.option("--store-dir", "-s", is_flag=True, help="List store instead of local")
379
+ def list_commands(store_dir):
380
+ """List all commands"""
381
+ try:
382
+ if store_dir:
383
+ store_path = _get_store_path()
384
+ path = store_path
385
+ title = f"Commands in store ({store_path})"
386
+ else:
387
+ path = COMMANDS_PATH
388
+ title = f"Local commands ({COMMANDS_PATH})"
389
+
390
+ click.echo(f"\n{title}:\n")
391
+
392
+ if not path.exists():
393
+ warning(f"Directory does not exist: {path}")
394
+ return
395
+
396
+ items = sorted(path.glob("*"))
397
+ if not items:
398
+ info("No commands found")
399
+ return
400
+
401
+ for item in items:
402
+ if item.name in [".git", ".gitignore", "README.md"]:
403
+ continue
404
+
405
+ if item.is_file():
406
+ size = item.stat().st_size / 1024
407
+ modified = datetime.fromtimestamp(item.stat().st_mtime).strftime("%Y-%m-%d %H:%M")
408
+ click.echo(f" 📄 {item.name:<40} {size:>8.1f} KB {modified}")
409
+ elif item.is_dir():
410
+ count = len(list(item.glob("*")))
411
+ click.echo(f" 📁 {item.name:<40} {count:>3} files")
412
+
413
+ click.echo()
414
+
415
+ except Exception as e:
416
+ error(f"Failed to list commands: {e}")
417
+ logger.exception(e)
418
+
419
+
420
+ @store.command(name="show")
421
+ @click.argument("command_name")
422
+ @click.option("--store-dir", "-s", is_flag=True, help="Show from store instead of local")
423
+ def show_command(command_name, store_dir):
424
+ """Show command file contents"""
425
+ try:
426
+ if store_dir:
427
+ store_path = _get_store_path()
428
+ path = store_path / command_name
429
+ else:
430
+ path = COMMANDS_PATH / command_name
431
+
432
+ if not path.exists():
433
+ error(f"Command not found: {command_name}")
434
+ return
435
+
436
+ if path.is_file():
437
+ click.echo(f"\n📄 {path}:\n")
438
+ click.echo(path.read_text())
439
+ else:
440
+ info(f"{command_name} is a directory")
441
+ for item in sorted(path.glob("*")):
442
+ click.echo(f" {item.name}")
443
+
444
+ click.echo()
445
+
446
+ except Exception as e:
447
+ error(f"Failed to show command: {e}")
448
+ logger.exception(e)
@@ -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 *
@@ -21,9 +21,9 @@ import click
21
21
  from mcli.lib.logger.logger import get_logger, register_subprocess
22
22
  from mcli.lib.paths import (
23
23
  get_custom_commands_dir,
24
+ get_git_root,
24
25
  get_lockfile_path,
25
26
  is_git_repository,
26
- get_git_root,
27
27
  )
28
28
 
29
29
  logger = get_logger()
@@ -131,7 +131,7 @@ class CustomCommandManager:
131
131
  List of command data dictionaries
132
132
  """
133
133
  commands = []
134
- include_test = os.environ.get('MCLI_INCLUDE_TEST_COMMANDS', 'false').lower() == 'true'
134
+ include_test = os.environ.get("MCLI_INCLUDE_TEST_COMMANDS", "false").lower() == "true"
135
135
 
136
136
  for command_file in self.commands_dir.glob("*.json"):
137
137
  # Skip the lockfile
@@ -139,7 +139,7 @@ class CustomCommandManager:
139
139
  continue
140
140
 
141
141
  # Skip test commands unless explicitly included
142
- if not include_test and command_file.stem.startswith(('test_', 'test-')):
142
+ if not include_test and command_file.stem.startswith(("test_", "test-")):
143
143
  logger.debug(f"Skipping test command: {command_file.name}")
144
144
  continue
145
145
 
@@ -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 *
@@ -0,0 +1,3 @@
1
+ from .logger import get_logger
2
+
3
+ __all__ = ["get_logger"]
mcli/lib/optional_deps.py CHANGED
@@ -219,9 +219,7 @@ def check_dependencies(*module_names: str) -> Dict[str, bool]:
219
219
  >>> print(status)
220
220
  {'torch': True, 'transformers': False, 'streamlit': True}
221
221
  """
222
- return {
223
- name: OptionalDependency(name).available for name in module_names
224
- }
222
+ return {name: OptionalDependency(name).available for name in module_names}
225
223
 
226
224
 
227
225
  # Pre-register common optional dependencies