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,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
|
+
]
|