mcli-framework 7.1.1__py3-none-any.whl ā 7.1.2__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/completion_cmd.py +59 -49
- mcli/app/completion_helpers.py +60 -138
- mcli/app/logs_cmd.py +6 -2
- mcli/app/main.py +17 -14
- mcli/app/model_cmd.py +19 -4
- mcli/chat/chat.py +3 -2
- mcli/lib/search/cached_vectorizer.py +1 -0
- mcli/lib/services/data_pipeline.py +12 -5
- mcli/lib/services/lsh_client.py +68 -57
- mcli/ml/api/app.py +28 -36
- mcli/ml/api/middleware.py +8 -16
- mcli/ml/api/routers/admin_router.py +3 -1
- mcli/ml/api/routers/auth_router.py +32 -56
- mcli/ml/api/routers/backtest_router.py +3 -1
- mcli/ml/api/routers/data_router.py +3 -1
- mcli/ml/api/routers/model_router.py +35 -74
- mcli/ml/api/routers/monitoring_router.py +3 -1
- mcli/ml/api/routers/portfolio_router.py +3 -1
- mcli/ml/api/routers/prediction_router.py +60 -65
- mcli/ml/api/routers/trade_router.py +6 -2
- mcli/ml/api/routers/websocket_router.py +12 -9
- mcli/ml/api/schemas.py +10 -2
- mcli/ml/auth/auth_manager.py +49 -114
- mcli/ml/auth/models.py +30 -15
- mcli/ml/auth/permissions.py +12 -19
- mcli/ml/backtesting/backtest_engine.py +134 -108
- mcli/ml/backtesting/performance_metrics.py +142 -108
- mcli/ml/cache.py +12 -18
- mcli/ml/cli/main.py +37 -23
- mcli/ml/config/settings.py +29 -12
- mcli/ml/dashboard/app.py +122 -130
- mcli/ml/dashboard/app_integrated.py +216 -150
- mcli/ml/dashboard/app_supabase.py +176 -108
- mcli/ml/dashboard/app_training.py +212 -206
- mcli/ml/dashboard/cli.py +14 -5
- mcli/ml/data_ingestion/api_connectors.py +51 -81
- mcli/ml/data_ingestion/data_pipeline.py +127 -125
- mcli/ml/data_ingestion/stream_processor.py +72 -80
- mcli/ml/database/migrations/env.py +3 -2
- mcli/ml/database/models.py +112 -79
- mcli/ml/database/session.py +6 -5
- mcli/ml/experimentation/ab_testing.py +149 -99
- mcli/ml/features/ensemble_features.py +9 -8
- mcli/ml/features/political_features.py +6 -5
- mcli/ml/features/recommendation_engine.py +15 -14
- mcli/ml/features/stock_features.py +7 -6
- mcli/ml/features/test_feature_engineering.py +8 -7
- mcli/ml/logging.py +10 -15
- mcli/ml/mlops/data_versioning.py +57 -64
- mcli/ml/mlops/experiment_tracker.py +49 -41
- mcli/ml/mlops/model_serving.py +59 -62
- mcli/ml/mlops/pipeline_orchestrator.py +203 -149
- mcli/ml/models/base_models.py +8 -7
- mcli/ml/models/ensemble_models.py +6 -5
- mcli/ml/models/recommendation_models.py +7 -6
- mcli/ml/models/test_models.py +18 -14
- mcli/ml/monitoring/drift_detection.py +95 -74
- mcli/ml/monitoring/metrics.py +10 -22
- mcli/ml/optimization/portfolio_optimizer.py +172 -132
- mcli/ml/predictions/prediction_engine.py +62 -50
- mcli/ml/preprocessing/data_cleaners.py +6 -5
- mcli/ml/preprocessing/feature_extractors.py +7 -6
- mcli/ml/preprocessing/ml_pipeline.py +3 -2
- mcli/ml/preprocessing/politician_trading_preprocessor.py +11 -10
- mcli/ml/preprocessing/test_preprocessing.py +4 -4
- mcli/ml/scripts/populate_sample_data.py +36 -16
- mcli/ml/tasks.py +82 -83
- mcli/ml/tests/test_integration.py +86 -76
- mcli/ml/tests/test_training_dashboard.py +169 -142
- mcli/mygroup/test_cmd.py +2 -1
- mcli/self/self_cmd.py +31 -16
- mcli/self/test_cmd.py +2 -1
- mcli/workflow/dashboard/dashboard_cmd.py +13 -6
- mcli/workflow/lsh_integration.py +46 -58
- mcli/workflow/politician_trading/commands.py +576 -427
- mcli/workflow/politician_trading/config.py +7 -7
- mcli/workflow/politician_trading/connectivity.py +35 -33
- mcli/workflow/politician_trading/data_sources.py +72 -71
- mcli/workflow/politician_trading/database.py +18 -16
- mcli/workflow/politician_trading/demo.py +4 -3
- mcli/workflow/politician_trading/models.py +5 -5
- mcli/workflow/politician_trading/monitoring.py +13 -13
- mcli/workflow/politician_trading/scrapers.py +332 -224
- mcli/workflow/politician_trading/scrapers_california.py +116 -94
- mcli/workflow/politician_trading/scrapers_eu.py +70 -71
- mcli/workflow/politician_trading/scrapers_uk.py +118 -90
- mcli/workflow/politician_trading/scrapers_us_states.py +125 -92
- mcli/workflow/politician_trading/workflow.py +98 -71
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/METADATA +1 -1
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/RECORD +94 -94
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/WHEEL +0 -0
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/entry_points.txt +0 -0
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/licenses/LICENSE +0 -0
- {mcli_framework-7.1.1.dist-info ā mcli_framework-7.1.2.dist-info}/top_level.txt +0 -0
mcli/app/completion_cmd.py
CHANGED
|
@@ -6,8 +6,10 @@ for bash, zsh, and fish shells.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import os
|
|
9
|
-
import click
|
|
10
9
|
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
11
13
|
from mcli.lib.ui.styling import success
|
|
12
14
|
|
|
13
15
|
|
|
@@ -22,29 +24,29 @@ def completion():
|
|
|
22
24
|
def bash_completion(ctx):
|
|
23
25
|
"""Generate bash completion script"""
|
|
24
26
|
from click.shell_completion import BashComplete
|
|
25
|
-
|
|
27
|
+
|
|
26
28
|
# Get the root CLI app
|
|
27
29
|
app = ctx.find_root().command
|
|
28
30
|
complete = BashComplete(app, {}, "mcli", "complete")
|
|
29
31
|
script = complete.source()
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
click.echo("# Bash completion script for MCLI")
|
|
32
34
|
click.echo("# Add this to your ~/.bashrc or ~/.bash_profile:")
|
|
33
35
|
click.echo()
|
|
34
36
|
click.echo(script)
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
@completion.command(name="zsh")
|
|
39
|
+
@completion.command(name="zsh")
|
|
38
40
|
@click.pass_context
|
|
39
41
|
def zsh_completion(ctx):
|
|
40
42
|
"""Generate zsh completion script"""
|
|
41
43
|
from click.shell_completion import ZshComplete
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
# Get the root CLI app
|
|
44
46
|
app = ctx.find_root().command
|
|
45
47
|
complete = ZshComplete(app, {}, "mcli", "complete")
|
|
46
48
|
script = complete.source()
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
click.echo("# Zsh completion script for MCLI")
|
|
49
51
|
click.echo("# Add this to your ~/.zshrc:")
|
|
50
52
|
click.echo()
|
|
@@ -56,12 +58,12 @@ def zsh_completion(ctx):
|
|
|
56
58
|
def fish_completion(ctx):
|
|
57
59
|
"""Generate fish completion script"""
|
|
58
60
|
from click.shell_completion import FishComplete
|
|
59
|
-
|
|
61
|
+
|
|
60
62
|
# Get the root CLI app
|
|
61
63
|
app = ctx.find_root().command
|
|
62
64
|
complete = FishComplete(app, {}, "mcli", "complete")
|
|
63
65
|
script = complete.source()
|
|
64
|
-
|
|
66
|
+
|
|
65
67
|
click.echo("# Fish completion script for MCLI")
|
|
66
68
|
click.echo("# Add this to ~/.config/fish/completions/mcli.fish:")
|
|
67
69
|
click.echo()
|
|
@@ -69,45 +71,49 @@ def fish_completion(ctx):
|
|
|
69
71
|
|
|
70
72
|
|
|
71
73
|
@completion.command(name="install")
|
|
72
|
-
@click.option(
|
|
73
|
-
|
|
74
|
+
@click.option(
|
|
75
|
+
"--shell",
|
|
76
|
+
type=click.Choice(["bash", "zsh", "fish"]),
|
|
77
|
+
help="Shell to install for (auto-detected if not specified)",
|
|
78
|
+
)
|
|
74
79
|
@click.pass_context
|
|
75
80
|
def install_completion(ctx, shell):
|
|
76
81
|
"""Install shell completion for the current user"""
|
|
77
82
|
import subprocess
|
|
78
|
-
|
|
83
|
+
|
|
79
84
|
# Auto-detect shell if not specified
|
|
80
85
|
if not shell:
|
|
81
|
-
shell_path = os.environ.get(
|
|
82
|
-
if
|
|
83
|
-
shell =
|
|
84
|
-
elif
|
|
85
|
-
shell =
|
|
86
|
-
elif
|
|
87
|
-
shell =
|
|
86
|
+
shell_path = os.environ.get("SHELL", "")
|
|
87
|
+
if "bash" in shell_path:
|
|
88
|
+
shell = "bash"
|
|
89
|
+
elif "zsh" in shell_path:
|
|
90
|
+
shell = "zsh"
|
|
91
|
+
elif "fish" in shell_path:
|
|
92
|
+
shell = "fish"
|
|
88
93
|
else:
|
|
89
94
|
click.echo("ā Could not auto-detect shell. Please specify --shell")
|
|
90
95
|
return
|
|
91
|
-
|
|
96
|
+
|
|
92
97
|
# Get the root CLI app
|
|
93
98
|
app = ctx.find_root().command
|
|
94
|
-
|
|
99
|
+
|
|
95
100
|
try:
|
|
96
|
-
if shell ==
|
|
101
|
+
if shell == "bash":
|
|
97
102
|
from click.shell_completion import BashComplete
|
|
103
|
+
|
|
98
104
|
complete = BashComplete(app, {}, "mcli", "complete")
|
|
99
105
|
script = complete.source()
|
|
100
|
-
|
|
106
|
+
|
|
101
107
|
# Install to bash completion directory
|
|
102
108
|
bash_completion_dir = Path.home() / ".bash_completion.d"
|
|
103
109
|
bash_completion_dir.mkdir(exist_ok=True)
|
|
104
110
|
completion_file = bash_completion_dir / "mcli"
|
|
105
111
|
completion_file.write_text(script)
|
|
106
|
-
|
|
112
|
+
|
|
107
113
|
# Add sourcing to .bashrc if needed
|
|
108
114
|
bashrc = Path.home() / ".bashrc"
|
|
109
115
|
source_line = f"[ -f {completion_file} ] && source {completion_file}"
|
|
110
|
-
|
|
116
|
+
|
|
111
117
|
if bashrc.exists():
|
|
112
118
|
content = bashrc.read_text()
|
|
113
119
|
if source_line not in content:
|
|
@@ -120,50 +126,54 @@ def install_completion(ctx, shell):
|
|
|
120
126
|
click.echo(f"ā
Completion installed to {completion_file}")
|
|
121
127
|
click.echo("š” Add this to your ~/.bashrc:")
|
|
122
128
|
click.echo(source_line)
|
|
123
|
-
|
|
124
|
-
elif shell ==
|
|
125
|
-
from click.shell_completion import ZshComplete
|
|
129
|
+
|
|
130
|
+
elif shell == "zsh":
|
|
131
|
+
from click.shell_completion import ZshComplete
|
|
132
|
+
|
|
126
133
|
complete = ZshComplete(app, {}, "mcli", "complete")
|
|
127
134
|
script = complete.source()
|
|
128
|
-
|
|
135
|
+
|
|
129
136
|
# Install to zsh completion directory
|
|
130
137
|
zsh_completion_dir = Path.home() / ".config" / "zsh" / "completions"
|
|
131
138
|
zsh_completion_dir.mkdir(parents=True, exist_ok=True)
|
|
132
139
|
completion_file = zsh_completion_dir / "_mcli"
|
|
133
140
|
completion_file.write_text(script)
|
|
134
|
-
|
|
141
|
+
|
|
135
142
|
# Add to fpath in .zshrc if needed
|
|
136
143
|
zshrc = Path.home() / ".zshrc"
|
|
137
144
|
fpath_line = f'fpath=("{zsh_completion_dir}" $fpath)'
|
|
138
|
-
|
|
145
|
+
|
|
139
146
|
if zshrc.exists():
|
|
140
147
|
content = zshrc.read_text()
|
|
141
148
|
if str(zsh_completion_dir) not in content:
|
|
142
149
|
with zshrc.open("a") as f:
|
|
143
|
-
f.write(
|
|
144
|
-
|
|
150
|
+
f.write(
|
|
151
|
+
f"\n# MCLI completion\n{fpath_line}\nautoload -U compinit && compinit\n"
|
|
152
|
+
)
|
|
153
|
+
click.echo("ā
Added completion to ~/.zshrc")
|
|
145
154
|
else:
|
|
146
155
|
click.echo("ā¹ļø Completion already configured in ~/.zshrc")
|
|
147
156
|
else:
|
|
148
157
|
click.echo(f"ā
Completion installed to {completion_file}")
|
|
149
158
|
click.echo("š” Add this to your ~/.zshrc:")
|
|
150
159
|
click.echo(f"{fpath_line}\nautoload -U compinit && compinit")
|
|
151
|
-
|
|
152
|
-
elif shell ==
|
|
160
|
+
|
|
161
|
+
elif shell == "fish":
|
|
153
162
|
from click.shell_completion import FishComplete
|
|
163
|
+
|
|
154
164
|
complete = FishComplete(app, {}, "mcli", "complete")
|
|
155
165
|
script = complete.source()
|
|
156
|
-
|
|
166
|
+
|
|
157
167
|
# Install to fish completion directory
|
|
158
168
|
fish_completion_dir = Path.home() / ".config" / "fish" / "completions"
|
|
159
169
|
fish_completion_dir.mkdir(parents=True, exist_ok=True)
|
|
160
170
|
completion_file = fish_completion_dir / "mcli.fish"
|
|
161
171
|
completion_file.write_text(script)
|
|
162
172
|
click.echo(f"ā
Completion installed to {completion_file}")
|
|
163
|
-
|
|
173
|
+
|
|
164
174
|
click.echo(f"š Shell completion for {shell} installed successfully!")
|
|
165
175
|
click.echo("š” Restart your shell or source your profile to enable completions")
|
|
166
|
-
|
|
176
|
+
|
|
167
177
|
except Exception as e:
|
|
168
178
|
click.echo(f"ā Failed to install completion: {e}")
|
|
169
179
|
|
|
@@ -171,39 +181,39 @@ def install_completion(ctx, shell):
|
|
|
171
181
|
@completion.command(name="status")
|
|
172
182
|
def completion_status():
|
|
173
183
|
"""Check current shell completion status"""
|
|
174
|
-
current_shell = os.environ.get(
|
|
175
|
-
shell_name = Path(current_shell).name if current_shell !=
|
|
176
|
-
|
|
184
|
+
current_shell = os.environ.get("SHELL", "unknown")
|
|
185
|
+
shell_name = Path(current_shell).name if current_shell != "unknown" else "unknown"
|
|
186
|
+
|
|
177
187
|
click.echo(f"š Current shell: {shell_name} ({current_shell})")
|
|
178
188
|
click.echo()
|
|
179
|
-
|
|
189
|
+
|
|
180
190
|
# Check for existing completions
|
|
181
191
|
completions_found = []
|
|
182
|
-
|
|
192
|
+
|
|
183
193
|
# Check bash
|
|
184
194
|
bash_completion = Path.home() / ".bash_completion.d" / "mcli"
|
|
185
195
|
if bash_completion.exists():
|
|
186
196
|
completions_found.append(f"ā
Bash completion: {bash_completion}")
|
|
187
197
|
else:
|
|
188
198
|
completions_found.append("ā Bash completion: Not installed")
|
|
189
|
-
|
|
199
|
+
|
|
190
200
|
# Check zsh
|
|
191
|
-
zsh_completion = Path.home() / ".config" / "zsh" / "completions" / "_mcli"
|
|
201
|
+
zsh_completion = Path.home() / ".config" / "zsh" / "completions" / "_mcli"
|
|
192
202
|
if zsh_completion.exists():
|
|
193
203
|
completions_found.append(f"ā
Zsh completion: {zsh_completion}")
|
|
194
204
|
else:
|
|
195
205
|
completions_found.append("ā Zsh completion: Not installed")
|
|
196
|
-
|
|
206
|
+
|
|
197
207
|
# Check fish
|
|
198
208
|
fish_completion = Path.home() / ".config" / "fish" / "completions" / "mcli.fish"
|
|
199
209
|
if fish_completion.exists():
|
|
200
210
|
completions_found.append(f"ā
Fish completion: {fish_completion}")
|
|
201
211
|
else:
|
|
202
212
|
completions_found.append("ā Fish completion: Not installed")
|
|
203
|
-
|
|
213
|
+
|
|
204
214
|
for status in completions_found:
|
|
205
215
|
click.echo(status)
|
|
206
|
-
|
|
216
|
+
|
|
207
217
|
click.echo()
|
|
208
218
|
click.echo("š” To install completion for your shell:")
|
|
209
219
|
click.echo(" mcli completion install")
|
|
@@ -212,5 +222,5 @@ def completion_status():
|
|
|
212
222
|
click.echo(f" mcli completion {shell_name}")
|
|
213
223
|
|
|
214
224
|
|
|
215
|
-
# Export the CLI group for registration
|
|
216
|
-
cli = completion
|
|
225
|
+
# Export the CLI group for registration
|
|
226
|
+
cli = completion
|
mcli/app/completion_helpers.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Completion helpers for MCLI that provide tab completion without loading heavy modules
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Dict, List
|
|
6
|
+
|
|
6
7
|
import click
|
|
7
8
|
from click.shell_completion import CompletionItem
|
|
8
9
|
|
|
@@ -11,12 +12,12 @@ LAZY_COMMAND_COMPLETIONS = {
|
|
|
11
12
|
"workflow": {
|
|
12
13
|
"subcommands": [
|
|
13
14
|
"api-daemon",
|
|
14
|
-
"daemon",
|
|
15
|
+
"daemon",
|
|
15
16
|
"file",
|
|
16
17
|
"politician-trading",
|
|
17
18
|
"scheduler",
|
|
18
19
|
"sync",
|
|
19
|
-
"videos"
|
|
20
|
+
"videos",
|
|
20
21
|
],
|
|
21
22
|
"politician-trading": {
|
|
22
23
|
"subcommands": [
|
|
@@ -24,7 +25,7 @@ LAZY_COMMAND_COMPLETIONS = {
|
|
|
24
25
|
"cron-job",
|
|
25
26
|
"data-sources",
|
|
26
27
|
"disclosures",
|
|
27
|
-
"health",
|
|
28
|
+
"health",
|
|
28
29
|
"jobs",
|
|
29
30
|
"monitor",
|
|
30
31
|
"politicians",
|
|
@@ -34,105 +35,50 @@ LAZY_COMMAND_COMPLETIONS = {
|
|
|
34
35
|
"stats",
|
|
35
36
|
"status",
|
|
36
37
|
"test-workflow",
|
|
37
|
-
"verify"
|
|
38
|
+
"verify",
|
|
38
39
|
],
|
|
39
|
-
"cron-job": {
|
|
40
|
-
"options": ["--create", "--test"]
|
|
41
|
-
},
|
|
40
|
+
"cron-job": {"options": ["--create", "--test"]},
|
|
42
41
|
"setup": {
|
|
43
42
|
"options": ["--create-tables", "--verify", "--generate-schema", "--output-dir"]
|
|
44
43
|
},
|
|
45
|
-
"run": {
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
"
|
|
55
|
-
"options": ["--interval", "--count"]
|
|
56
|
-
},
|
|
57
|
-
"status": {
|
|
58
|
-
"options": ["--json"]
|
|
59
|
-
},
|
|
60
|
-
"stats": {
|
|
61
|
-
"options": ["--json"]
|
|
62
|
-
},
|
|
63
|
-
"test-workflow": {
|
|
64
|
-
"options": ["--verbose", "--validate-writes"]
|
|
65
|
-
},
|
|
66
|
-
"schema": {
|
|
67
|
-
"options": ["--show-location", "--generate", "--output-dir"]
|
|
68
|
-
},
|
|
69
|
-
"data-sources": {
|
|
70
|
-
"options": ["--json"]
|
|
71
|
-
},
|
|
72
|
-
"jobs": {
|
|
73
|
-
"options": ["--json", "--limit"]
|
|
74
|
-
},
|
|
44
|
+
"run": {"options": ["--full", "--us-only", "--eu-only"]},
|
|
45
|
+
"connectivity": {"options": ["--json", "--continuous", "--interval", "--duration"]},
|
|
46
|
+
"health": {"options": ["--json"]},
|
|
47
|
+
"monitor": {"options": ["--interval", "--count"]},
|
|
48
|
+
"status": {"options": ["--json"]},
|
|
49
|
+
"stats": {"options": ["--json"]},
|
|
50
|
+
"test-workflow": {"options": ["--verbose", "--validate-writes"]},
|
|
51
|
+
"schema": {"options": ["--show-location", "--generate", "--output-dir"]},
|
|
52
|
+
"data-sources": {"options": ["--json"]},
|
|
53
|
+
"jobs": {"options": ["--json", "--limit"]},
|
|
75
54
|
"politicians": {
|
|
76
55
|
"options": ["--json", "--limit", "--role", "--party", "--state", "--search"]
|
|
77
56
|
},
|
|
78
57
|
"disclosures": {
|
|
79
|
-
"options": [
|
|
58
|
+
"options": [
|
|
59
|
+
"--json",
|
|
60
|
+
"--limit",
|
|
61
|
+
"--politician",
|
|
62
|
+
"--asset",
|
|
63
|
+
"--transaction-type",
|
|
64
|
+
"--amount-min",
|
|
65
|
+
"--amount-max",
|
|
66
|
+
"--days",
|
|
67
|
+
"--details",
|
|
68
|
+
]
|
|
80
69
|
},
|
|
81
|
-
"verify": {
|
|
82
|
-
"options": ["--json"]
|
|
83
|
-
}
|
|
70
|
+
"verify": {"options": ["--json"]},
|
|
84
71
|
},
|
|
85
72
|
"scheduler": {
|
|
86
|
-
"subcommands": [
|
|
87
|
-
"add",
|
|
88
|
-
"cancel",
|
|
89
|
-
"list",
|
|
90
|
-
"monitor",
|
|
91
|
-
"remove",
|
|
92
|
-
"start",
|
|
93
|
-
"status",
|
|
94
|
-
"stop"
|
|
95
|
-
]
|
|
96
|
-
},
|
|
97
|
-
"daemon": {
|
|
98
|
-
"subcommands": [
|
|
99
|
-
"start",
|
|
100
|
-
"stop",
|
|
101
|
-
"status",
|
|
102
|
-
"logs"
|
|
103
|
-
]
|
|
73
|
+
"subcommands": ["add", "cancel", "list", "monitor", "remove", "start", "status", "stop"]
|
|
104
74
|
},
|
|
105
|
-
"
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"logs"
|
|
111
|
-
]
|
|
112
|
-
},
|
|
113
|
-
"videos": {
|
|
114
|
-
"subcommands": [
|
|
115
|
-
"remove-overlay",
|
|
116
|
-
"extract-frames",
|
|
117
|
-
"create-video"
|
|
118
|
-
]
|
|
119
|
-
},
|
|
120
|
-
"sync": {
|
|
121
|
-
"subcommands": [
|
|
122
|
-
"status",
|
|
123
|
-
"sync"
|
|
124
|
-
]
|
|
125
|
-
},
|
|
126
|
-
"file": {
|
|
127
|
-
"subcommands": [
|
|
128
|
-
"search",
|
|
129
|
-
"organize"
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
"chat": {
|
|
134
|
-
"options": ["--model", "--system", "--temperature", "--max-tokens", "--stream"]
|
|
75
|
+
"daemon": {"subcommands": ["start", "stop", "status", "logs"]},
|
|
76
|
+
"api-daemon": {"subcommands": ["start", "stop", "status", "logs"]},
|
|
77
|
+
"videos": {"subcommands": ["remove-overlay", "extract-frames", "create-video"]},
|
|
78
|
+
"sync": {"subcommands": ["status", "sync"]},
|
|
79
|
+
"file": {"subcommands": ["search", "organize"]},
|
|
135
80
|
},
|
|
81
|
+
"chat": {"options": ["--model", "--system", "--temperature", "--max-tokens", "--stream"]},
|
|
136
82
|
"model": {
|
|
137
83
|
"subcommands": [
|
|
138
84
|
"download",
|
|
@@ -142,79 +88,51 @@ LAZY_COMMAND_COMPLETIONS = {
|
|
|
142
88
|
"pull",
|
|
143
89
|
"delete",
|
|
144
90
|
"recommend",
|
|
145
|
-
"status"
|
|
146
|
-
]
|
|
147
|
-
},
|
|
148
|
-
"cron-test": {
|
|
149
|
-
"options": ["--quick", "--cleanup", "--verbose"]
|
|
150
|
-
},
|
|
151
|
-
"visual": {
|
|
152
|
-
"subcommands": [
|
|
153
|
-
"demo",
|
|
154
|
-
"spinner-test"
|
|
155
|
-
]
|
|
156
|
-
},
|
|
157
|
-
"redis": {
|
|
158
|
-
"subcommands": [
|
|
159
|
-
"start",
|
|
160
|
-
"stop",
|
|
161
91
|
"status",
|
|
162
|
-
"flush"
|
|
163
|
-
]
|
|
164
|
-
},
|
|
165
|
-
"logs": {
|
|
166
|
-
"subcommands": [
|
|
167
|
-
"tail",
|
|
168
|
-
"view",
|
|
169
|
-
"clear"
|
|
170
92
|
]
|
|
171
93
|
},
|
|
94
|
+
"cron-test": {"options": ["--quick", "--cleanup", "--verbose"]},
|
|
95
|
+
"visual": {"subcommands": ["demo", "spinner-test"]},
|
|
96
|
+
"redis": {"subcommands": ["start", "stop", "status", "flush"]},
|
|
97
|
+
"logs": {"subcommands": ["tail", "view", "clear"]},
|
|
172
98
|
"completion": {
|
|
173
|
-
"subcommands": [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"fish",
|
|
177
|
-
"install",
|
|
178
|
-
"status"
|
|
179
|
-
],
|
|
180
|
-
"install": {
|
|
181
|
-
"options": ["--shell"]
|
|
182
|
-
}
|
|
183
|
-
}
|
|
99
|
+
"subcommands": ["bash", "zsh", "fish", "install", "status"],
|
|
100
|
+
"install": {"options": ["--shell"]},
|
|
101
|
+
},
|
|
184
102
|
}
|
|
185
103
|
|
|
186
104
|
|
|
187
105
|
def get_completion_items(cmd_path: List[str], incomplete: str = "") -> List[CompletionItem]:
|
|
188
106
|
"""Get completion items for a given command path without loading modules"""
|
|
189
107
|
items = []
|
|
190
|
-
|
|
108
|
+
|
|
191
109
|
# Navigate to the completion data for this path
|
|
192
110
|
current_data = LAZY_COMMAND_COMPLETIONS
|
|
193
|
-
|
|
111
|
+
|
|
194
112
|
for part in cmd_path:
|
|
195
113
|
if part in current_data:
|
|
196
114
|
current_data = current_data[part]
|
|
197
115
|
else:
|
|
198
116
|
return items # No completion data available
|
|
199
|
-
|
|
117
|
+
|
|
200
118
|
# Add subcommands
|
|
201
119
|
if "subcommands" in current_data:
|
|
202
120
|
for subcommand in current_data["subcommands"]:
|
|
203
121
|
if subcommand.startswith(incomplete):
|
|
204
122
|
items.append(CompletionItem(subcommand))
|
|
205
|
-
|
|
206
|
-
# Add options
|
|
123
|
+
|
|
124
|
+
# Add options
|
|
207
125
|
if "options" in current_data:
|
|
208
126
|
for option in current_data["options"]:
|
|
209
127
|
if option.startswith(incomplete):
|
|
210
128
|
items.append(CompletionItem(option))
|
|
211
|
-
|
|
129
|
+
|
|
212
130
|
return items
|
|
213
131
|
|
|
214
132
|
|
|
215
133
|
class CompletionAwareLazyGroup(click.Group):
|
|
216
134
|
"""A Click group that provides completion without loading modules"""
|
|
217
|
-
|
|
135
|
+
|
|
218
136
|
def __init__(self, name, import_path, *args, **kwargs):
|
|
219
137
|
self.import_path = import_path
|
|
220
138
|
self._loaded_group = None
|
|
@@ -225,6 +143,7 @@ class CompletionAwareLazyGroup(click.Group):
|
|
|
225
143
|
if self._loaded_group is None:
|
|
226
144
|
try:
|
|
227
145
|
import importlib
|
|
146
|
+
|
|
228
147
|
module_path, attr_name = self.import_path.rsplit(".", 1)
|
|
229
148
|
module = importlib.import_module(module_path)
|
|
230
149
|
self._loaded_group = getattr(module, attr_name)
|
|
@@ -232,6 +151,7 @@ class CompletionAwareLazyGroup(click.Group):
|
|
|
232
151
|
# Return a dummy group that shows an error
|
|
233
152
|
def error_callback():
|
|
234
153
|
click.echo(f"Error: Command group {self.name} is not available")
|
|
154
|
+
|
|
235
155
|
self._loaded_group = click.Group(self.name, callback=error_callback)
|
|
236
156
|
return self._loaded_group
|
|
237
157
|
|
|
@@ -252,13 +172,13 @@ class CompletionAwareLazyGroup(click.Group):
|
|
|
252
172
|
data = LAZY_COMMAND_COMPLETIONS[self.name]
|
|
253
173
|
if "subcommands" in data:
|
|
254
174
|
return sorted(data["subcommands"])
|
|
255
|
-
|
|
175
|
+
|
|
256
176
|
# Try to get from static completion data for other commands
|
|
257
177
|
if self.name in LAZY_COMMAND_COMPLETIONS:
|
|
258
178
|
data = LAZY_COMMAND_COMPLETIONS[self.name]
|
|
259
179
|
if "subcommands" in data:
|
|
260
180
|
return sorted(data["subcommands"])
|
|
261
|
-
|
|
181
|
+
|
|
262
182
|
# Fallback to loading the actual group
|
|
263
183
|
group = self._load_group()
|
|
264
184
|
return group.list_commands(ctx)
|
|
@@ -274,10 +194,10 @@ class CompletionAwareLazyGroup(click.Group):
|
|
|
274
194
|
if subcommand.startswith(incomplete):
|
|
275
195
|
items.append(CompletionItem(subcommand))
|
|
276
196
|
return items
|
|
277
|
-
|
|
197
|
+
|
|
278
198
|
# Fallback to loading the actual group
|
|
279
199
|
group = self._load_group()
|
|
280
|
-
if hasattr(group,
|
|
200
|
+
if hasattr(group, "shell_complete"):
|
|
281
201
|
return group.shell_complete(ctx, incomplete)
|
|
282
202
|
return []
|
|
283
203
|
|
|
@@ -287,6 +207,8 @@ class CompletionAwareLazyGroup(click.Group):
|
|
|
287
207
|
return group.get_params(ctx)
|
|
288
208
|
|
|
289
209
|
|
|
290
|
-
def create_completion_aware_lazy_group(
|
|
210
|
+
def create_completion_aware_lazy_group(
|
|
211
|
+
name: str, import_path: str, help_text: str = None
|
|
212
|
+
) -> CompletionAwareLazyGroup:
|
|
291
213
|
"""Create a completion-aware lazy group"""
|
|
292
|
-
return CompletionAwareLazyGroup(name, import_path, help=help_text)
|
|
214
|
+
return CompletionAwareLazyGroup(name, import_path, help=help_text)
|
mcli/app/logs_cmd.py
CHANGED
|
@@ -161,7 +161,9 @@ def tail_logs(log_type: str, lines: int, date: Optional[str], follow: bool):
|
|
|
161
161
|
|
|
162
162
|
# Use tail -f for real-time following
|
|
163
163
|
cmd = ["tail", f"-n{lines}", "-f", str(log_file)]
|
|
164
|
-
process = subprocess.Popen(
|
|
164
|
+
process = subprocess.Popen(
|
|
165
|
+
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
|
|
166
|
+
)
|
|
165
167
|
|
|
166
168
|
try:
|
|
167
169
|
for line in iter(process.stdout.readline, ""):
|
|
@@ -179,7 +181,9 @@ def tail_logs(log_type: str, lines: int, date: Optional[str], follow: bool):
|
|
|
179
181
|
tail_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
|
|
180
182
|
|
|
181
183
|
# Display with formatting
|
|
182
|
-
console.print(
|
|
184
|
+
console.print(
|
|
185
|
+
f"\nš **Last {len(tail_lines)} lines from {log_file.name}**\n", style="cyan"
|
|
186
|
+
)
|
|
183
187
|
|
|
184
188
|
for line in tail_lines:
|
|
185
189
|
formatted_line = _format_log_line(line.rstrip())
|