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.

Files changed (186) hide show
  1. mcli/app/chat_cmd.py +42 -0
  2. mcli/app/commands_cmd.py +226 -0
  3. mcli/app/completion_cmd.py +216 -0
  4. mcli/app/completion_helpers.py +288 -0
  5. mcli/app/cron_test_cmd.py +697 -0
  6. mcli/app/logs_cmd.py +419 -0
  7. mcli/app/main.py +492 -0
  8. mcli/app/model/model.py +1060 -0
  9. mcli/app/model_cmd.py +227 -0
  10. mcli/app/redis_cmd.py +269 -0
  11. mcli/app/video/video.py +1114 -0
  12. mcli/app/visual_cmd.py +303 -0
  13. mcli/chat/chat.py +2409 -0
  14. mcli/chat/command_rag.py +514 -0
  15. mcli/chat/enhanced_chat.py +652 -0
  16. mcli/chat/system_controller.py +1010 -0
  17. mcli/chat/system_integration.py +1016 -0
  18. mcli/cli.py +25 -0
  19. mcli/config.toml +20 -0
  20. mcli/lib/api/api.py +586 -0
  21. mcli/lib/api/daemon_client.py +203 -0
  22. mcli/lib/api/daemon_client_local.py +44 -0
  23. mcli/lib/api/daemon_decorator.py +217 -0
  24. mcli/lib/api/mcli_decorators.py +1032 -0
  25. mcli/lib/auth/auth.py +85 -0
  26. mcli/lib/auth/aws_manager.py +85 -0
  27. mcli/lib/auth/azure_manager.py +91 -0
  28. mcli/lib/auth/credential_manager.py +192 -0
  29. mcli/lib/auth/gcp_manager.py +93 -0
  30. mcli/lib/auth/key_manager.py +117 -0
  31. mcli/lib/auth/mcli_manager.py +93 -0
  32. mcli/lib/auth/token_manager.py +75 -0
  33. mcli/lib/auth/token_util.py +1011 -0
  34. mcli/lib/config/config.py +47 -0
  35. mcli/lib/discovery/__init__.py +1 -0
  36. mcli/lib/discovery/command_discovery.py +274 -0
  37. mcli/lib/erd/erd.py +1345 -0
  38. mcli/lib/erd/generate_graph.py +453 -0
  39. mcli/lib/files/files.py +76 -0
  40. mcli/lib/fs/fs.py +109 -0
  41. mcli/lib/lib.py +29 -0
  42. mcli/lib/logger/logger.py +611 -0
  43. mcli/lib/performance/optimizer.py +409 -0
  44. mcli/lib/performance/rust_bridge.py +502 -0
  45. mcli/lib/performance/uvloop_config.py +154 -0
  46. mcli/lib/pickles/pickles.py +50 -0
  47. mcli/lib/search/cached_vectorizer.py +479 -0
  48. mcli/lib/services/data_pipeline.py +460 -0
  49. mcli/lib/services/lsh_client.py +441 -0
  50. mcli/lib/services/redis_service.py +387 -0
  51. mcli/lib/shell/shell.py +137 -0
  52. mcli/lib/toml/toml.py +33 -0
  53. mcli/lib/ui/styling.py +47 -0
  54. mcli/lib/ui/visual_effects.py +634 -0
  55. mcli/lib/watcher/watcher.py +185 -0
  56. mcli/ml/api/app.py +215 -0
  57. mcli/ml/api/middleware.py +224 -0
  58. mcli/ml/api/routers/admin_router.py +12 -0
  59. mcli/ml/api/routers/auth_router.py +244 -0
  60. mcli/ml/api/routers/backtest_router.py +12 -0
  61. mcli/ml/api/routers/data_router.py +12 -0
  62. mcli/ml/api/routers/model_router.py +302 -0
  63. mcli/ml/api/routers/monitoring_router.py +12 -0
  64. mcli/ml/api/routers/portfolio_router.py +12 -0
  65. mcli/ml/api/routers/prediction_router.py +267 -0
  66. mcli/ml/api/routers/trade_router.py +12 -0
  67. mcli/ml/api/routers/websocket_router.py +76 -0
  68. mcli/ml/api/schemas.py +64 -0
  69. mcli/ml/auth/auth_manager.py +425 -0
  70. mcli/ml/auth/models.py +154 -0
  71. mcli/ml/auth/permissions.py +302 -0
  72. mcli/ml/backtesting/backtest_engine.py +502 -0
  73. mcli/ml/backtesting/performance_metrics.py +393 -0
  74. mcli/ml/cache.py +400 -0
  75. mcli/ml/cli/main.py +398 -0
  76. mcli/ml/config/settings.py +394 -0
  77. mcli/ml/configs/dvc_config.py +230 -0
  78. mcli/ml/configs/mlflow_config.py +131 -0
  79. mcli/ml/configs/mlops_manager.py +293 -0
  80. mcli/ml/dashboard/app.py +532 -0
  81. mcli/ml/dashboard/app_integrated.py +738 -0
  82. mcli/ml/dashboard/app_supabase.py +560 -0
  83. mcli/ml/dashboard/app_training.py +615 -0
  84. mcli/ml/dashboard/cli.py +51 -0
  85. mcli/ml/data_ingestion/api_connectors.py +501 -0
  86. mcli/ml/data_ingestion/data_pipeline.py +567 -0
  87. mcli/ml/data_ingestion/stream_processor.py +512 -0
  88. mcli/ml/database/migrations/env.py +94 -0
  89. mcli/ml/database/models.py +667 -0
  90. mcli/ml/database/session.py +200 -0
  91. mcli/ml/experimentation/ab_testing.py +845 -0
  92. mcli/ml/features/ensemble_features.py +607 -0
  93. mcli/ml/features/political_features.py +676 -0
  94. mcli/ml/features/recommendation_engine.py +809 -0
  95. mcli/ml/features/stock_features.py +573 -0
  96. mcli/ml/features/test_feature_engineering.py +346 -0
  97. mcli/ml/logging.py +85 -0
  98. mcli/ml/mlops/data_versioning.py +518 -0
  99. mcli/ml/mlops/experiment_tracker.py +377 -0
  100. mcli/ml/mlops/model_serving.py +481 -0
  101. mcli/ml/mlops/pipeline_orchestrator.py +614 -0
  102. mcli/ml/models/base_models.py +324 -0
  103. mcli/ml/models/ensemble_models.py +675 -0
  104. mcli/ml/models/recommendation_models.py +474 -0
  105. mcli/ml/models/test_models.py +487 -0
  106. mcli/ml/monitoring/drift_detection.py +676 -0
  107. mcli/ml/monitoring/metrics.py +45 -0
  108. mcli/ml/optimization/portfolio_optimizer.py +834 -0
  109. mcli/ml/preprocessing/data_cleaners.py +451 -0
  110. mcli/ml/preprocessing/feature_extractors.py +491 -0
  111. mcli/ml/preprocessing/ml_pipeline.py +382 -0
  112. mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
  113. mcli/ml/preprocessing/test_preprocessing.py +294 -0
  114. mcli/ml/scripts/populate_sample_data.py +200 -0
  115. mcli/ml/tasks.py +400 -0
  116. mcli/ml/tests/test_integration.py +429 -0
  117. mcli/ml/tests/test_training_dashboard.py +387 -0
  118. mcli/public/oi/oi.py +15 -0
  119. mcli/public/public.py +4 -0
  120. mcli/self/self_cmd.py +1246 -0
  121. mcli/workflow/daemon/api_daemon.py +800 -0
  122. mcli/workflow/daemon/async_command_database.py +681 -0
  123. mcli/workflow/daemon/async_process_manager.py +591 -0
  124. mcli/workflow/daemon/client.py +530 -0
  125. mcli/workflow/daemon/commands.py +1196 -0
  126. mcli/workflow/daemon/daemon.py +905 -0
  127. mcli/workflow/daemon/daemon_api.py +59 -0
  128. mcli/workflow/daemon/enhanced_daemon.py +571 -0
  129. mcli/workflow/daemon/process_cli.py +244 -0
  130. mcli/workflow/daemon/process_manager.py +439 -0
  131. mcli/workflow/daemon/test_daemon.py +275 -0
  132. mcli/workflow/dashboard/dashboard_cmd.py +113 -0
  133. mcli/workflow/docker/docker.py +0 -0
  134. mcli/workflow/file/file.py +100 -0
  135. mcli/workflow/gcloud/config.toml +21 -0
  136. mcli/workflow/gcloud/gcloud.py +58 -0
  137. mcli/workflow/git_commit/ai_service.py +328 -0
  138. mcli/workflow/git_commit/commands.py +430 -0
  139. mcli/workflow/lsh_integration.py +355 -0
  140. mcli/workflow/model_service/client.py +594 -0
  141. mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
  142. mcli/workflow/model_service/lightweight_embedder.py +397 -0
  143. mcli/workflow/model_service/lightweight_model_server.py +714 -0
  144. mcli/workflow/model_service/lightweight_test.py +241 -0
  145. mcli/workflow/model_service/model_service.py +1955 -0
  146. mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
  147. mcli/workflow/model_service/pdf_processor.py +386 -0
  148. mcli/workflow/model_service/test_efficient_runner.py +234 -0
  149. mcli/workflow/model_service/test_example.py +315 -0
  150. mcli/workflow/model_service/test_integration.py +131 -0
  151. mcli/workflow/model_service/test_new_features.py +149 -0
  152. mcli/workflow/openai/openai.py +99 -0
  153. mcli/workflow/politician_trading/commands.py +1790 -0
  154. mcli/workflow/politician_trading/config.py +134 -0
  155. mcli/workflow/politician_trading/connectivity.py +490 -0
  156. mcli/workflow/politician_trading/data_sources.py +395 -0
  157. mcli/workflow/politician_trading/database.py +410 -0
  158. mcli/workflow/politician_trading/demo.py +248 -0
  159. mcli/workflow/politician_trading/models.py +165 -0
  160. mcli/workflow/politician_trading/monitoring.py +413 -0
  161. mcli/workflow/politician_trading/scrapers.py +966 -0
  162. mcli/workflow/politician_trading/scrapers_california.py +412 -0
  163. mcli/workflow/politician_trading/scrapers_eu.py +377 -0
  164. mcli/workflow/politician_trading/scrapers_uk.py +350 -0
  165. mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
  166. mcli/workflow/politician_trading/supabase_functions.py +354 -0
  167. mcli/workflow/politician_trading/workflow.py +852 -0
  168. mcli/workflow/registry/registry.py +180 -0
  169. mcli/workflow/repo/repo.py +223 -0
  170. mcli/workflow/scheduler/commands.py +493 -0
  171. mcli/workflow/scheduler/cron_parser.py +238 -0
  172. mcli/workflow/scheduler/job.py +182 -0
  173. mcli/workflow/scheduler/monitor.py +139 -0
  174. mcli/workflow/scheduler/persistence.py +324 -0
  175. mcli/workflow/scheduler/scheduler.py +679 -0
  176. mcli/workflow/sync/sync_cmd.py +437 -0
  177. mcli/workflow/sync/test_cmd.py +314 -0
  178. mcli/workflow/videos/videos.py +242 -0
  179. mcli/workflow/wakatime/wakatime.py +11 -0
  180. mcli/workflow/workflow.py +37 -0
  181. mcli_framework-7.0.0.dist-info/METADATA +479 -0
  182. mcli_framework-7.0.0.dist-info/RECORD +186 -0
  183. mcli_framework-7.0.0.dist-info/WHEEL +5 -0
  184. mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
  185. mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
  186. mcli_framework-7.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1032 @@
1
+ """
2
+ MCLI Decorators - Complete Click Superset with Built-in API and Background Processing
3
+
4
+ This module provides decorators that completely subsume Click functionality,
5
+ adding API endpoints and background processing capabilities while maintaining
6
+ the familiar Click interface. Users only need to import mcli and get everything.
7
+ """
8
+
9
+ import functools
10
+ import inspect
11
+ import os
12
+ import time
13
+ from pathlib import Path
14
+ from typing import Any, Callable, Dict, List, Optional, Union
15
+
16
+ import click
17
+
18
+ from mcli.lib.logger.logger import get_logger
19
+ from mcli.lib.toml.toml import read_from_toml
20
+
21
+ from .api import api_endpoint as _api_endpoint
22
+ from .api import get_api_app, start_api_server, stop_api_server
23
+ from .daemon_decorator import daemon_command as _daemon_command
24
+ from .daemon_decorator import is_daemon_available
25
+
26
+ logger = get_logger(__name__)
27
+
28
+ # =============================================================================
29
+ # Complete Click Superset Decorators
30
+ # =============================================================================
31
+
32
+
33
+ def command(
34
+ name: Optional[str] = None,
35
+ cls: Optional[type] = None,
36
+ help: Optional[str] = None,
37
+ epilog: Optional[str] = None,
38
+ short_help: Optional[str] = None,
39
+ options_metavar: Optional[str] = None,
40
+ add_help_option: bool = True,
41
+ no_args_is_help: bool = False,
42
+ hidden: bool = False,
43
+ deprecated: bool = False,
44
+ # MCLI extensions
45
+ api_endpoint: Optional[str] = None,
46
+ api_method: str = "POST",
47
+ api_description: Optional[str] = None,
48
+ api_tags: Optional[List[str]] = None,
49
+ background: bool = False,
50
+ background_timeout: Optional[int] = None,
51
+ **kwargs,
52
+ ):
53
+ """
54
+ Complete Click command decorator with built-in API and background processing.
55
+
56
+ This decorator completely subsumes Click's @command decorator. All Click
57
+ parameters work exactly as expected, with additional MCLI capabilities.
58
+
59
+ Args:
60
+ # Standard Click parameters (all work exactly as in Click)
61
+ name: Command name
62
+ cls: Command class
63
+ help: Help text
64
+ epilog: Epilog text
65
+ short_help: Short help text
66
+ options_metavar: Options metavar
67
+ add_help_option: Add help option
68
+ no_args_is_help: Show help if no args
69
+ hidden: Hide from help
70
+ deprecated: Mark as deprecated
71
+
72
+ # MCLI extensions (optional)
73
+ api_endpoint: API endpoint path (enables API endpoint)
74
+ api_method: HTTP method for API endpoint
75
+ api_description: API documentation description
76
+ api_tags: OpenAPI tags for API endpoint
77
+ background: Enable background processing
78
+ background_timeout: Background processing timeout
79
+
80
+ Example:
81
+ # Standard Click command (works exactly as before)
82
+ @mcli.command()
83
+ def greet(name: str):
84
+ return f"Hello, {name}!"
85
+
86
+ # Click command with API endpoint
87
+ @mcli.command(api_endpoint="/greet", api_method="POST")
88
+ def greet(name: str):
89
+ return {"message": f"Hello, {name}!"}
90
+
91
+ # Click command with background processing
92
+ @mcli.command(background=True, background_timeout=60)
93
+ def process_file(file_path: str):
94
+ return {"processed": file_path}
95
+
96
+ # Click command with both API and background
97
+ @mcli.command(
98
+ api_endpoint="/process",
99
+ api_method="POST",
100
+ background=True,
101
+ background_timeout=300
102
+ )
103
+ def process_file(file_path: str):
104
+ return {"processed": file_path}
105
+ """
106
+
107
+ def decorator(func: Callable) -> Callable:
108
+ # Import Click here to avoid circular imports
109
+ import click
110
+
111
+ # Filter out MCLI-specific parameters for Click
112
+ click_kwargs = {
113
+ "name": name,
114
+ "cls": cls,
115
+ "help": help,
116
+ "epilog": epilog,
117
+ "short_help": short_help,
118
+ "options_metavar": options_metavar,
119
+ "add_help_option": add_help_option,
120
+ "no_args_is_help": no_args_is_help,
121
+ "hidden": hidden,
122
+ "deprecated": deprecated,
123
+ }
124
+
125
+ # Add any other Click parameters
126
+ click_kwargs.update(kwargs)
127
+
128
+ # Create the Click command with all standard parameters
129
+ click_command = click.command(**click_kwargs)(func)
130
+
131
+ # Apply API endpoint if specified
132
+ if api_endpoint:
133
+ click_command = _api_endpoint(
134
+ endpoint_path=api_endpoint,
135
+ http_method=api_method,
136
+ description=api_description or help or f"API endpoint for {func.__name__}",
137
+ tags=api_tags or ["mcli"],
138
+ )(click_command)
139
+
140
+ # Apply background processing if enabled
141
+ if background:
142
+ click_command = _daemon_command(
143
+ command_name=name or func.__name__,
144
+ auto_route=True,
145
+ fallback_to_local=True,
146
+ timeout=background_timeout,
147
+ )(click_command)
148
+
149
+ return click_command
150
+
151
+ return decorator
152
+
153
+
154
+ def group(
155
+ name: Optional[str] = None,
156
+ commands: Optional[Union[Dict[str, Callable], List[Callable]]] = None,
157
+ order: Optional[List[str]] = None,
158
+ help: Optional[str] = None,
159
+ epilog: Optional[str] = None,
160
+ short_help: Optional[str] = None,
161
+ options_metavar: Optional[str] = None,
162
+ add_help_option: bool = True,
163
+ no_args_is_help: bool = False,
164
+ hidden: bool = False,
165
+ deprecated: bool = False,
166
+ # MCLI extensions
167
+ api_base_path: Optional[str] = None,
168
+ api_description: Optional[str] = None,
169
+ api_tags: Optional[List[str]] = None,
170
+ **kwargs,
171
+ ):
172
+ """
173
+ Complete Click group decorator with built-in API capabilities.
174
+
175
+ This decorator completely subsumes Click's @group decorator. All Click
176
+ parameters work exactly as expected, with additional MCLI capabilities.
177
+
178
+ Args:
179
+ # Standard Click parameters (all work exactly as in Click)
180
+ name: Group name
181
+ commands: Commands dictionary or list
182
+ order: Command order
183
+ help: Help text
184
+ epilog: Epilog text
185
+ short_help: Short help text
186
+ options_metavar: Options metavar
187
+ add_help_option: Add help option
188
+ no_args_is_help: Show help if no args
189
+ hidden: Hide from help
190
+ deprecated: Mark as deprecated
191
+
192
+ # MCLI extensions (optional)
193
+ api_base_path: Base path for API endpoints in this group
194
+ api_description: API documentation description
195
+ api_tags: OpenAPI tags for API endpoints
196
+
197
+ Example:
198
+ # Standard Click group (works exactly as before)
199
+ @mcli.group()
200
+ def mycli():
201
+ pass
202
+
203
+ # Click group with API base path
204
+ @mcli.group(api_base_path="/api/v1")
205
+ def mycli():
206
+ pass
207
+ """
208
+
209
+ def decorator(func: Callable) -> Callable:
210
+ # Import Click here to avoid circular imports
211
+ import click
212
+
213
+ # Filter out MCLI-specific parameters for Click
214
+ click_kwargs = {
215
+ "name": name,
216
+ "help": help,
217
+ "epilog": epilog,
218
+ "short_help": short_help,
219
+ "options_metavar": options_metavar,
220
+ "add_help_option": add_help_option,
221
+ "no_args_is_help": no_args_is_help,
222
+ "hidden": hidden,
223
+ "deprecated": deprecated,
224
+ }
225
+
226
+ # Add commands if provided
227
+ if commands is not None:
228
+ click_kwargs["commands"] = commands
229
+
230
+ # Add order if provided
231
+ if order is not None:
232
+ click_kwargs["order"] = order
233
+
234
+ # Add any other Click parameters
235
+ click_kwargs.update(kwargs)
236
+
237
+ # Create the Click group with all standard parameters
238
+ click_group = click.group(**click_kwargs)(func)
239
+
240
+ # Store API configuration for child commands
241
+ if api_base_path:
242
+ click_group.api_base_path = api_base_path
243
+ click_group.api_description = api_description
244
+ click_group.api_tags = api_tags
245
+
246
+ return click_group
247
+
248
+ return decorator
249
+
250
+
251
+ # =============================================================================
252
+ # Re-export Click functionality for complete subsume
253
+ # =============================================================================
254
+
255
+
256
+ def option(*param_decls, **attrs):
257
+ """
258
+ Re-export Click's option decorator.
259
+
260
+ This allows users to use @mcli.option instead of @click.option.
261
+ """
262
+ import click
263
+
264
+ return click.option(*param_decls, **attrs)
265
+
266
+
267
+ def argument(*param_decls, **attrs):
268
+ """
269
+ Re-export Click's argument decorator.
270
+
271
+ This allows users to use @mcli.argument instead of @click.argument.
272
+ """
273
+ import click
274
+
275
+ return click.argument(*param_decls, **attrs)
276
+
277
+
278
+ def echo(message=None, file=None, nl=True, err=False, color=None):
279
+ """
280
+ Re-export Click's echo function.
281
+
282
+ This allows users to use mcli.echo instead of click.echo.
283
+ """
284
+ import click
285
+
286
+ return click.echo(message, file, nl, err, color)
287
+
288
+
289
+ def get_current_context():
290
+ """
291
+ Re-export Click's get_current_context function.
292
+
293
+ This allows users to use mcli.get_current_context instead of click.get_current_context.
294
+ """
295
+ import click
296
+
297
+ return click.get_current_context()
298
+
299
+
300
+ def get_app():
301
+ """
302
+ Re-export Click's get_app function.
303
+
304
+ This allows users to use mcli.get_app instead of click.get_app.
305
+ """
306
+ import click
307
+
308
+ return click.get_app
309
+
310
+
311
+ def launch(url, wait=False, locate=False):
312
+ """
313
+ Re-export Click's launch function.
314
+
315
+ This allows users to use mcli.launch instead of click.launch.
316
+ """
317
+ import click
318
+
319
+ return click.launch(url, wait, locate)
320
+
321
+
322
+ def open_file(filename, mode="r", encoding=None, errors="strict", lazy=False, atomic=False):
323
+ """
324
+ Re-export Click's open_file function.
325
+
326
+ This allows users to use mcli.open_file instead of click.open_file.
327
+ """
328
+ import click
329
+
330
+ return click.open_file(filename, mode, encoding, errors, lazy, atomic)
331
+
332
+
333
+ def get_os_args():
334
+ """
335
+ Re-export Click's get_os_args object.
336
+
337
+ This allows users to use mcli.get_os_args instead of click.get_os_args.
338
+ """
339
+ import click
340
+
341
+ return click.get_os_args
342
+
343
+
344
+ def get_binary_stream(name):
345
+ """
346
+ Re-export Click's get_binary_stream function.
347
+
348
+ This allows users to use mcli.get_binary_stream instead of click.get_binary_stream.
349
+ """
350
+ import click
351
+
352
+ return click.get_binary_stream(name)
353
+
354
+
355
+ def get_text_stream(name, encoding=None, errors="strict"):
356
+ """
357
+ Re-export Click's get_text_stream function.
358
+
359
+ This allows users to use mcli.get_text_stream instead of click.get_text_stream.
360
+ """
361
+ import click
362
+
363
+ return click.get_text_stream(name, encoding, errors)
364
+
365
+
366
+ def format_filename(filename):
367
+ """
368
+ Re-export Click's format_filename function.
369
+
370
+ This allows users to use mcli.format_filename instead of click.format_filename.
371
+ """
372
+ import click
373
+
374
+ return click.format_filename(filename)
375
+
376
+
377
+ def getchar(echo=False):
378
+ """
379
+ Re-export Click's getchar function.
380
+
381
+ This allows users to use mcli.getchar instead of click.getchar.
382
+ """
383
+ import click
384
+
385
+ return click.getchar(echo)
386
+
387
+
388
+ def pause(info="Press any key to continue ...", err=False):
389
+ """
390
+ Re-export Click's pause function.
391
+
392
+ This allows users to use mcli.pause instead of click.pause.
393
+ """
394
+ import click
395
+
396
+ return click.pause(info, err)
397
+
398
+
399
+ def clear():
400
+ """
401
+ Re-export Click's clear function.
402
+
403
+ This allows users to use mcli.clear instead of click.clear.
404
+ """
405
+ import click
406
+
407
+ return click.clear()
408
+
409
+
410
+ def style(
411
+ text,
412
+ fg=None,
413
+ bg=None,
414
+ bold=None,
415
+ dim=None,
416
+ underline=None,
417
+ overline=None,
418
+ italic=None,
419
+ blink=None,
420
+ reverse=None,
421
+ strikethrough=None,
422
+ reset=True,
423
+ ):
424
+ """
425
+ Re-export Click's style function.
426
+
427
+ This allows users to use mcli.style instead of click.style.
428
+ """
429
+ import click
430
+
431
+ return click.style(
432
+ text, fg, bg, bold, dim, underline, overline, italic, blink, reverse, strikethrough, reset
433
+ )
434
+
435
+
436
+ def unstyle(text):
437
+ """
438
+ Re-export Click's unstyle function.
439
+
440
+ This allows users to use mcli.unstyle instead of click.unstyle.
441
+ """
442
+ import click
443
+
444
+ return click.unstyle(text)
445
+
446
+
447
+ def secho(message=None, file=None, nl=True, err=False, color=None, **styles):
448
+ """
449
+ Re-export Click's secho function.
450
+
451
+ This allows users to use mcli.secho instead of click.secho.
452
+ """
453
+ import click
454
+
455
+ return click.secho(message, file, nl, err, color, **styles)
456
+
457
+
458
+ def edit(
459
+ filename=None, editor=None, env=None, require_save=True, extension=".txt", filename_pattern=None
460
+ ):
461
+ """
462
+ Re-export Click's edit function.
463
+
464
+ This allows users to use mcli.edit instead of click.edit.
465
+ """
466
+ import click
467
+
468
+ return click.edit(filename, editor, env, require_save, extension, filename_pattern)
469
+
470
+
471
+ def confirm(text, default=False, abort=False, prompt_suffix=": ", show_default=True, err=False):
472
+ """
473
+ Re-export Click's confirm function.
474
+
475
+ This allows users to use mcli.confirm instead of click.confirm.
476
+ """
477
+ import click
478
+
479
+ return click.confirm(text, default, abort, prompt_suffix, show_default, err)
480
+
481
+
482
+ def prompt(
483
+ text,
484
+ default=None,
485
+ hide_input=False,
486
+ confirmation_prompt=False,
487
+ type=None,
488
+ value_proc=None,
489
+ prompt_suffix=": ",
490
+ show_default=True,
491
+ err=False,
492
+ show_choices=True,
493
+ ):
494
+ """
495
+ Re-export Click's prompt function.
496
+
497
+ This allows users to use mcli.prompt instead of click.prompt.
498
+ """
499
+ import click
500
+
501
+ return click.prompt(
502
+ text,
503
+ default,
504
+ hide_input,
505
+ confirmation_prompt,
506
+ type,
507
+ value_proc,
508
+ prompt_suffix,
509
+ show_default,
510
+ err,
511
+ show_choices,
512
+ )
513
+
514
+
515
+ def progressbar(
516
+ iterable=None,
517
+ length=None,
518
+ label=None,
519
+ show_eta=True,
520
+ show_percent=True,
521
+ show_pos=False,
522
+ item_show_func=None,
523
+ fill_char="#",
524
+ empty_char="-",
525
+ bar_template="%(label)s [%(bar)s] %(info)s",
526
+ info_sep=" ",
527
+ width=36,
528
+ file=None,
529
+ color=None,
530
+ ):
531
+ """
532
+ Re-export Click's progressbar function.
533
+
534
+ This allows users to use mcli.progressbar instead of click.progressbar.
535
+ """
536
+ import click
537
+
538
+ # Ensure show_eta is always a bool (default True if None)
539
+ show_eta_bool = True if show_eta is None else bool(show_eta)
540
+ return click.progressbar(
541
+ iterable=iterable,
542
+ length=length,
543
+ label=label,
544
+ show_eta=show_eta_bool,
545
+ show_percent=show_percent,
546
+ show_pos=show_pos,
547
+ item_show_func=item_show_func,
548
+ fill_char=fill_char,
549
+ empty_char=empty_char,
550
+ bar_template=bar_template,
551
+ info_sep=info_sep,
552
+ width=width,
553
+ file=file,
554
+ color=color,
555
+ )
556
+
557
+
558
+ def get_terminal_size():
559
+ """
560
+ Re-export Click's get_terminal_size function.
561
+
562
+ This allows users to use mcli.get_terminal_size instead of click.get_terminal_size.
563
+ """
564
+ import click
565
+
566
+ return click.get_terminal_size
567
+
568
+
569
+ def get_app_dir(app_name, roaming=True, force_posix=False):
570
+ """
571
+ Re-export Click's get_app_dir function.
572
+
573
+ This allows users to use mcli.get_app_dir instead of click.get_app_dir.
574
+ """
575
+ import click
576
+
577
+ return click.get_app_dir(app_name, roaming, force_posix)
578
+
579
+
580
+ def get_network_credentials():
581
+ """
582
+ Re-export Click's get_network_credentials function.
583
+
584
+ This allows users to use mcli.get_network_credentials instead of click.get_network_credentials.
585
+ """
586
+ import click
587
+
588
+ return click.get_network_credentials
589
+
590
+
591
+ # Re-export Click types and classes
592
+ def _get_click_types():
593
+ """Get Click types for re-export"""
594
+ import click
595
+
596
+ return {
597
+ "Path": click.Path,
598
+ "Choice": click.Choice,
599
+ "IntRange": click.IntRange,
600
+ "FloatRange": click.FloatRange,
601
+ "UNPROCESSED": click.UNPROCESSED,
602
+ "STRING": click.STRING,
603
+ "INT": click.INT,
604
+ "FLOAT": click.FLOAT,
605
+ "BOOL": click.BOOL,
606
+ "UUID": click.UUID,
607
+ "File": click.File,
608
+ "ParamType": click.ParamType,
609
+ "BadParameter": click.BadParameter,
610
+ "UsageError": click.UsageError,
611
+ "Abort": click.Abort,
612
+ }
613
+
614
+
615
+ # Add Click types to the module namespace
616
+ _click_types = _get_click_types()
617
+ globals().update(_click_types)
618
+
619
+ # =============================================================================
620
+ # Convenience Decorators for Common Patterns
621
+ # =============================================================================
622
+
623
+
624
+ def api_command(
625
+ endpoint_path: str,
626
+ http_method: str = "POST",
627
+ description: Optional[str] = None,
628
+ tags: Optional[List[str]] = None,
629
+ background: bool = True,
630
+ background_timeout: Optional[int] = None,
631
+ **click_kwargs,
632
+ ):
633
+ """
634
+ Convenience decorator for Click commands that should be API endpoints.
635
+
636
+ This is equivalent to @mcli.command() with api_endpoint and background=True.
637
+
638
+ Args:
639
+ endpoint_path: API endpoint path
640
+ http_method: HTTP method
641
+ description: API description
642
+ tags: OpenAPI tags
643
+ background: Enable background processing
644
+ background_timeout: Background timeout
645
+ **click_kwargs: All standard Click command parameters
646
+
647
+ Example:
648
+ @mcli.api_command("/greet", "POST", description="Greet someone")
649
+ def greet(name: str):
650
+ return {"message": f"Hello, {name}!"}
651
+ """
652
+ return command(
653
+ api_endpoint=endpoint_path,
654
+ api_method=http_method,
655
+ api_description=description,
656
+ api_tags=tags,
657
+ background=background,
658
+ background_timeout=background_timeout,
659
+ **click_kwargs,
660
+ )
661
+
662
+
663
+ def background_command(timeout: Optional[int] = None, **click_kwargs):
664
+ """
665
+ Convenience decorator for Click commands that should use background processing.
666
+
667
+ This is equivalent to @mcli.command() with background=True.
668
+
669
+ Args:
670
+ timeout: Background processing timeout
671
+ **click_kwargs: All standard Click command parameters
672
+
673
+ Example:
674
+ @mcli.background_command(timeout=300)
675
+ def process_large_file(file_path: str):
676
+ return {"processed": file_path}
677
+ """
678
+ return command(background=True, background_timeout=timeout, **click_kwargs)
679
+
680
+
681
+ # =============================================================================
682
+ # Legacy Support - Keep old names for backward compatibility
683
+ # =============================================================================
684
+
685
+
686
+ def api(
687
+ endpoint_path: Optional[str] = None,
688
+ http_method: str = "POST",
689
+ description: Optional[str] = None,
690
+ tags: Optional[List[str]] = None,
691
+ enable_background: bool = True,
692
+ background_timeout: Optional[int] = None,
693
+ ):
694
+ """
695
+ Legacy decorator - use @mcli.command() with api_endpoint parameter instead.
696
+
697
+ Example:
698
+ # Old way
699
+ @mcli.api("/greet", "POST")
700
+ def greet(name: str):
701
+ return {"message": f"Hello, {name}!"}
702
+
703
+ # New way (recommended)
704
+ @mcli.command(api_endpoint="/greet", api_method="POST")
705
+ def greet(name: str):
706
+ return {"message": f"Hello, {name}!"}
707
+ """
708
+
709
+ def decorator(func: Callable) -> Callable:
710
+ return command(
711
+ api_endpoint=endpoint_path or f"/{func.__name__}",
712
+ api_method=http_method,
713
+ api_description=description,
714
+ api_tags=tags,
715
+ background=enable_background,
716
+ background_timeout=background_timeout,
717
+ )(func)
718
+
719
+ return decorator
720
+
721
+
722
+ def background(
723
+ command_name: Optional[str] = None,
724
+ auto_route: bool = True,
725
+ fallback_to_local: bool = True,
726
+ timeout: Optional[int] = None,
727
+ ):
728
+ """
729
+ Legacy decorator - use @mcli.command() with background=True instead.
730
+
731
+ Example:
732
+ # Old way
733
+ @mcli.background(timeout=300)
734
+ def process_file(file_path: str):
735
+ return {"processed": file_path}
736
+
737
+ # New way (recommended)
738
+ @mcli.command(background=True, background_timeout=300)
739
+ def process_file(file_path: str):
740
+ return {"processed": file_path}
741
+ """
742
+
743
+ def decorator(func: Callable) -> Callable:
744
+ return command(name=command_name, background=True, background_timeout=timeout)(func)
745
+
746
+ return decorator
747
+
748
+
749
+ def cli_with_api(
750
+ endpoint_path: Optional[str] = None,
751
+ http_method: str = "POST",
752
+ description: Optional[str] = None,
753
+ tags: Optional[List[str]] = None,
754
+ enable_background: bool = True,
755
+ background_timeout: Optional[int] = None,
756
+ ):
757
+ """
758
+ Legacy decorator - use @mcli.command() with api_endpoint and background=True instead.
759
+
760
+ Example:
761
+ # Old way
762
+ @mcli.cli_with_api("/process", "POST")
763
+ def process_file(file_path: str):
764
+ return {"processed": file_path}
765
+
766
+ # New way (recommended)
767
+ @mcli.command(api_endpoint="/process", api_method="POST", background=True)
768
+ def process_file(file_path: str):
769
+ return {"processed": file_path}
770
+ """
771
+ return command(
772
+ api_endpoint=endpoint_path,
773
+ api_method=http_method,
774
+ api_description=description,
775
+ api_tags=tags,
776
+ background=enable_background,
777
+ background_timeout=background_timeout,
778
+ )
779
+
780
+
781
+ # =============================================================================
782
+ # Server Management Functions
783
+ # =============================================================================
784
+
785
+
786
+ def start_server(
787
+ host: str = "0.0.0.0", port: Optional[int] = None, debug: bool = False
788
+ ) -> Optional[str]:
789
+ """
790
+ Start the API server for your CLI.
791
+
792
+ Args:
793
+ host: Server host address
794
+ port: Server port (uses random port if None)
795
+ debug: Enable debug mode
796
+
797
+ Returns:
798
+ Server URL if started successfully, None otherwise
799
+
800
+ Example:
801
+ if __name__ == "__main__":
802
+ mcli.start_server(port=8000)
803
+ my_cli()
804
+ """
805
+ try:
806
+ if port is not None:
807
+ server_url = start_api_server(host=host, port=port, debug=debug)
808
+ else:
809
+ server_url = start_api_server(host=host, debug=debug)
810
+ logger.info(f"API server started at: {server_url}")
811
+ return server_url
812
+ except Exception as e:
813
+ logger.error(f"Failed to start API server: {e}")
814
+ return None
815
+
816
+
817
+ def stop_server():
818
+ """
819
+ Stop the API server.
820
+
821
+ Example:
822
+ import atexit
823
+ atexit.register(mcli.stop_server)
824
+ """
825
+ try:
826
+ stop_api_server()
827
+ logger.info("API server stopped")
828
+ except Exception as e:
829
+ logger.error(f"Failed to stop API server: {e}")
830
+
831
+
832
+ def is_server_running() -> bool:
833
+ """
834
+ Check if the API server is running.
835
+
836
+ Returns:
837
+ True if server is running, False otherwise
838
+ """
839
+ try:
840
+ app = get_api_app()
841
+ return app is not None
842
+ except Exception:
843
+ return False
844
+
845
+
846
+ def is_background_available() -> bool:
847
+ """
848
+ Check if background processing service is available.
849
+
850
+ Returns:
851
+ True if background service is available, False otherwise
852
+ """
853
+ return is_daemon_available()
854
+
855
+
856
+ # =============================================================================
857
+ # Configuration Helpers
858
+ # =============================================================================
859
+
860
+
861
+ def get_api_config() -> Dict[str, Any]:
862
+ """
863
+ Get the current API configuration.
864
+
865
+ Returns:
866
+ Dictionary with API configuration settings
867
+ """
868
+ config = {
869
+ "enabled": False,
870
+ "host": "0.0.0.0",
871
+ "port": None,
872
+ "use_random_port": True,
873
+ "debug": False,
874
+ }
875
+
876
+ # Check environment variables
877
+ if os.environ.get("MCLI_API_SERVER", "false").lower() in ("true", "1", "yes"):
878
+ config["enabled"] = True
879
+
880
+ if os.environ.get("MCLI_API_HOST"):
881
+ config["host"] = os.environ.get("MCLI_API_HOST")
882
+
883
+ port_env = os.environ.get("MCLI_API_PORT")
884
+ if port_env is not None:
885
+ config["port"] = int(port_env)
886
+ config["use_random_port"] = False
887
+
888
+ if os.environ.get("MCLI_API_DEBUG", "false").lower() in ("true", "1", "yes"):
889
+ config["debug"] = True
890
+
891
+ return config
892
+
893
+
894
+ def enable_api_server():
895
+ """
896
+ Enable the API server via environment variable.
897
+
898
+ Example:
899
+ mcli.enable_api_server()
900
+ # Now your CLI will start the API server
901
+ """
902
+ os.environ["MCLI_API_SERVER"] = "true"
903
+
904
+
905
+ def disable_api_server():
906
+ """
907
+ Disable the API server via environment variable.
908
+ """
909
+ os.environ["MCLI_API_SERVER"] = "false"
910
+
911
+
912
+ # =============================================================================
913
+ # Convenience Functions for Common Patterns
914
+ # =============================================================================
915
+
916
+
917
+ def health_check():
918
+ """
919
+ Create a health check endpoint.
920
+
921
+ Example:
922
+ @mcli.command(api_endpoint="/health", api_method="GET")
923
+ def health():
924
+ return {"status": "healthy", "timestamp": time.time()}
925
+ """
926
+ import time
927
+
928
+ return {"status": "healthy", "timestamp": time.time()}
929
+
930
+
931
+ def status_check():
932
+ """
933
+ Create a status check endpoint that includes server and background service status.
934
+
935
+ Example:
936
+ @mcli.command(api_endpoint="/status", api_method="GET")
937
+ def status():
938
+ return mcli.status_check()
939
+ """
940
+ return {
941
+ "api_server": "running" if is_server_running() else "not_running",
942
+ "background_service": "available" if is_background_available() else "not_available",
943
+ "timestamp": time.time(),
944
+ }
945
+
946
+
947
+ # =============================================================================
948
+ # Chat Interface
949
+ # =============================================================================
950
+
951
+
952
+ class ChatCommandGroup(click.Group):
953
+ """Special command group that provides chat-based interaction"""
954
+
955
+ def __init__(self, *args, **kwargs):
956
+ super().__init__(*args, **kwargs)
957
+ self.chat_client = None
958
+
959
+ def get_help(self, ctx):
960
+ """Start interactive chat session instead of showing normal help"""
961
+ from mcli.chat.chat import ChatClient
962
+
963
+ self.chat_client = ChatClient()
964
+ self.chat_client.start_interactive_session()
965
+ return ""
966
+
967
+
968
+ from typing import Any, Callable
969
+
970
+
971
+ def chat(**kwargs) -> Callable[[Callable[..., Any]], click.Group]:
972
+ """Create a chat command group that provides an interactive LLM-powered interface"""
973
+ kwargs.setdefault("invoke_without_command", True)
974
+ kwargs.setdefault("no_args_is_help", False)
975
+ return click.group(cls=ChatCommandGroup, **kwargs)
976
+
977
+
978
+ # =============================================================================
979
+ # Export everything for complete Click subsume
980
+ # =============================================================================
981
+
982
+ # Main decorators (complete Click superset)
983
+ __all__ = [
984
+ # Core decorators
985
+ "command", # @mcli.command - Complete Click command with API/background
986
+ "group", # @mcli.group - Complete Click group with API support
987
+ "chat", # @mcli.chat - Interactive command chat interface
988
+ # Click re-exports (complete subsume)
989
+ "option", # @mcli.option - Click option decorator
990
+ "argument", # @mcli.argument - Click argument decorator
991
+ "echo", # mcli.echo - Click echo function
992
+ "get_current_context", # mcli.get_current_context - Click context
993
+ "get_app", # mcli.get_app - Click app
994
+ "launch", # mcli.launch - Click launch
995
+ "open_file", # mcli.open_file - Click file operations
996
+ "get_os_args", # mcli.get_os_args - Click OS args
997
+ "get_binary_stream", # mcli.get_binary_stream - Click binary stream
998
+ "get_text_stream", # mcli.get_text_stream - Click text stream
999
+ "format_filename", # mcli.format_filename - Click filename
1000
+ "getchar", # mcli.getchar - Click character input
1001
+ "pause", # mcli.pause - Click pause
1002
+ "clear", # mcli.clear - Click clear
1003
+ "style", # mcli.style - Click styling
1004
+ "unstyle", # mcli.unstyle - Click unstyle
1005
+ "secho", # mcli.secho - Click styled echo
1006
+ "edit", # mcli.edit - Click editor
1007
+ "confirm", # mcli.confirm - Click confirmation
1008
+ "prompt", # mcli.prompt - Click prompt
1009
+ "progressbar", # mcli.progressbar - Click progress bar
1010
+ "get_terminal_size", # mcli.get_terminal_size - Click terminal size
1011
+ "get_app_dir", # mcli.get_app_dir - Click app directory
1012
+ "get_network_credentials", # mcli.get_network_credentials - Click network
1013
+ # Convenience decorators
1014
+ "api_command", # @mcli.api_command - Convenience for API endpoints
1015
+ "background_command", # @mcli.background_command - Convenience for background
1016
+ # Legacy decorators (for backward compatibility)
1017
+ "api", # @mcli.api - Legacy API decorator
1018
+ "background", # @mcli.background - Legacy background decorator
1019
+ "cli_with_api", # @mcli.cli_with_api - Legacy combined decorator
1020
+ # Server management
1021
+ "start_server",
1022
+ "stop_server",
1023
+ "is_server_running",
1024
+ "is_background_available",
1025
+ # Configuration
1026
+ "get_api_config",
1027
+ "enable_api_server",
1028
+ "disable_api_server",
1029
+ # Convenience functions
1030
+ "health_check",
1031
+ "status_check",
1032
+ ]