mcli-framework 8.0.44__tar.gz → 8.0.45__tar.gz
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.
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/MANIFEST.in +2 -6
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/PKG-INFO +20 -18
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/pyproject.toml +24 -25
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/commands_cmd.py +47 -20
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/main.py +24 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/model_cmd.py +10 -34
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/new_cmd.py +2 -2
- mcli_framework-8.0.45/src/mcli/app/setup_cmd.py +187 -0
- mcli_framework-8.0.45/src/mcli/app/source_sync_cmd.py +335 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/sync_cmd.py +76 -36
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/api.py +3 -3
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/daemon_client.py +9 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/config/__init__.py +17 -1
- mcli_framework-8.0.45/src/mcli/lib/config/settings.py +192 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/defaults.py +10 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/env.py +1 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/messages.py +21 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/ipfs_sync.py +62 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/ipfs_utils.py +87 -0
- mcli_framework-8.0.45/src/mcli/lib/ipns_manager.py +206 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pickles/pickles.py +15 -1
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/script_loader.py +18 -2
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/secrets/manager.py +12 -3
- mcli_framework-8.0.45/src/mcli/self/release_notes_cmd.py +304 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/self_cmd.py +8 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/daemon_api.py +14 -2
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/PKG-INFO +20 -18
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/SOURCES.txt +6 -128
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/requires.txt +19 -17
- mcli_framework-8.0.44/.github/dependabot.yml +0 -49
- mcli_framework-8.0.44/.github/dependency-review-config.yml +0 -17
- mcli_framework-8.0.44/.github/workflows/build.yml +0 -102
- mcli_framework-8.0.44/.github/workflows/ci.yml +0 -275
- mcli_framework-8.0.44/.github/workflows/codeql.yml +0 -43
- mcli_framework-8.0.44/.github/workflows/docs-links.yml +0 -48
- mcli_framework-8.0.44/.github/workflows/publish-self-hosted.yml +0 -244
- mcli_framework-8.0.44/.github/workflows/publish.yml +0 -225
- mcli_framework-8.0.44/.github/workflows/release.yml +0 -91
- mcli_framework-8.0.44/.github/workflows/security.yml +0 -128
- mcli_framework-8.0.44/.github/workflows/test.yml +0 -154
- mcli_framework-8.0.44/tests/cli/__init__.py +0 -0
- mcli_framework-8.0.44/tests/cli/test_all_commands.py +0 -7
- mcli_framework-8.0.44/tests/cli/test_app_logs_cmd.py +0 -206
- mcli_framework-8.0.44/tests/cli/test_app_redis_cmd.py +0 -276
- mcli_framework-8.0.44/tests/cli/test_logs_cmd.py +0 -287
- mcli_framework-8.0.44/tests/cli/test_main_app.py +0 -36
- mcli_framework-8.0.44/tests/cli/test_model_cmd.py +0 -619
- mcli_framework-8.0.44/tests/cli/test_self_cmd.py +0 -788
- mcli_framework-8.0.44/tests/cli/test_self_cmd_plugins.py +0 -273
- mcli_framework-8.0.44/tests/cli/test_self_cmd_utilities.py +0 -225
- mcli_framework-8.0.44/tests/cli/test_workflow_creation_commands.py +0 -109
- mcli_framework-8.0.44/tests/cli/test_workflow_file.py +0 -137
- mcli_framework-8.0.44/tests/cli/test_workflow_gcloud.py +0 -120
- mcli_framework-8.0.44/tests/cli/test_workflow_registry.py +0 -231
- mcli_framework-8.0.44/tests/conftest.py +0 -149
- mcli_framework-8.0.44/tests/e2e/__init__.py +0 -0
- mcli_framework-8.0.44/tests/e2e/test_complete_workflows.py +0 -422
- mcli_framework-8.0.44/tests/e2e/test_model_workflow.py +0 -155
- mcli_framework-8.0.44/tests/e2e/test_new_user_workflow.py +0 -144
- mcli_framework-8.0.44/tests/e2e/test_update_workflow.py +0 -195
- mcli_framework-8.0.44/tests/fixtures/__init__.py +0 -75
- mcli_framework-8.0.44/tests/fixtures/chat_fixtures.py +0 -82
- mcli_framework-8.0.44/tests/fixtures/cli_fixtures.py +0 -93
- mcli_framework-8.0.44/tests/fixtures/command_fixtures.py +0 -325
- mcli_framework-8.0.44/tests/fixtures/data_fixtures.py +0 -97
- mcli_framework-8.0.44/tests/fixtures/db_fixtures.py +0 -100
- mcli_framework-8.0.44/tests/fixtures/model_fixtures.py +0 -66
- mcli_framework-8.0.44/tests/integration/__init__.py +0 -0
- mcli_framework-8.0.44/tests/integration/test_all_commands_comprehensive.py +0 -878
- mcli_framework-8.0.44/tests/integration/test_daemon_server.py +0 -824
- mcli_framework-8.0.44/tests/integration/test_direct_file_execution.py +0 -257
- mcli_framework-8.0.44/tests/integration/test_e2e_dashboard_lsh_supabase.py +0 -695
- mcli_framework-8.0.44/tests/integration/test_flask_webapp.py +0 -7
- mcli_framework-8.0.44/tests/integration/test_folder_workflows_integration.py +0 -382
- mcli_framework-8.0.44/tests/integration/test_gcloud_services.py +0 -58
- mcli_framework-8.0.44/tests/integration/test_ml_data_pipeline.py +0 -642
- mcli_framework-8.0.44/tests/integration/test_module_imports.py +0 -132
- mcli_framework-8.0.44/tests/integration/test_notebook_workflows.py +0 -503
- mcli_framework-8.0.44/tests/integration/test_oi_service.py +0 -10
- mcli_framework-8.0.44/tests/integration/test_repo_operations.py +0 -77
- mcli_framework-8.0.44/tests/integration/test_scheduler_integration.py +0 -482
- mcli_framework-8.0.44/tests/integration/test_service_registry.py +0 -141
- mcli_framework-8.0.44/tests/integration/test_video_processing.py +0 -69
- mcli_framework-8.0.44/tests/integration/test_wakatime_api.py +0 -10
- mcli_framework-8.0.44/tests/integration/test_webapp_full.py +0 -7
- mcli_framework-8.0.44/tests/integration/test_workflow.py +0 -7
- mcli_framework-8.0.44/tests/integration/test_workflow_commands.py +0 -7
- mcli_framework-8.0.44/tests/performance/__init__.py +0 -0
- mcli_framework-8.0.44/tests/property/__init__.py +0 -0
- mcli_framework-8.0.44/tests/unit/__init__.py +0 -0
- mcli_framework-8.0.44/tests/unit/storage/__init__.py +0 -1
- mcli_framework-8.0.44/tests/unit/storage/test_cache.py +0 -244
- mcli_framework-8.0.44/tests/unit/storage/test_encryption.py +0 -118
- mcli_framework-8.0.44/tests/unit/storage/test_storacha_cli.py +0 -285
- mcli_framework-8.0.44/tests/unit/test_api_utils.py +0 -98
- mcli_framework-8.0.44/tests/unit/test_async_process_manager.py +0 -571
- mcli_framework-8.0.44/tests/unit/test_auth_modules.py +0 -324
- mcli_framework-8.0.44/tests/unit/test_bug_fixes.py +0 -41
- mcli_framework-8.0.44/tests/unit/test_command_fixtures.py +0 -240
- mcli_framework-8.0.44/tests/unit/test_config.py +0 -98
- mcli_framework-8.0.44/tests/unit/test_correlation_logging.py +0 -698
- mcli_framework-8.0.44/tests/unit/test_custom_commands.py +0 -338
- mcli_framework-8.0.44/tests/unit/test_custom_commands_filtering.py +0 -164
- mcli_framework-8.0.44/tests/unit/test_daemon_api.py +0 -266
- mcli_framework-8.0.44/tests/unit/test_dependencies.py +0 -60
- mcli_framework-8.0.44/tests/unit/test_doc_convert_workflow.py +0 -259
- mcli_framework-8.0.44/tests/unit/test_emulator_workflow.py +0 -618
- mcli_framework-8.0.44/tests/unit/test_erd_generation.py +0 -1365
- mcli_framework-8.0.44/tests/unit/test_erd_generic.py +0 -254
- mcli_framework-8.0.44/tests/unit/test_erd_imports.py +0 -21
- mcli_framework-8.0.44/tests/unit/test_folder_workflows.py +0 -401
- mcli_framework-8.0.44/tests/unit/test_git_commit_workflow.py +0 -343
- mcli_framework-8.0.44/tests/unit/test_health_cmd.py +0 -589
- mcli_framework-8.0.44/tests/unit/test_import_cmd.py +0 -866
- mcli_framework-8.0.44/tests/unit/test_init_mv_cmd.py +0 -293
- mcli_framework-8.0.44/tests/unit/test_ipfs_cmd.py +0 -320
- mcli_framework-8.0.44/tests/unit/test_ipfs_retry.py +0 -233
- mcli_framework-8.0.44/tests/unit/test_language_suffix.py +0 -467
- mcli_framework-8.0.44/tests/unit/test_lib_auth.py +0 -10
- mcli_framework-8.0.44/tests/unit/test_lib_files.py +0 -55
- mcli_framework-8.0.44/tests/unit/test_lib_utils.py +0 -9
- mcli_framework-8.0.44/tests/unit/test_logger.py +0 -214
- mcli_framework-8.0.44/tests/unit/test_new_cmd.py +0 -819
- mcli_framework-8.0.44/tests/unit/test_notebook_command_loader.py +0 -525
- mcli_framework-8.0.44/tests/unit/test_notebook_executor.py +0 -233
- mcli_framework-8.0.44/tests/unit/test_optional_deps.py +0 -211
- mcli_framework-8.0.44/tests/unit/test_paths.py +0 -202
- mcli_framework-8.0.44/tests/unit/test_pdf_compress.py +0 -257
- mcli_framework-8.0.44/tests/unit/test_pyenv.py +0 -427
- mcli_framework-8.0.44/tests/unit/test_regression.py +0 -129
- mcli_framework-8.0.44/tests/unit/test_scheduler.py +0 -439
- mcli_framework-8.0.44/tests/unit/test_scheduler_cron_parser.py +0 -509
- mcli_framework-8.0.44/tests/unit/test_scheduler_job.py +0 -505
- mcli_framework-8.0.44/tests/unit/test_scheduler_models.py +0 -419
- mcli_framework-8.0.44/tests/unit/test_scheduler_monitor.py +0 -509
- mcli_framework-8.0.44/tests/unit/test_scheduler_persistence.py +0 -709
- mcli_framework-8.0.44/tests/unit/test_scheduler_validation.py +0 -390
- mcli_framework-8.0.44/tests/unit/test_script_loader_options.py +0 -210
- mcli_framework-8.0.44/tests/unit/test_security_command_injection.py +0 -225
- mcli_framework-8.0.44/tests/unit/test_self_update.py +0 -200
- mcli_framework-8.0.44/tests/unit/test_service_config.py +0 -82
- mcli_framework-8.0.44/tests/unit/test_service_health.py +0 -88
- mcli_framework-8.0.44/tests/unit/test_service_manager.py +0 -150
- mcli_framework-8.0.44/tests/unit/test_service_state.py +0 -93
- mcli_framework-8.0.44/tests/unit/test_services_cmd.py +0 -162
- mcli_framework-8.0.44/tests/unit/test_shell_exceptions.py +0 -428
- mcli_framework-8.0.44/tests/unit/test_shell_functions.py +0 -329
- mcli_framework-8.0.44/tests/unit/test_shell_security.py +0 -215
- mcli_framework-8.0.44/tests/unit/test_store_cmd.py +0 -445
- mcli_framework-8.0.44/tests/unit/test_sync_cmd.py +0 -266
- mcli_framework-8.0.44/tests/unit/test_toml_utils.py +0 -192
- mcli_framework-8.0.44/tests/unit/test_ui_rich.py +0 -22
- mcli_framework-8.0.44/tests/unit/test_uv_compat.py +0 -224
- mcli_framework-8.0.44/tests/unit/test_workflow_file_completion.py +0 -219
- mcli_framework-8.0.44/tests/unit/test_workflow_models.py +0 -337
- mcli_framework-8.0.44/tests/unit/workflow/test_notebook.py +0 -443
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/LICENSE +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/README.md +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/llms-full.txt +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/llms.txt +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/Cargo.toml +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/src/command_parser.rs +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/src/file_watcher.rs +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/src/lib.rs +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/src/process_manager.rs +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/mcli_rust/src/tfidf.rs +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/setup.cfg +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/completion_helpers.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/context_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/create_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/delete_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/edit_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/import_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/init_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/list_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/migrate_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/model/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/model/model.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/mv_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/remove_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/rm_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/search_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/services_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/video/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/app/video/video.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/config.toml +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/daemon_client_local.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/daemon_decorator.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/api/mcli_decorators.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/auth.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/aws_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/azure_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/credential_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/gcp_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/key_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/mcli_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/token_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/auth/token_util.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/config/config.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/commands.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/paths.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/scripts.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/constants/storage.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/custom_commands.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/discovery/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/discovery/command_discovery.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/erd/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/erd/erd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/erd/generate_graph.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/errors.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/feature_detection.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/files/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/files/files.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/folder_workflows.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/fs/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/fs/fs.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/lib.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/logger/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/logger/correlation.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/logger/logger.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/logger/structured.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/optional_deps.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/paths.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/performance/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/performance/optimizer.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/performance/rust_bridge.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/performance/uvloop_config.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pickles/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pyenv/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pyenv/deps.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pyenv/manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/pyenv/venv.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/script_sync.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/script_watcher.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/search/cached_vectorizer.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/secrets/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/secrets/commands.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/secrets/repl.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/secrets/store.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/config.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/data_pipeline.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/health.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/lsh_client.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/redis_service.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/registry.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/state.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/services/supervisor.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/shell/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/shell/exceptions.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/shell/shell.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/templates/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/templates/command_templates.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/toml/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/toml/toml.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/types.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/ui/styling.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/ui/visual_effects.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/watcher/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/watcher/watcher.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/workflow_models.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/lib/workspace_registry.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/mygroup/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/mygroup/test_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/public/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/public/commands/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/public/oi/oi.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/public/public.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/completion_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/env_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/health_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/ipfs_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/logs_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/migrate_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/store_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/test_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/self/workflows_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/backends/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/backends/ipfs_backend.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/base.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/cache.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/encryption.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/factory.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/registry.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/storage/storacha_cli.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/async_command_database.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/async_process_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/client.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/daemon.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/enhanced_daemon.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/process_cli.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/process_manager.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/daemon/test_daemon.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/doc_convert.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/docker/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/docker/docker.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/file/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/gcloud/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/gcloud/config.toml +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/gcloud/gcloud.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/git_commit/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/git_commit/ai_service.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/interview/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/lsh_integration.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/client.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/download_and_run_efficient_models.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/lightweight_embedder.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/lightweight_model_server.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/lightweight_test.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/model_service.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/ollama_efficient_runner.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/openai_adapter.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/pdf_processor.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/test_efficient_runner.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/test_example.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/test_integration.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/model_service/test_new_features.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/command_loader.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/converter.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/executor.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/notebook_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/schema.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/notebook/validator.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/openai/openai.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/registry/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/registry/registry.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/repo/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/repo/repo.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/cron_parser.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/job.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/models.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/monitor.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/persistence.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/scheduler.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/scheduler/validation.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/search/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/secrets/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/secrets/secrets_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/storage/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/storage/storage_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/sync/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/sync/test_cmd.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/videos/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/wakatime/__init__.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/wakatime/wakatime.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli/workflow/workflow.py +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/dependency_links.txt +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/entry_points.txt +0 -0
- {mcli_framework-8.0.44 → mcli_framework-8.0.45}/src/mcli_framework.egg-info/top_level.txt +0 -0
|
@@ -17,12 +17,8 @@ recursive-include src/mcli *.toml
|
|
|
17
17
|
graft mcli_rust/src
|
|
18
18
|
include mcli_rust/Cargo.toml
|
|
19
19
|
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Include tests (optional, for development)
|
|
24
|
-
recursive-include tests *.py
|
|
25
|
-
include tests/*.ini
|
|
20
|
+
# Exclude CI/test files from distribution (not needed for end users)
|
|
21
|
+
# GitHub workflows and test files are available in the source repository
|
|
26
22
|
|
|
27
23
|
# Exclude build artifacts
|
|
28
24
|
prune build/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcli-framework
|
|
3
|
-
Version: 8.0.
|
|
3
|
+
Version: 8.0.45
|
|
4
4
|
Summary: Portable workflow framework - transform any script into a versioned, schedulable command. Store in ~/.mcli/workflows/, version with lockfile, run as daemon or cron job.
|
|
5
5
|
Author-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
6
6
|
Maintainer-email: Luis Fernandez de la Vara <luis@lefv.io>
|
|
@@ -37,10 +37,12 @@ Requires-Python: >=3.10
|
|
|
37
37
|
Description-Content-Type: text/markdown
|
|
38
38
|
License-File: LICENSE
|
|
39
39
|
Requires-Dist: click<9.0.0,>=8.1.7
|
|
40
|
-
Requires-Dist: rich
|
|
40
|
+
Requires-Dist: rich<15.0.0,>=14.0.0
|
|
41
41
|
Requires-Dist: requests<3.0.0,>=2.31.0
|
|
42
|
-
Requires-Dist: tomli
|
|
43
|
-
Requires-Dist: python-dotenv
|
|
42
|
+
Requires-Dist: tomli<3.0.0,>=2.2.1
|
|
43
|
+
Requires-Dist: python-dotenv<2.0.0,>=1.1.1
|
|
44
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
|
45
|
+
Requires-Dist: pydantic-settings<3.0.0,>=2.0.0
|
|
44
46
|
Requires-Dist: watchdog<4.0.0,>=3.0.0
|
|
45
47
|
Requires-Dist: tqdm<5.0.0,>=4.66.1
|
|
46
48
|
Requires-Dist: humanize<5.0.0,>=4.9.0
|
|
@@ -48,22 +50,22 @@ Requires-Dist: psutil<6.0.0,>=5.9.0
|
|
|
48
50
|
Requires-Dist: inquirerpy<0.4.0,>=0.3.4
|
|
49
51
|
Requires-Dist: gitpython<4.0.0,>=3.1.40
|
|
50
52
|
Requires-Dist: prompt-toolkit<4.0.0,>=3.0.0
|
|
51
|
-
Requires-Dist: aiohttp
|
|
52
|
-
Requires-Dist: httpx
|
|
53
|
-
Requires-Dist: websockets
|
|
54
|
-
Requires-Dist: beautifulsoup4
|
|
55
|
-
Requires-Dist: fuzzywuzzy
|
|
53
|
+
Requires-Dist: aiohttp<4.0.0,>=3.13.3
|
|
54
|
+
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
55
|
+
Requires-Dist: websockets<14.0.0,>=12.0
|
|
56
|
+
Requires-Dist: beautifulsoup4<5.0.0,>=4.13.5
|
|
57
|
+
Requires-Dist: fuzzywuzzy<1.0.0,>=0.18.0
|
|
56
58
|
Requires-Dist: openai<2.0.0,>=1.3.0
|
|
57
|
-
Requires-Dist: anthropic
|
|
58
|
-
Requires-Dist: ollama
|
|
59
|
+
Requires-Dist: anthropic<1.0.0,>=0.60.0
|
|
60
|
+
Requires-Dist: ollama<1.0.0,>=0.5.3
|
|
59
61
|
Requires-Dist: ipython<9.0.0,>=8.12.0
|
|
60
|
-
Requires-Dist: fastapi
|
|
61
|
-
Requires-Dist: uvicorn
|
|
62
|
-
Requires-Dist: uvloop
|
|
63
|
-
Requires-Dist: aiosqlite
|
|
64
|
-
Requires-Dist: redis
|
|
65
|
-
Requires-Dist: aiohttp-sse-client
|
|
66
|
-
Requires-Dist: aiomqtt
|
|
62
|
+
Requires-Dist: fastapi<1.0.0,>=0.110.0
|
|
63
|
+
Requires-Dist: uvicorn<1.0.0,>=0.27.0
|
|
64
|
+
Requires-Dist: uvloop<1.0.0,>=0.19.0
|
|
65
|
+
Requires-Dist: aiosqlite<1.0.0,>=0.20.0
|
|
66
|
+
Requires-Dist: redis<6.0.0,>=5.0.0
|
|
67
|
+
Requires-Dist: aiohttp-sse-client<1.0.0,>=0.2.1
|
|
68
|
+
Requires-Dist: aiomqtt<3.0.0,>=2.0.0
|
|
67
69
|
Provides-Extra: dev
|
|
68
70
|
Requires-Dist: pytest>=8.4.1; extra == "dev"
|
|
69
71
|
Requires-Dist: pytest-cov<5.0.0,>=4.1.0; extra == "dev"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mcli-framework"
|
|
3
|
-
version = "8.0.
|
|
3
|
+
version = "8.0.45"
|
|
4
4
|
description = "Portable workflow framework - transform any script into a versioned, schedulable command. Store in ~/.mcli/workflows/, version with lockfile, run as daemon or cron job."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -37,10 +37,12 @@ classifiers = [
|
|
|
37
37
|
dependencies = [
|
|
38
38
|
# Core CLI dependencies
|
|
39
39
|
"click>=8.1.7,<9.0.0",
|
|
40
|
-
"rich>=14.0.0",
|
|
40
|
+
"rich>=14.0.0,<15.0.0",
|
|
41
41
|
"requests>=2.31.0,<3.0.0",
|
|
42
|
-
"tomli>=2.2.1",
|
|
43
|
-
"python-dotenv>=1.1.1",
|
|
42
|
+
"tomli>=2.2.1,<3.0.0",
|
|
43
|
+
"python-dotenv>=1.1.1,<2.0.0",
|
|
44
|
+
"pydantic>=2.0.0,<3.0.0",
|
|
45
|
+
"pydantic-settings>=2.0.0,<3.0.0",
|
|
44
46
|
# Core utilities
|
|
45
47
|
"watchdog>=3.0.0,<4.0.0",
|
|
46
48
|
"tqdm>=4.66.1,<5.0.0",
|
|
@@ -50,25 +52,25 @@ dependencies = [
|
|
|
50
52
|
"gitpython>=3.1.40,<4.0.0",
|
|
51
53
|
"prompt-toolkit>=3.0.0,<4.0.0",
|
|
52
54
|
# Basic HTTP/async support
|
|
53
|
-
"aiohttp>=3.13.3", # CVE-2025-69223 through CVE-2025-69230 fixes
|
|
54
|
-
"httpx>=0.28.1",
|
|
55
|
-
"websockets>=12.0",
|
|
55
|
+
"aiohttp>=3.13.3,<4.0.0", # CVE-2025-69223 through CVE-2025-69230 fixes
|
|
56
|
+
"httpx>=0.28.1,<1.0.0",
|
|
57
|
+
"websockets>=12.0,<14.0.0",
|
|
56
58
|
# Data parsing
|
|
57
|
-
"beautifulsoup4>=4.13.5",
|
|
58
|
-
"fuzzywuzzy>=0.18.0",
|
|
59
|
+
"beautifulsoup4>=4.13.5,<5.0.0",
|
|
60
|
+
"fuzzywuzzy>=0.18.0,<1.0.0",
|
|
59
61
|
# Chat and AI capabilities
|
|
60
62
|
"openai>=1.3.0,<2.0.0",
|
|
61
|
-
"anthropic>=0.60.0",
|
|
62
|
-
"ollama>=0.5.3",
|
|
63
|
+
"anthropic>=0.60.0,<1.0.0",
|
|
64
|
+
"ollama>=0.5.3,<1.0.0",
|
|
63
65
|
"ipython>=8.12.0,<9.0.0",
|
|
64
66
|
# Enhanced async/performance features
|
|
65
|
-
"fastapi>=0.110.0",
|
|
66
|
-
"uvicorn>=0.27.0",
|
|
67
|
-
"uvloop>=0.19.0",
|
|
68
|
-
"aiosqlite>=0.20.0",
|
|
69
|
-
"redis>=5.0.0",
|
|
70
|
-
"aiohttp-sse-client>=0.2.1",
|
|
71
|
-
"aiomqtt>=2.0.0",
|
|
67
|
+
"fastapi>=0.110.0,<1.0.0",
|
|
68
|
+
"uvicorn>=0.27.0,<1.0.0",
|
|
69
|
+
"uvloop>=0.19.0,<1.0.0",
|
|
70
|
+
"aiosqlite>=0.20.0,<1.0.0",
|
|
71
|
+
"redis>=5.0.0,<6.0.0",
|
|
72
|
+
"aiohttp-sse-client>=0.2.1,<1.0.0",
|
|
73
|
+
"aiomqtt>=2.0.0,<3.0.0",
|
|
72
74
|
]
|
|
73
75
|
|
|
74
76
|
[project.urls]
|
|
@@ -177,20 +179,15 @@ disable_error_code = [
|
|
|
177
179
|
"index",
|
|
178
180
|
"type-arg",
|
|
179
181
|
"override",
|
|
180
|
-
"comparison-overlap",
|
|
181
|
-
"redundant-expr",
|
|
182
182
|
"no-any-return",
|
|
183
183
|
"has-type",
|
|
184
184
|
"valid-type",
|
|
185
185
|
"type-var",
|
|
186
186
|
"dict-item",
|
|
187
187
|
"call-overload",
|
|
188
|
-
"empty-body",
|
|
189
188
|
"no-redef",
|
|
190
189
|
"abstract",
|
|
191
190
|
"list-item",
|
|
192
|
-
"str-bytes-safe",
|
|
193
|
-
"func-returns-value",
|
|
194
191
|
]
|
|
195
192
|
|
|
196
193
|
# Module discovery
|
|
@@ -259,6 +256,8 @@ requires = ["setuptools>=65.0.0", "wheel>=0.40.0"]
|
|
|
259
256
|
build-backend = "setuptools.build_meta"
|
|
260
257
|
|
|
261
258
|
[dependency-groups]
|
|
259
|
+
# NOTE: This is the primary dev dependency specification (PEP 735).
|
|
260
|
+
# [project.optional-dependencies] dev is kept for pip compatibility.
|
|
262
261
|
dev = [
|
|
263
262
|
"black>=25.0.0,<26.0.0", # Pin to 25.x to match lockfile
|
|
264
263
|
"isort>=5.13.2",
|
|
@@ -320,7 +319,7 @@ precision = 2
|
|
|
320
319
|
skip_covered = false
|
|
321
320
|
skip_empty = false
|
|
322
321
|
# Fail if coverage is below threshold
|
|
323
|
-
fail_under =
|
|
322
|
+
fail_under = 50.0
|
|
324
323
|
|
|
325
324
|
[tool.coverage.html]
|
|
326
325
|
directory = "htmlcov"
|
|
@@ -338,7 +337,7 @@ addopts = [
|
|
|
338
337
|
"--cov-report=html",
|
|
339
338
|
"--cov-report=xml",
|
|
340
339
|
"--cov-branch",
|
|
341
|
-
"--cov-fail-under=
|
|
340
|
+
"--cov-fail-under=50",
|
|
342
341
|
]
|
|
343
342
|
testpaths = ["tests"]
|
|
344
343
|
python_files = ["test_*.py", "*_test.py"]
|
|
@@ -353,7 +353,9 @@ def init_store(path, remote):
|
|
|
353
353
|
# Initialize git if not already initialized
|
|
354
354
|
git_dir = store_path / ".git"
|
|
355
355
|
if not git_dir.exists():
|
|
356
|
-
subprocess.run(
|
|
356
|
+
subprocess.run(
|
|
357
|
+
["git", "init"], cwd=store_path, check=True, capture_output=True, timeout=60
|
|
358
|
+
)
|
|
357
359
|
success(f"Initialized git repository at {store_path}")
|
|
358
360
|
|
|
359
361
|
# Create .gitignore
|
|
@@ -395,7 +397,10 @@ Last updated: {datetime.now().isoformat()}
|
|
|
395
397
|
# Add remote if provided
|
|
396
398
|
if remote:
|
|
397
399
|
subprocess.run(
|
|
398
|
-
["git", "remote", "add", "origin", remote],
|
|
400
|
+
["git", "remote", "add", "origin", remote],
|
|
401
|
+
cwd=store_path,
|
|
402
|
+
check=True,
|
|
403
|
+
timeout=60,
|
|
399
404
|
)
|
|
400
405
|
success(f"Added remote: {remote}")
|
|
401
406
|
else:
|
|
@@ -455,11 +460,15 @@ def push_commands(message, all, is_global):
|
|
|
455
460
|
success(f"Copied {copied_count} items to store")
|
|
456
461
|
|
|
457
462
|
# Git add, commit, push
|
|
458
|
-
subprocess.run(["git", "add", "."], cwd=store_path, check=True)
|
|
463
|
+
subprocess.run(["git", "add", "."], cwd=store_path, check=True, timeout=60)
|
|
459
464
|
|
|
460
465
|
# Check if there are changes
|
|
461
466
|
result = subprocess.run(
|
|
462
|
-
["git", "status", "--porcelain"],
|
|
467
|
+
["git", "status", "--porcelain"],
|
|
468
|
+
cwd=store_path,
|
|
469
|
+
capture_output=True,
|
|
470
|
+
text=True,
|
|
471
|
+
timeout=60,
|
|
463
472
|
)
|
|
464
473
|
|
|
465
474
|
if not result.stdout.strip():
|
|
@@ -468,12 +477,14 @@ def push_commands(message, all, is_global):
|
|
|
468
477
|
|
|
469
478
|
# Commit with message
|
|
470
479
|
commit_msg = message or f"Update commands {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
|
471
|
-
subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True)
|
|
480
|
+
subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True, timeout=60)
|
|
472
481
|
success(f"Committed changes: {commit_msg}")
|
|
473
482
|
|
|
474
483
|
# Push to remote if configured
|
|
475
484
|
try:
|
|
476
|
-
subprocess.run(
|
|
485
|
+
subprocess.run(
|
|
486
|
+
["git", "push"], cwd=store_path, check=True, capture_output=True, timeout=60
|
|
487
|
+
)
|
|
477
488
|
success("Pushed to remote")
|
|
478
489
|
except subprocess.CalledProcessError:
|
|
479
490
|
warning("No remote configured or push failed. Commands committed locally.")
|
|
@@ -502,7 +513,7 @@ def pull_commands(force, is_global):
|
|
|
502
513
|
|
|
503
514
|
# Pull from remote
|
|
504
515
|
try:
|
|
505
|
-
subprocess.run(["git", "pull"], cwd=store_path, check=True)
|
|
516
|
+
subprocess.run(["git", "pull"], cwd=store_path, check=True, timeout=60)
|
|
506
517
|
success("Pulled latest changes from remote")
|
|
507
518
|
except subprocess.CalledProcessError:
|
|
508
519
|
warning("No remote configured or pull failed. Using local store.")
|
|
@@ -561,7 +572,9 @@ def sync_commands(message, is_global):
|
|
|
561
572
|
# First pull
|
|
562
573
|
info("Pulling latest changes...")
|
|
563
574
|
try:
|
|
564
|
-
subprocess.run(
|
|
575
|
+
subprocess.run(
|
|
576
|
+
["git", "pull"], cwd=store_path, check=True, capture_output=True, timeout=60
|
|
577
|
+
)
|
|
565
578
|
success("Pulled from remote")
|
|
566
579
|
except subprocess.CalledProcessError:
|
|
567
580
|
warning("No remote or pull failed")
|
|
@@ -581,7 +594,11 @@ def sync_commands(message, is_global):
|
|
|
581
594
|
|
|
582
595
|
# Check for changes
|
|
583
596
|
result = subprocess.run(
|
|
584
|
-
["git", "status", "--porcelain"],
|
|
597
|
+
["git", "status", "--porcelain"],
|
|
598
|
+
cwd=store_path,
|
|
599
|
+
capture_output=True,
|
|
600
|
+
text=True,
|
|
601
|
+
timeout=60,
|
|
585
602
|
)
|
|
586
603
|
|
|
587
604
|
if not result.stdout.strip():
|
|
@@ -589,12 +606,14 @@ def sync_commands(message, is_global):
|
|
|
589
606
|
return
|
|
590
607
|
|
|
591
608
|
# Commit and push
|
|
592
|
-
subprocess.run(["git", "add", "."], cwd=store_path, check=True)
|
|
609
|
+
subprocess.run(["git", "add", "."], cwd=store_path, check=True, timeout=60)
|
|
593
610
|
commit_msg = message or f"Sync commands {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
|
594
|
-
subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True)
|
|
611
|
+
subprocess.run(["git", "commit", "-m", commit_msg], cwd=store_path, check=True, timeout=60)
|
|
595
612
|
|
|
596
613
|
try:
|
|
597
|
-
subprocess.run(
|
|
614
|
+
subprocess.run(
|
|
615
|
+
["git", "push"], cwd=store_path, check=True, capture_output=True, timeout=60
|
|
616
|
+
)
|
|
598
617
|
success("Synced and pushed to remote")
|
|
599
618
|
except subprocess.CalledProcessError:
|
|
600
619
|
success("Synced locally (no remote configured)")
|
|
@@ -614,7 +633,11 @@ def store_status():
|
|
|
614
633
|
|
|
615
634
|
# Git status
|
|
616
635
|
result = subprocess.run(
|
|
617
|
-
["git", "status", "--short", "--branch"],
|
|
636
|
+
["git", "status", "--short", "--branch"],
|
|
637
|
+
cwd=store_path,
|
|
638
|
+
capture_output=True,
|
|
639
|
+
text=True,
|
|
640
|
+
timeout=60,
|
|
618
641
|
)
|
|
619
642
|
|
|
620
643
|
if result.stdout:
|
|
@@ -622,7 +645,7 @@ def store_status():
|
|
|
622
645
|
|
|
623
646
|
# Show remote
|
|
624
647
|
result = subprocess.run(
|
|
625
|
-
["git", "remote", "-v"], cwd=store_path, capture_output=True, text=True
|
|
648
|
+
["git", "remote", "-v"], cwd=store_path, capture_output=True, text=True, timeout=60
|
|
626
649
|
)
|
|
627
650
|
|
|
628
651
|
if result.stdout:
|
|
@@ -656,17 +679,23 @@ def configure_store(remote, path):
|
|
|
656
679
|
if remote:
|
|
657
680
|
# Check if remote exists
|
|
658
681
|
result = subprocess.run(
|
|
659
|
-
["git", "remote"], cwd=store_path, capture_output=True, text=True
|
|
682
|
+
["git", "remote"], cwd=store_path, capture_output=True, text=True, timeout=60
|
|
660
683
|
)
|
|
661
684
|
|
|
662
685
|
if "origin" in result.stdout:
|
|
663
686
|
subprocess.run(
|
|
664
|
-
["git", "remote", "set-url", "origin", remote],
|
|
687
|
+
["git", "remote", "set-url", "origin", remote],
|
|
688
|
+
cwd=store_path,
|
|
689
|
+
check=True,
|
|
690
|
+
timeout=60,
|
|
665
691
|
)
|
|
666
692
|
success(f"Updated remote URL: {remote}")
|
|
667
693
|
else:
|
|
668
694
|
subprocess.run(
|
|
669
|
-
["git", "remote", "add", "origin", remote],
|
|
695
|
+
["git", "remote", "add", "origin", remote],
|
|
696
|
+
cwd=store_path,
|
|
697
|
+
check=True,
|
|
698
|
+
timeout=60,
|
|
670
699
|
)
|
|
671
700
|
success(f"Added remote URL: {remote}")
|
|
672
701
|
|
|
@@ -1391,9 +1420,7 @@ def add_command(command_name, group, description, template, language, shell, is_
|
|
|
1391
1420
|
if language != "ipynb":
|
|
1392
1421
|
import stat
|
|
1393
1422
|
|
|
1394
|
-
script_path.chmod(
|
|
1395
|
-
script_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
|
1396
|
-
)
|
|
1423
|
+
script_path.chmod(script_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
1397
1424
|
|
|
1398
1425
|
logger.info(f"Created script: {script_path}")
|
|
1399
1426
|
except Exception as e:
|
|
@@ -11,6 +11,7 @@ from mcli.lib.logger.logger import disable_runtime_tracing, enable_runtime_traci
|
|
|
11
11
|
|
|
12
12
|
# Desired command order for help display
|
|
13
13
|
COMMAND_ORDER = [
|
|
14
|
+
"setup",
|
|
14
15
|
"init",
|
|
15
16
|
"new",
|
|
16
17
|
"import",
|
|
@@ -20,6 +21,7 @@ COMMAND_ORDER = [
|
|
|
20
21
|
"search",
|
|
21
22
|
"list",
|
|
22
23
|
"run",
|
|
24
|
+
"source",
|
|
23
25
|
"context",
|
|
24
26
|
"health",
|
|
25
27
|
"services",
|
|
@@ -110,6 +112,10 @@ def discover_modules(base_path: Path, config_path: Optional[Path] = None) -> lis
|
|
|
110
112
|
config = tomli.load(f)
|
|
111
113
|
logger.debug(f"Config loaded: {config}")
|
|
112
114
|
logger.debug(f"Using config from {config_path}")
|
|
115
|
+
KNOWN_CONFIG_KEYS = {"paths", "settings", "plugins", "commands", "services"}
|
|
116
|
+
unknown_keys = set(config.keys()) - KNOWN_CONFIG_KEYS
|
|
117
|
+
if unknown_keys:
|
|
118
|
+
logger.warning(f"Unknown keys in config.toml: {unknown_keys}. Check for typos.")
|
|
113
119
|
except Exception as e:
|
|
114
120
|
logger.warning(f"Error reading config file {config_path}: {e}")
|
|
115
121
|
config = {"paths": {"included_dirs": ["app", "self", "workflow", "public"]}}
|
|
@@ -441,6 +447,15 @@ def _add_lazy_commands(app: click.Group):
|
|
|
441
447
|
except ImportError as e:
|
|
442
448
|
logger.debug(f"Could not load sync group: {e}")
|
|
443
449
|
|
|
450
|
+
# mcli setup - Onboarding wizard for new users
|
|
451
|
+
try:
|
|
452
|
+
from mcli.app.setup_cmd import setup
|
|
453
|
+
|
|
454
|
+
app.add_command(setup, name="setup")
|
|
455
|
+
logger.debug("Added setup command")
|
|
456
|
+
except ImportError as e:
|
|
457
|
+
logger.debug(f"Could not load setup command: {e}")
|
|
458
|
+
|
|
444
459
|
# mcli init - Top-level shortcut to initialize workflows directory
|
|
445
460
|
try:
|
|
446
461
|
from mcli.app.init_cmd import init
|
|
@@ -468,6 +483,15 @@ def _add_lazy_commands(app: click.Group):
|
|
|
468
483
|
except ImportError as e:
|
|
469
484
|
logger.debug(f"Could not load health command: {e}")
|
|
470
485
|
|
|
486
|
+
# mcli source - Python source file sync
|
|
487
|
+
try:
|
|
488
|
+
from mcli.app.source_sync_cmd import source_group
|
|
489
|
+
|
|
490
|
+
app.add_command(source_group, name="source")
|
|
491
|
+
logger.debug("Added source sync command")
|
|
492
|
+
except ImportError as e:
|
|
493
|
+
logger.debug(f"Could not load source sync command: {e}")
|
|
494
|
+
|
|
471
495
|
# mcli services - Service lifecycle management
|
|
472
496
|
try:
|
|
473
497
|
from mcli.app.services_cmd import services
|
|
@@ -5,10 +5,8 @@ This stub exists for backwards compatibility with tests and imports.
|
|
|
5
5
|
The actual model command implementation is now in ~/.mcli/workflows/model.json
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import json
|
|
9
8
|
import sys
|
|
10
9
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
12
10
|
|
|
13
11
|
from mcli.lib.constants.paths import DirNames
|
|
14
12
|
|
|
@@ -21,38 +19,16 @@ try:
|
|
|
21
19
|
model_json_path = Path.home() / DirNames.MCLI / "commands" / "model.json"
|
|
22
20
|
|
|
23
21
|
if model_json_path.exists():
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
app = namespace.get("app")
|
|
35
|
-
if app:
|
|
36
|
-
# The model group command
|
|
37
|
-
model = app
|
|
38
|
-
|
|
39
|
-
# Extract individual subcommands from the model group
|
|
40
|
-
if hasattr(model, "commands"):
|
|
41
|
-
commands = model.commands
|
|
42
|
-
list = commands.get("list")
|
|
43
|
-
download = commands.get("download")
|
|
44
|
-
start = commands.get("start")
|
|
45
|
-
recommend = commands.get("recommend")
|
|
46
|
-
status = commands.get("status")
|
|
47
|
-
stop = commands.get("stop")
|
|
48
|
-
pull = commands.get("pull")
|
|
49
|
-
delete = commands.get("delete")
|
|
50
|
-
else:
|
|
51
|
-
# Fallback if commands aren't available
|
|
52
|
-
list = download = start = recommend = status = stop = pull = delete = None
|
|
53
|
-
else:
|
|
54
|
-
# If app is not found, create empty placeholders
|
|
55
|
-
model = list = download = start = recommend = status = stop = pull = delete = None
|
|
22
|
+
# SECURITY: Do not execute arbitrary code from JSON files (fixes #165)
|
|
23
|
+
# The model command should be registered through the workflow system instead
|
|
24
|
+
import logging
|
|
25
|
+
|
|
26
|
+
_logger = logging.getLogger(__name__)
|
|
27
|
+
_logger.warning(
|
|
28
|
+
"model.json contains executable code - skipping exec() for security. "
|
|
29
|
+
"Use workflow system instead."
|
|
30
|
+
)
|
|
31
|
+
model = list = download = start = recommend = status = stop = pull = delete = None
|
|
56
32
|
else:
|
|
57
33
|
# If the JSON file doesn't exist, create empty placeholders
|
|
58
34
|
print(f"Warning: {model_json_path} not found", file=sys.stderr)
|
|
@@ -696,9 +696,9 @@ def save_script(
|
|
|
696
696
|
with open(script_path, "w") as f:
|
|
697
697
|
f.write(code)
|
|
698
698
|
|
|
699
|
-
# Make executable for shell/python scripts
|
|
699
|
+
# Make executable for shell/python scripts (owner + group, not world)
|
|
700
700
|
if language in (ScriptLanguages.PYTHON, ScriptLanguages.SHELL):
|
|
701
|
-
script_path.chmod(script_path.stat().st_mode | stat.S_IXUSR)
|
|
701
|
+
script_path.chmod(script_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP)
|
|
702
702
|
|
|
703
703
|
return script_path
|
|
704
704
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Onboarding wizard for new MCLI users.
|
|
3
|
+
|
|
4
|
+
Provides interactive and non-interactive setup modes to configure
|
|
5
|
+
MCLI with validated settings.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from rich.prompt import Confirm, Prompt
|
|
13
|
+
from rich.table import Table
|
|
14
|
+
|
|
15
|
+
from mcli.lib.logger.logger import get_logger
|
|
16
|
+
from mcli.lib.ui.styling import console, info, success
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _write_env_file(env_dict: dict, path: Path):
|
|
22
|
+
"""Write a validated env dict to a .env file, preserving existing keys."""
|
|
23
|
+
existing = {}
|
|
24
|
+
if path.exists():
|
|
25
|
+
for line in path.read_text().splitlines():
|
|
26
|
+
line = line.strip()
|
|
27
|
+
if line and not line.startswith("#") and "=" in line:
|
|
28
|
+
key, _, val = line.partition("=")
|
|
29
|
+
existing[key.strip()] = val.strip()
|
|
30
|
+
|
|
31
|
+
merged = {**existing, **env_dict}
|
|
32
|
+
|
|
33
|
+
lines = ["# MCLI Configuration (generated by mcli setup)", ""]
|
|
34
|
+
for key in sorted(merged):
|
|
35
|
+
lines.append(f"{key}={merged[key]}")
|
|
36
|
+
lines.append("")
|
|
37
|
+
|
|
38
|
+
path.write_text("\n".join(lines))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _write_config_toml(included_dirs: list, path: Path):
|
|
42
|
+
"""Write a config.toml with paths configuration."""
|
|
43
|
+
dirs_str = ", ".join(f'"{d}"' for d in included_dirs)
|
|
44
|
+
content = f"""# MCLI Configuration
|
|
45
|
+
# Generated by mcli setup
|
|
46
|
+
|
|
47
|
+
[paths]
|
|
48
|
+
included_dirs = [{dirs_str}]
|
|
49
|
+
"""
|
|
50
|
+
path.write_text(content)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _run_minimal_setup():
|
|
54
|
+
"""Minimal setup: just create directories and default config."""
|
|
55
|
+
from mcli.lib.config.settings import MCLISettings
|
|
56
|
+
|
|
57
|
+
settings = MCLISettings()
|
|
58
|
+
home = settings.home_path
|
|
59
|
+
home.mkdir(parents=True, exist_ok=True)
|
|
60
|
+
(home / "workflows").mkdir(exist_ok=True)
|
|
61
|
+
|
|
62
|
+
config_toml = home / "config.toml"
|
|
63
|
+
if not config_toml.exists():
|
|
64
|
+
_write_config_toml(settings.included_dirs, config_toml)
|
|
65
|
+
|
|
66
|
+
return settings
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _run_interactive_setup():
|
|
70
|
+
"""Interactive setup: ask user for configuration choices."""
|
|
71
|
+
from mcli.lib.config.settings import MCLISettings
|
|
72
|
+
|
|
73
|
+
console.print()
|
|
74
|
+
console.print("[bold cyan]MCLI Setup Wizard[/bold cyan]")
|
|
75
|
+
console.print("[dim]Configure your MCLI installation step by step.[/dim]")
|
|
76
|
+
console.print()
|
|
77
|
+
|
|
78
|
+
env_overrides = {}
|
|
79
|
+
|
|
80
|
+
# Step 1: Environment
|
|
81
|
+
env = Prompt.ask(
|
|
82
|
+
"[cyan]Environment[/cyan]",
|
|
83
|
+
choices=["development", "staging", "production"],
|
|
84
|
+
default="development",
|
|
85
|
+
)
|
|
86
|
+
if env != "development":
|
|
87
|
+
env_overrides["MCLI_ENV"] = env
|
|
88
|
+
|
|
89
|
+
# Step 2: Editor
|
|
90
|
+
default_editor = os.getenv("EDITOR", "vim")
|
|
91
|
+
editor = Prompt.ask("[cyan]Preferred editor[/cyan]", default=default_editor)
|
|
92
|
+
if editor != "vim":
|
|
93
|
+
env_overrides["EDITOR"] = editor
|
|
94
|
+
|
|
95
|
+
# Step 3: API keys (optional)
|
|
96
|
+
console.print()
|
|
97
|
+
console.print("[bold]API Keys[/bold] [dim](optional, press Enter to skip)[/dim]")
|
|
98
|
+
|
|
99
|
+
openai_key = Prompt.ask("[cyan]OpenAI API key[/cyan]", default="", show_default=False)
|
|
100
|
+
if openai_key:
|
|
101
|
+
env_overrides["OPENAI_API_KEY"] = openai_key
|
|
102
|
+
|
|
103
|
+
anthropic_key = Prompt.ask("[cyan]Anthropic API key[/cyan]", default="", show_default=False)
|
|
104
|
+
if anthropic_key:
|
|
105
|
+
env_overrides["ANTHROPIC_API_KEY"] = anthropic_key
|
|
106
|
+
|
|
107
|
+
# Step 4: Debug mode
|
|
108
|
+
console.print()
|
|
109
|
+
if Confirm.ask("[cyan]Enable debug mode?[/cyan]", default=False):
|
|
110
|
+
env_overrides["MCLI_DEBUG"] = "1"
|
|
111
|
+
|
|
112
|
+
# Build validated settings
|
|
113
|
+
settings = MCLISettings(**env_overrides, _env_file=None)
|
|
114
|
+
|
|
115
|
+
# Create directories
|
|
116
|
+
home = settings.home_path
|
|
117
|
+
home.mkdir(parents=True, exist_ok=True)
|
|
118
|
+
(home / "workflows").mkdir(exist_ok=True)
|
|
119
|
+
|
|
120
|
+
# Write config files
|
|
121
|
+
env_dict = settings.to_env_dict()
|
|
122
|
+
env_dict.update({k: v for k, v in env_overrides.items() if k not in env_dict and v})
|
|
123
|
+
|
|
124
|
+
if env_dict:
|
|
125
|
+
env_path = Path.cwd() / ".env"
|
|
126
|
+
_write_env_file(env_dict, env_path)
|
|
127
|
+
console.print(f"[green]\u2713[/green] Wrote .env to {env_path}")
|
|
128
|
+
|
|
129
|
+
config_toml = home / "config.toml"
|
|
130
|
+
if not config_toml.exists():
|
|
131
|
+
_write_config_toml(settings.included_dirs, config_toml)
|
|
132
|
+
console.print(f"[green]\u2713[/green] Wrote config.toml to {config_toml}")
|
|
133
|
+
|
|
134
|
+
return settings
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@click.command("setup")
|
|
138
|
+
@click.option("--minimal", is_flag=True, help="Minimal setup (directories + defaults only)")
|
|
139
|
+
@click.option("--full", is_flag=True, help="Full setup with all optional features")
|
|
140
|
+
def setup(minimal, full):
|
|
141
|
+
"""Interactive setup wizard for new users.
|
|
142
|
+
|
|
143
|
+
Configures MCLI with validated settings, creates necessary directories,
|
|
144
|
+
and writes configuration files.
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
mcli setup # Interactive wizard
|
|
148
|
+
mcli setup --minimal # Directories + defaults only
|
|
149
|
+
mcli setup --full # All features configured
|
|
150
|
+
"""
|
|
151
|
+
from mcli.lib.config.settings import MCLISettings
|
|
152
|
+
|
|
153
|
+
if minimal:
|
|
154
|
+
settings = _run_minimal_setup()
|
|
155
|
+
success("Minimal setup complete!")
|
|
156
|
+
elif full:
|
|
157
|
+
# Full mode: same as interactive but with all prompts
|
|
158
|
+
settings = _run_interactive_setup()
|
|
159
|
+
else:
|
|
160
|
+
settings = _run_interactive_setup()
|
|
161
|
+
|
|
162
|
+
# Summary table
|
|
163
|
+
console.print()
|
|
164
|
+
table = Table(title="Setup Summary", show_header=False)
|
|
165
|
+
table.add_column("Setting", style="cyan")
|
|
166
|
+
table.add_column("Value", style="green")
|
|
167
|
+
|
|
168
|
+
table.add_row("Environment", settings.mcli_env)
|
|
169
|
+
table.add_row("Home Directory", str(settings.home_path))
|
|
170
|
+
table.add_row("Workflows", str(settings.workflows_dir))
|
|
171
|
+
table.add_row("Editor", settings.editor)
|
|
172
|
+
table.add_row("Debug Mode", "Yes" if settings.is_debug else "No")
|
|
173
|
+
table.add_row("OpenAI API", "Configured" if settings.has_api_key("openai") else "Not set")
|
|
174
|
+
table.add_row(
|
|
175
|
+
"Anthropic API",
|
|
176
|
+
"Configured" if settings.has_api_key("anthropic") else "Not set",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
console.print(table)
|
|
180
|
+
console.print()
|
|
181
|
+
|
|
182
|
+
# Next steps
|
|
183
|
+
console.print("[bold]Next Steps:[/bold]")
|
|
184
|
+
console.print(" 1. Initialize workflows: [cyan]mcli init[/cyan]")
|
|
185
|
+
console.print(" 2. Create a command: [cyan]mcli new my-command[/cyan]")
|
|
186
|
+
console.print(" 3. Run a command: [cyan]mcli run my-command[/cyan]")
|
|
187
|
+
console.print()
|