mcli-framework 7.10.1__py3-none-any.whl → 7.10.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/lib/custom_commands.py +10 -0
- mcli/lib/optional_deps.py +240 -0
- mcli/workflow/git_commit/ai_service.py +13 -2
- mcli/workflow/notebook/converter.py +375 -0
- mcli/workflow/notebook/notebook_cmd.py +441 -0
- mcli/workflow/notebook/schema.py +402 -0
- mcli/workflow/notebook/validator.py +313 -0
- mcli/workflow/workflow.py +14 -0
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/METADATA +36 -2
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/RECORD +14 -94
- mcli/__init__.py +0 -160
- mcli/__main__.py +0 -14
- mcli/app/__init__.py +0 -23
- mcli/app/model/__init__.py +0 -0
- mcli/app/video/__init__.py +0 -5
- mcli/chat/__init__.py +0 -34
- mcli/lib/__init__.py +0 -0
- mcli/lib/api/__init__.py +0 -0
- mcli/lib/auth/__init__.py +0 -1
- mcli/lib/config/__init__.py +0 -1
- mcli/lib/erd/__init__.py +0 -25
- mcli/lib/files/__init__.py +0 -0
- mcli/lib/fs/__init__.py +0 -1
- mcli/lib/logger/__init__.py +0 -3
- mcli/lib/performance/__init__.py +0 -17
- mcli/lib/pickles/__init__.py +0 -1
- mcli/lib/secrets/__init__.py +0 -10
- mcli/lib/shell/__init__.py +0 -0
- mcli/lib/toml/__init__.py +0 -1
- mcli/lib/watcher/__init__.py +0 -0
- mcli/ml/__init__.py +0 -16
- mcli/ml/api/__init__.py +0 -30
- mcli/ml/api/routers/__init__.py +0 -27
- mcli/ml/auth/__init__.py +0 -41
- mcli/ml/backtesting/__init__.py +0 -33
- mcli/ml/cli/__init__.py +0 -5
- mcli/ml/config/__init__.py +0 -33
- mcli/ml/configs/__init__.py +0 -16
- mcli/ml/dashboard/__init__.py +0 -12
- mcli/ml/dashboard/components/__init__.py +0 -7
- mcli/ml/dashboard/pages/__init__.py +0 -6
- mcli/ml/data_ingestion/__init__.py +0 -29
- mcli/ml/database/__init__.py +0 -40
- mcli/ml/experimentation/__init__.py +0 -29
- mcli/ml/features/__init__.py +0 -39
- mcli/ml/features/political_features.py +0 -677
- mcli/ml/mlops/__init__.py +0 -19
- mcli/ml/models/__init__.py +0 -90
- mcli/ml/monitoring/__init__.py +0 -25
- mcli/ml/optimization/__init__.py +0 -27
- mcli/ml/predictions/__init__.py +0 -5
- mcli/ml/preprocessing/__init__.py +0 -24
- mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -570
- mcli/ml/scripts/__init__.py +0 -1
- mcli/ml/serving/__init__.py +0 -1
- mcli/ml/trading/__init__.py +0 -63
- mcli/ml/training/__init__.py +0 -7
- mcli/mygroup/__init__.py +0 -3
- mcli/public/__init__.py +0 -1
- mcli/public/commands/__init__.py +0 -2
- mcli/self/__init__.py +0 -3
- mcli/workflow/__init__.py +0 -0
- mcli/workflow/daemon/__init__.py +0 -15
- mcli/workflow/dashboard/__init__.py +0 -5
- mcli/workflow/docker/__init__.py +0 -0
- mcli/workflow/file/__init__.py +0 -0
- mcli/workflow/gcloud/__init__.py +0 -1
- mcli/workflow/git_commit/__init__.py +0 -0
- mcli/workflow/interview/__init__.py +0 -0
- mcli/workflow/politician_trading/__init__.py +0 -4
- mcli/workflow/politician_trading/config.py +0 -134
- mcli/workflow/politician_trading/connectivity.py +0 -492
- mcli/workflow/politician_trading/data_sources.py +0 -654
- mcli/workflow/politician_trading/database.py +0 -412
- mcli/workflow/politician_trading/demo.py +0 -249
- mcli/workflow/politician_trading/models.py +0 -327
- mcli/workflow/politician_trading/monitoring.py +0 -413
- mcli/workflow/politician_trading/scrapers.py +0 -1074
- mcli/workflow/politician_trading/scrapers_california.py +0 -434
- mcli/workflow/politician_trading/scrapers_corporate_registry.py +0 -797
- mcli/workflow/politician_trading/scrapers_eu.py +0 -376
- mcli/workflow/politician_trading/scrapers_free_sources.py +0 -509
- mcli/workflow/politician_trading/scrapers_third_party.py +0 -373
- mcli/workflow/politician_trading/scrapers_uk.py +0 -378
- mcli/workflow/politician_trading/scrapers_us_states.py +0 -471
- mcli/workflow/politician_trading/seed_database.py +0 -520
- mcli/workflow/politician_trading/supabase_functions.py +0 -354
- mcli/workflow/politician_trading/workflow.py +0 -879
- mcli/workflow/registry/__init__.py +0 -0
- mcli/workflow/repo/__init__.py +0 -0
- mcli/workflow/scheduler/__init__.py +0 -25
- mcli/workflow/search/__init__.py +0 -0
- mcli/workflow/sync/__init__.py +0 -5
- mcli/workflow/videos/__init__.py +0 -1
- mcli/workflow/wakatime/__init__.py +0 -80
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/WHEEL +0 -0
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/entry_points.txt +0 -0
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/licenses/LICENSE +0 -0
- {mcli_framework-7.10.1.dist-info → mcli_framework-7.10.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI commands for MCLI workflow notebook management.
|
|
3
|
+
|
|
4
|
+
Provides commands for:
|
|
5
|
+
- Converting between workflow and notebook formats
|
|
6
|
+
- Migrating existing workflows
|
|
7
|
+
- Validating notebooks
|
|
8
|
+
- Launching the visual editor
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
import click
|
|
16
|
+
|
|
17
|
+
from mcli.lib.logger.logger import get_logger
|
|
18
|
+
from mcli.lib.paths import get_custom_commands_dir
|
|
19
|
+
from mcli.lib.ui.styling import error, info, success, warning
|
|
20
|
+
|
|
21
|
+
from .converter import WorkflowConverter
|
|
22
|
+
from .schema import WorkflowNotebook
|
|
23
|
+
from .validator import NotebookValidator
|
|
24
|
+
|
|
25
|
+
logger = get_logger()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group(name="notebook")
|
|
29
|
+
def notebook():
|
|
30
|
+
"""Workflow notebook management commands"""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@notebook.command(name="convert")
|
|
35
|
+
@click.argument("input_file", type=click.Path(exists=True))
|
|
36
|
+
@click.option(
|
|
37
|
+
"--to",
|
|
38
|
+
"format_type",
|
|
39
|
+
type=click.Choice(["notebook", "workflow"]),
|
|
40
|
+
required=True,
|
|
41
|
+
help="Target format",
|
|
42
|
+
)
|
|
43
|
+
@click.option(
|
|
44
|
+
"-o",
|
|
45
|
+
"--output",
|
|
46
|
+
type=click.Path(),
|
|
47
|
+
help="Output file path (defaults to input file)",
|
|
48
|
+
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--backup/--no-backup",
|
|
51
|
+
default=True,
|
|
52
|
+
help="Create backup before conversion",
|
|
53
|
+
)
|
|
54
|
+
def convert(input_file: str, format_type: str, output: Optional[str], backup: bool):
|
|
55
|
+
"""
|
|
56
|
+
Convert between workflow and notebook formats.
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
|
|
60
|
+
# Convert workflow to notebook
|
|
61
|
+
mcli workflow notebook convert workflow.json --to notebook
|
|
62
|
+
|
|
63
|
+
# Convert notebook to workflow
|
|
64
|
+
mcli workflow notebook convert notebook.json --to workflow -o output.json
|
|
65
|
+
"""
|
|
66
|
+
input_path = Path(input_file)
|
|
67
|
+
output_path = Path(output) if output else input_path
|
|
68
|
+
|
|
69
|
+
# Create backup if requested
|
|
70
|
+
if backup and output_path == input_path:
|
|
71
|
+
backup_path = input_path.with_suffix(".json.bak")
|
|
72
|
+
import shutil
|
|
73
|
+
|
|
74
|
+
shutil.copy2(input_path, backup_path)
|
|
75
|
+
info(f"Created backup: {backup_path}")
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
if format_type == "notebook":
|
|
79
|
+
# Convert to notebook format
|
|
80
|
+
result_path = WorkflowConverter.convert_file_to_notebook(input_path, output_path)
|
|
81
|
+
success(f"Converted to notebook format: {result_path}")
|
|
82
|
+
else:
|
|
83
|
+
# Convert to workflow format
|
|
84
|
+
result_path = WorkflowConverter.convert_file_to_workflow(input_path, output_path)
|
|
85
|
+
success(f"Converted to workflow format: {result_path}")
|
|
86
|
+
|
|
87
|
+
except Exception as e:
|
|
88
|
+
error(f"Conversion failed: {e}")
|
|
89
|
+
raise click.Abort()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@notebook.command(name="migrate")
|
|
93
|
+
@click.option(
|
|
94
|
+
"-d",
|
|
95
|
+
"--directory",
|
|
96
|
+
type=click.Path(exists=True, file_okay=False),
|
|
97
|
+
default=None,
|
|
98
|
+
help="Directory to migrate (defaults to ~/.mcli/commands)",
|
|
99
|
+
)
|
|
100
|
+
@click.option(
|
|
101
|
+
"--backup/--no-backup",
|
|
102
|
+
default=True,
|
|
103
|
+
help="Create backup files before migration",
|
|
104
|
+
)
|
|
105
|
+
@click.option(
|
|
106
|
+
"--in-place/--separate",
|
|
107
|
+
default=True,
|
|
108
|
+
help="Convert in place or create separate files",
|
|
109
|
+
)
|
|
110
|
+
@click.option(
|
|
111
|
+
"--dry-run",
|
|
112
|
+
is_flag=True,
|
|
113
|
+
help="Show what would be migrated without making changes",
|
|
114
|
+
)
|
|
115
|
+
def migrate(directory: Optional[str], backup: bool, in_place: bool, dry_run: bool):
|
|
116
|
+
"""
|
|
117
|
+
Migrate all workflow files in a directory to notebook format.
|
|
118
|
+
|
|
119
|
+
Examples:
|
|
120
|
+
|
|
121
|
+
# Migrate all workflows in default directory
|
|
122
|
+
mcli workflow notebook migrate
|
|
123
|
+
|
|
124
|
+
# Dry run to see what would be migrated
|
|
125
|
+
mcli workflow notebook migrate --dry-run
|
|
126
|
+
|
|
127
|
+
# Migrate specific directory without backup
|
|
128
|
+
mcli workflow notebook migrate -d /path/to/workflows --no-backup
|
|
129
|
+
"""
|
|
130
|
+
target_dir = Path(directory) if directory else get_custom_commands_dir()
|
|
131
|
+
|
|
132
|
+
info(f"Migrating workflows in: {target_dir}")
|
|
133
|
+
|
|
134
|
+
if dry_run:
|
|
135
|
+
warning("DRY RUN MODE - No files will be modified")
|
|
136
|
+
# Count files that would be migrated
|
|
137
|
+
count = 0
|
|
138
|
+
for json_file in target_dir.glob("*.json"):
|
|
139
|
+
if json_file.name == "commands.lock.json":
|
|
140
|
+
continue
|
|
141
|
+
try:
|
|
142
|
+
with open(json_file, "r") as f:
|
|
143
|
+
data = json.load(f)
|
|
144
|
+
if "nbformat" not in data:
|
|
145
|
+
count += 1
|
|
146
|
+
info(f" Would convert: {json_file.name}")
|
|
147
|
+
except Exception as e:
|
|
148
|
+
warning(f" Would skip {json_file.name}: {e}")
|
|
149
|
+
|
|
150
|
+
info(f"\nTotal files to migrate: {count}")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
results = WorkflowConverter.migrate_directory(target_dir, backup=backup, in_place=in_place)
|
|
155
|
+
|
|
156
|
+
success(f"\nMigration complete:")
|
|
157
|
+
info(f" Total files: {results['total']}")
|
|
158
|
+
success(f" Converted: {results['converted']}")
|
|
159
|
+
warning(f" Skipped: {results['skipped']}")
|
|
160
|
+
if results["failed"] > 0:
|
|
161
|
+
error(f" Failed: {results['failed']}")
|
|
162
|
+
|
|
163
|
+
if results["files"]:
|
|
164
|
+
info("\nConverted files:")
|
|
165
|
+
for file_path in results["files"]:
|
|
166
|
+
info(f" - {Path(file_path).name}")
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
error(f"Migration failed: {e}")
|
|
170
|
+
raise click.Abort()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@notebook.command(name="validate")
|
|
174
|
+
@click.argument("notebook_file", type=click.Path(exists=True))
|
|
175
|
+
@click.option(
|
|
176
|
+
"--schema",
|
|
177
|
+
is_flag=True,
|
|
178
|
+
help="Validate against JSON schema",
|
|
179
|
+
)
|
|
180
|
+
@click.option(
|
|
181
|
+
"--syntax",
|
|
182
|
+
is_flag=True,
|
|
183
|
+
help="Validate code syntax",
|
|
184
|
+
)
|
|
185
|
+
@click.option(
|
|
186
|
+
"--all",
|
|
187
|
+
"validate_all",
|
|
188
|
+
is_flag=True,
|
|
189
|
+
help="Run all validations",
|
|
190
|
+
)
|
|
191
|
+
def validate(notebook_file: str, schema: bool, syntax: bool, validate_all: bool):
|
|
192
|
+
"""
|
|
193
|
+
Validate a workflow notebook.
|
|
194
|
+
|
|
195
|
+
Examples:
|
|
196
|
+
|
|
197
|
+
# Validate schema only
|
|
198
|
+
mcli workflow notebook validate notebook.json --schema
|
|
199
|
+
|
|
200
|
+
# Validate code syntax
|
|
201
|
+
mcli workflow notebook validate notebook.json --syntax
|
|
202
|
+
|
|
203
|
+
# Run all validations
|
|
204
|
+
mcli workflow notebook validate notebook.json --all
|
|
205
|
+
"""
|
|
206
|
+
if validate_all:
|
|
207
|
+
schema = syntax = True
|
|
208
|
+
elif not (schema or syntax):
|
|
209
|
+
# Default to all if no specific validation requested
|
|
210
|
+
schema = syntax = True
|
|
211
|
+
|
|
212
|
+
notebook_path = Path(notebook_file)
|
|
213
|
+
validator = NotebookValidator()
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
# Load notebook
|
|
217
|
+
notebook = WorkflowConverter.load_notebook_json(notebook_path)
|
|
218
|
+
|
|
219
|
+
all_valid = True
|
|
220
|
+
|
|
221
|
+
if schema:
|
|
222
|
+
info("Validating JSON schema...")
|
|
223
|
+
schema_valid = validator.validate_schema(notebook)
|
|
224
|
+
if schema_valid:
|
|
225
|
+
success(" Schema validation passed")
|
|
226
|
+
else:
|
|
227
|
+
error(" Schema validation failed")
|
|
228
|
+
for err in validator.schema_errors:
|
|
229
|
+
error(f" - {err}")
|
|
230
|
+
all_valid = False
|
|
231
|
+
|
|
232
|
+
if syntax:
|
|
233
|
+
info("Validating code syntax...")
|
|
234
|
+
syntax_valid = validator.validate_syntax(notebook)
|
|
235
|
+
if syntax_valid:
|
|
236
|
+
success(" Syntax validation passed")
|
|
237
|
+
else:
|
|
238
|
+
error(" Syntax validation failed")
|
|
239
|
+
for err in validator.syntax_errors:
|
|
240
|
+
error(f" - {err}")
|
|
241
|
+
all_valid = False
|
|
242
|
+
|
|
243
|
+
if all_valid:
|
|
244
|
+
success(f"\nNotebook is valid: {notebook_path}")
|
|
245
|
+
else:
|
|
246
|
+
error(f"\nNotebook has validation errors: {notebook_path}")
|
|
247
|
+
raise click.Abort()
|
|
248
|
+
|
|
249
|
+
except Exception as e:
|
|
250
|
+
error(f"Validation failed: {e}")
|
|
251
|
+
raise click.Abort()
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@notebook.command(name="info")
|
|
255
|
+
@click.argument("notebook_file", type=click.Path(exists=True))
|
|
256
|
+
@click.option(
|
|
257
|
+
"--json",
|
|
258
|
+
"output_json",
|
|
259
|
+
is_flag=True,
|
|
260
|
+
help="Output as JSON",
|
|
261
|
+
)
|
|
262
|
+
def notebook_info(notebook_file: str, output_json: bool):
|
|
263
|
+
"""
|
|
264
|
+
Display information about a workflow notebook.
|
|
265
|
+
|
|
266
|
+
Examples:
|
|
267
|
+
|
|
268
|
+
# Show notebook info
|
|
269
|
+
mcli workflow notebook info notebook.json
|
|
270
|
+
|
|
271
|
+
# Output as JSON
|
|
272
|
+
mcli workflow notebook info notebook.json --json
|
|
273
|
+
"""
|
|
274
|
+
notebook_path = Path(notebook_file)
|
|
275
|
+
|
|
276
|
+
try:
|
|
277
|
+
notebook = WorkflowConverter.load_notebook_json(notebook_path)
|
|
278
|
+
|
|
279
|
+
if output_json:
|
|
280
|
+
# Output as JSON
|
|
281
|
+
info_data = {
|
|
282
|
+
"name": notebook.metadata.mcli.name,
|
|
283
|
+
"description": notebook.metadata.mcli.description,
|
|
284
|
+
"group": notebook.metadata.mcli.group,
|
|
285
|
+
"version": notebook.metadata.mcli.version,
|
|
286
|
+
"language": notebook.metadata.mcli.language.value,
|
|
287
|
+
"total_cells": len(notebook.cells),
|
|
288
|
+
"code_cells": len(notebook.code_cells),
|
|
289
|
+
"markdown_cells": len(notebook.markdown_cells),
|
|
290
|
+
"created_at": notebook.metadata.mcli.created_at,
|
|
291
|
+
"updated_at": notebook.metadata.mcli.updated_at,
|
|
292
|
+
}
|
|
293
|
+
click.echo(json.dumps(info_data, indent=2))
|
|
294
|
+
else:
|
|
295
|
+
# Pretty print
|
|
296
|
+
info(f"Notebook: {notebook.metadata.mcli.name}")
|
|
297
|
+
if notebook.metadata.mcli.description:
|
|
298
|
+
info(f"Description: {notebook.metadata.mcli.description}")
|
|
299
|
+
if notebook.metadata.mcli.group:
|
|
300
|
+
info(f"Group: {notebook.metadata.mcli.group}")
|
|
301
|
+
info(f"Version: {notebook.metadata.mcli.version}")
|
|
302
|
+
info(f"Language: {notebook.metadata.mcli.language.value}")
|
|
303
|
+
info(f"\nCells:")
|
|
304
|
+
info(f" Total: {len(notebook.cells)}")
|
|
305
|
+
info(f" Code: {len(notebook.code_cells)}")
|
|
306
|
+
info(f" Markdown: {len(notebook.markdown_cells)}")
|
|
307
|
+
if notebook.metadata.mcli.created_at:
|
|
308
|
+
info(f"\nCreated: {notebook.metadata.mcli.created_at}")
|
|
309
|
+
if notebook.metadata.mcli.updated_at:
|
|
310
|
+
info(f"Updated: {notebook.metadata.mcli.updated_at}")
|
|
311
|
+
|
|
312
|
+
except Exception as e:
|
|
313
|
+
error(f"Failed to read notebook: {e}")
|
|
314
|
+
raise click.Abort()
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
@notebook.command(name="create")
|
|
318
|
+
@click.argument("name")
|
|
319
|
+
@click.option(
|
|
320
|
+
"-d",
|
|
321
|
+
"--description",
|
|
322
|
+
default="",
|
|
323
|
+
help="Notebook description",
|
|
324
|
+
)
|
|
325
|
+
@click.option(
|
|
326
|
+
"-g",
|
|
327
|
+
"--group",
|
|
328
|
+
default=None,
|
|
329
|
+
help="Command group",
|
|
330
|
+
)
|
|
331
|
+
@click.option(
|
|
332
|
+
"-l",
|
|
333
|
+
"--language",
|
|
334
|
+
type=click.Choice(["python", "shell", "bash"]),
|
|
335
|
+
default="python",
|
|
336
|
+
help="Default language",
|
|
337
|
+
)
|
|
338
|
+
@click.option(
|
|
339
|
+
"-o",
|
|
340
|
+
"--output",
|
|
341
|
+
type=click.Path(),
|
|
342
|
+
help="Output file path",
|
|
343
|
+
)
|
|
344
|
+
def create(name: str, description: str, group: Optional[str], language: str, output: Optional[str]):
|
|
345
|
+
"""
|
|
346
|
+
Create a new workflow notebook.
|
|
347
|
+
|
|
348
|
+
Examples:
|
|
349
|
+
|
|
350
|
+
# Create a new Python workflow notebook
|
|
351
|
+
mcli workflow notebook create my-workflow
|
|
352
|
+
|
|
353
|
+
# Create with description and group
|
|
354
|
+
mcli workflow notebook create my-workflow -d "My workflow" -g workflow
|
|
355
|
+
"""
|
|
356
|
+
from .schema import CellLanguage, MCLIMetadata, NotebookMetadata
|
|
357
|
+
|
|
358
|
+
# Create notebook
|
|
359
|
+
mcli_meta = MCLIMetadata(
|
|
360
|
+
name=name,
|
|
361
|
+
description=description,
|
|
362
|
+
group=group,
|
|
363
|
+
language=CellLanguage(language),
|
|
364
|
+
)
|
|
365
|
+
notebook_meta = NotebookMetadata(mcli=mcli_meta)
|
|
366
|
+
notebook = WorkflowNotebook(metadata=notebook_meta)
|
|
367
|
+
|
|
368
|
+
# Add welcome markdown cell
|
|
369
|
+
notebook.add_markdown_cell(
|
|
370
|
+
f"# {name}\n\n{description}\n\n"
|
|
371
|
+
f"This is a workflow notebook. Add code cells below to define your workflow."
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# Add example code cell
|
|
375
|
+
if language == "python":
|
|
376
|
+
example_code = '''"""
|
|
377
|
+
Example workflow cell.
|
|
378
|
+
"""
|
|
379
|
+
import click
|
|
380
|
+
|
|
381
|
+
@click.command()
|
|
382
|
+
def hello():
|
|
383
|
+
"""Example command"""
|
|
384
|
+
click.echo("Hello from workflow!")
|
|
385
|
+
|
|
386
|
+
if __name__ == "__main__":
|
|
387
|
+
hello()
|
|
388
|
+
'''
|
|
389
|
+
else:
|
|
390
|
+
example_code = """#!/usr/bin/env bash
|
|
391
|
+
# Example workflow shell script
|
|
392
|
+
|
|
393
|
+
echo "Hello from workflow!"
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
notebook.add_code_cell(example_code, CellLanguage(language))
|
|
397
|
+
|
|
398
|
+
# Determine output path
|
|
399
|
+
if output:
|
|
400
|
+
output_path = Path(output)
|
|
401
|
+
else:
|
|
402
|
+
commands_dir = get_custom_commands_dir()
|
|
403
|
+
output_path = commands_dir / f"{name}.json"
|
|
404
|
+
|
|
405
|
+
# Save notebook
|
|
406
|
+
WorkflowConverter.save_notebook_json(notebook, output_path)
|
|
407
|
+
success(f"Created notebook: {output_path}")
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@notebook.command(name="edit")
|
|
411
|
+
@click.argument("notebook_file", type=click.Path(exists=True))
|
|
412
|
+
@click.option(
|
|
413
|
+
"--port",
|
|
414
|
+
default=8888,
|
|
415
|
+
help="Server port for editor",
|
|
416
|
+
)
|
|
417
|
+
def edit(notebook_file: str, port: int):
|
|
418
|
+
"""
|
|
419
|
+
Open a workflow notebook in the visual editor.
|
|
420
|
+
|
|
421
|
+
This launches a web server with Monaco editor for visual editing.
|
|
422
|
+
|
|
423
|
+
Examples:
|
|
424
|
+
|
|
425
|
+
# Open notebook in editor
|
|
426
|
+
mcli workflow notebook edit notebook.json
|
|
427
|
+
|
|
428
|
+
# Use custom port
|
|
429
|
+
mcli workflow notebook edit notebook.json --port 9000
|
|
430
|
+
"""
|
|
431
|
+
# TODO: Implement web editor server (Phase 2)
|
|
432
|
+
warning("Visual editor is not yet implemented (coming in Phase 2)")
|
|
433
|
+
info(f"Would open editor for: {notebook_file} on port {port}")
|
|
434
|
+
info("\nFor now, you can:")
|
|
435
|
+
info(" 1. Edit the JSON file directly in your editor")
|
|
436
|
+
info(" 2. Use VSCode with Jupyter extension for .ipynb files")
|
|
437
|
+
info(" 3. Wait for the Monaco editor integration (Phase 2)")
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
if __name__ == "__main__":
|
|
441
|
+
notebook()
|