mcli-framework 7.8.5__tar.gz → 7.9.0__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.
Potentially problematic release.
This version of mcli-framework might be problematic. Click here for more details.
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/PKG-INFO +2 -1
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/pyproject.toml +2 -1
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/main.py +9 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/lib.py +8 -1
- mcli_framework-7.9.0/src/mcli/lib/secrets/commands.py +185 -0
- mcli_framework-7.9.0/src/mcli/lib/secrets/manager.py +213 -0
- mcli_framework-7.9.0/src/mcli/lib/secrets/repl.py +297 -0
- mcli_framework-7.9.0/src/mcli/lib/secrets/store.py +246 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/self_cmd.py +8 -0
- mcli_framework-7.9.0/src/mcli/self/zsh_cmd.py +259 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/PKG-INFO +2 -1
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/SOURCES.txt +5 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/requires.txt +1 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/dependabot.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/build.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/ci.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/ml-pipeline.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/publish-self-hosted.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/publish.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/release.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/security.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/.github/workflows/test.yml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/LICENSE +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/MANIFEST.in +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/README.md +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/Cargo.toml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/src/command_parser.rs +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/src/file_watcher.rs +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/src/lib.rs +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/src/process_manager.rs +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/mcli_rust/src/tfidf.rs +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/setup.cfg +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/commands_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/completion_helpers.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/model/model.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/model_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/app/video/video.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/chat/chat.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/chat/command_rag.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/chat/enhanced_chat.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/chat/system_controller.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/chat/system_integration.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/cli.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/config.toml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/api/api.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/api/daemon_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/api/daemon_client_local.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/api/daemon_decorator.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/api/mcli_decorators.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/auth.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/aws_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/azure_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/credential_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/gcp_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/key_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/mcli_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/token_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/auth/token_util.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/config/config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/custom_commands.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/discovery/__init__.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/discovery/command_discovery.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/erd/erd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/erd/generate_graph.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/files/files.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/fs/fs.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/logger/logger.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/paths.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/performance/optimizer.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/performance/rust_bridge.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/performance/uvloop_config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/pickles/pickles.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/search/cached_vectorizer.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/services/data_pipeline.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/services/lsh_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/services/redis_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/shell/shell.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/toml/toml.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/ui/styling.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/ui/visual_effects.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/lib/watcher/watcher.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/app.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/middleware.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/admin_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/auth_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/backtest_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/data_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/model_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/monitoring_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/portfolio_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/prediction_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/trade_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/routers/websocket_router.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/api/schemas.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/auth/auth_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/auth/models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/auth/permissions.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/backtesting/backtest_engine.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/backtesting/performance_metrics.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/cache.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/cli/main.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/config/settings.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/configs/dvc_config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/configs/mlflow_config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/configs/mlops_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/app.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/app_integrated.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/app_supabase.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/app_training.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/cli.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/common.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/components/charts.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/components/metrics.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/components/tables.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/overview.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/cicd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/debug_dependencies.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/gravity_viz.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/monte_carlo_predictions.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/predictions_enhanced.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/scrapers_and_logs.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/test_portfolio.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/trading.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/pages/workflows.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/streamlit_extras_utils.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/styles.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/utils.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/dashboard/warning_suppression.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/data_ingestion/api_connectors.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/data_ingestion/data_pipeline.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/data_ingestion/stream_processor.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/database/migrations/env.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/database/models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/database/session.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/experimentation/ab_testing.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/features/ensemble_features.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/features/political_features.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/features/recommendation_engine.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/features/stock_features.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/features/test_feature_engineering.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/logging.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/mlops/data_versioning.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/mlops/experiment_tracker.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/mlops/model_serving.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/mlops/pipeline_orchestrator.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/models/base_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/models/ensemble_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/models/recommendation_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/models/test_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/monitoring/drift_detection.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/monitoring/metrics.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/optimization/portfolio_optimizer.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/predictions/monte_carlo.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/predictions/prediction_engine.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/preprocessing/data_cleaners.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/preprocessing/feature_extractors.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/preprocessing/ml_pipeline.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/preprocessing/test_preprocessing.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/scripts/populate_sample_data.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/tasks.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/tests/test_integration.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/tests/test_training_dashboard.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/alpaca_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/migrations.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/paper_trading.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/risk_management.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/trading/trading_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/ml/training/train_model.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/mygroup/test_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/public/oi/oi.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/public/public.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/completion_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/logs_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/redis_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/store_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/test_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/self/visual_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/async_command_database.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/async_process_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/daemon.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/daemon_api.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/enhanced_daemon.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/process_cli.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/process_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/daemon/test_daemon.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/dashboard/dashboard_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/docker/docker.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/gcloud/config.toml +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/gcloud/gcloud.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/git_commit/ai_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/lsh_integration.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/download_and_run_efficient_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/lightweight_embedder.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/lightweight_model_server.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/lightweight_test.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/model_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/ollama_efficient_runner.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/openai_adapter.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/pdf_processor.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/test_efficient_runner.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/test_example.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/test_integration.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/model_service/test_new_features.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/openai/openai.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/connectivity.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/data_sources.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/database.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/demo.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/monitoring.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_california.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_corporate_registry.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_eu.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_free_sources.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_third_party.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_uk.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/scrapers_us_states.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/seed_database.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/supabase_functions.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/politician_trading/workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/registry/registry.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/repo/repo.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/scheduler/cron_parser.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/scheduler/job.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/scheduler/monitor.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/scheduler/persistence.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/scheduler/scheduler.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/sync/test_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/wakatime/wakatime.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli/workflow/workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/dependency_links.txt +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/entry_points.txt +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/src/mcli_framework.egg-info/top_level.txt +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_all_commands.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_app_logs_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_app_redis_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_logs_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_main_app.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_model_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_self_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_self_cmd_commands.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_self_cmd_plugins.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_self_cmd_utilities.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_workflow_file.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_workflow_gcloud.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/cli/test_workflow_registry.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/conftest.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/demo_generate_graph.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/demo_hierarchical_transform.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/e2e/test_complete_workflows.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/e2e/test_model_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/e2e/test_new_user_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/e2e/test_update_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/fixtures/chat_fixtures.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/fixtures/cli_fixtures.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/fixtures/data_fixtures.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/fixtures/db_fixtures.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/fixtures/model_fixtures.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_agent.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_california_scraper.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_chat_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_chat_system.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_congress_scraper.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_daemon_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_daemon_server.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_e2e_dashboard_lsh_supabase.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_flask_webapp.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_gcloud_services.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_lsh_client.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_lsh_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_ml_auth.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_ml_data_pipeline.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_ml_models.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_ml_pipeline.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_module_imports.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_oi_service.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_politician_trading.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_repo_operations.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_scheduler_integration.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_service_registry.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_supabase_live_connection.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_uk_scraper.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_us_states_scraper.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_video_processing.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_wakatime_api.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_webapp_full.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/integration/test_workflow_commands.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/run_tests.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/test_harness.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/test_openai_adapter.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_api_utils.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_async_process_manager.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_auth_modules.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_bug_fixes.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_config.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_custom_commands.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_daemon_api.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_dashboard_components.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_dashboard_functions.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_dashboard_pages.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_dependencies.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_emulator_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_erd_generation.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_erd_generic.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_erd_imports.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_git_commit_workflow.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_lib_auth.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_lib_files.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_lib_utils.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_logger.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_ml_preprocessing.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_paths.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_pdf_compress.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_prediction_engine.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_regression.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_scheduler.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_scheduler_cron_parser.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_scheduler_job.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_scheduler_monitor.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_scheduler_persistence.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_self_update.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_store_cmd.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_supabase_connection.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_supabase_pagination.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_toml_utils.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_trading_imports.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_ui_rich.py +0 -0
- {mcli_framework-7.8.5 → mcli_framework-7.9.0}/tests/unit/test_uv_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcli-framework
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.9.0
|
|
4
4
|
Summary: Portable workflow framework - transform any script into a versioned, schedulable command. Store in ~/.mcli/commands/, 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>
|
|
@@ -48,6 +48,7 @@ Requires-Dist: humanize<5.0.0,>=4.9.0
|
|
|
48
48
|
Requires-Dist: psutil<6.0.0,>=5.9.0
|
|
49
49
|
Requires-Dist: inquirerpy<0.4.0,>=0.3.4
|
|
50
50
|
Requires-Dist: gitpython<4.0.0,>=3.1.40
|
|
51
|
+
Requires-Dist: prompt-toolkit<4.0.0,>=3.0.0
|
|
51
52
|
Requires-Dist: aiohttp>=3.9.0
|
|
52
53
|
Requires-Dist: httpx>=0.28.1
|
|
53
54
|
Requires-Dist: websockets>=12.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mcli-framework"
|
|
3
|
-
version = "7.
|
|
3
|
+
version = "7.9.0"
|
|
4
4
|
description = "Portable workflow framework - transform any script into a versioned, schedulable command. Store in ~/.mcli/commands/, version with lockfile, run as daemon or cron job."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.9"
|
|
@@ -49,6 +49,7 @@ dependencies = [
|
|
|
49
49
|
"psutil>=5.9.0,<6.0.0",
|
|
50
50
|
"inquirerpy>=0.3.4,<0.4.0",
|
|
51
51
|
"gitpython>=3.1.40,<4.0.0",
|
|
52
|
+
"prompt-toolkit>=3.0.0,<4.0.0",
|
|
52
53
|
# Basic HTTP/async support
|
|
53
54
|
"aiohttp>=3.9.0",
|
|
54
55
|
"httpx>=0.28.1",
|
|
@@ -344,6 +344,15 @@ def _add_lazy_commands(app: click.Group):
|
|
|
344
344
|
except Exception as e:
|
|
345
345
|
logger.debug(f"Could not load self commands: {e}")
|
|
346
346
|
|
|
347
|
+
# Library utilities and secrets management
|
|
348
|
+
try:
|
|
349
|
+
from mcli.lib.lib import lib
|
|
350
|
+
|
|
351
|
+
app.add_command(lib, name="lib")
|
|
352
|
+
logger.debug("Added lib commands")
|
|
353
|
+
except Exception as e:
|
|
354
|
+
logger.debug(f"Could not load lib commands: {e}")
|
|
355
|
+
|
|
347
356
|
# Add workflow with completion-aware lazy loading
|
|
348
357
|
try:
|
|
349
358
|
from mcli.app.completion_helpers import create_completion_aware_lazy_group
|
|
@@ -3,6 +3,8 @@ import sys
|
|
|
3
3
|
|
|
4
4
|
import click
|
|
5
5
|
|
|
6
|
+
from mcli.lib.secrets.commands import secrets_group
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
def import_public_module(module_name: str):
|
|
8
10
|
prefix = "mcli.public."
|
|
@@ -20,10 +22,15 @@ def import_public_module(module_name: str):
|
|
|
20
22
|
return module
|
|
21
23
|
|
|
22
24
|
|
|
23
|
-
@click.group(name="lib")
|
|
25
|
+
@click.group(name="lib", help="Library utilities and secrets management")
|
|
24
26
|
def lib():
|
|
27
|
+
"""Library utilities and management commands."""
|
|
25
28
|
pass
|
|
26
29
|
|
|
27
30
|
|
|
31
|
+
# Add secrets as a subcommand
|
|
32
|
+
lib.add_command(secrets_group)
|
|
33
|
+
|
|
34
|
+
|
|
28
35
|
if __name__ == "__main__":
|
|
29
36
|
lib()
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI commands for secrets management.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
|
|
10
|
+
from mcli.lib.ui.styling import error, info, success, warning
|
|
11
|
+
|
|
12
|
+
from .manager import SecretsManager
|
|
13
|
+
from .repl import run_repl
|
|
14
|
+
from .store import SecretsStore
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@click.group(name="secrets", help="Secure secrets management with encryption and git sync")
|
|
18
|
+
def secrets_group():
|
|
19
|
+
"""Secrets management commands."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@secrets_group.command(name="repl", help="Launch interactive secrets shell")
|
|
24
|
+
def secrets_repl():
|
|
25
|
+
"""Launch the interactive secrets REPL."""
|
|
26
|
+
run_repl()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@secrets_group.command(name="set", help="Set a secret value")
|
|
30
|
+
@click.argument("key")
|
|
31
|
+
@click.argument("value")
|
|
32
|
+
@click.option("-n", "--namespace", default="default", help="Namespace for the secret")
|
|
33
|
+
def secrets_set(key: str, value: str, namespace: str):
|
|
34
|
+
"""Set a secret value."""
|
|
35
|
+
manager = SecretsManager()
|
|
36
|
+
try:
|
|
37
|
+
manager.set(key, value, namespace)
|
|
38
|
+
success(f"Secret '{key}' set in namespace '{namespace}'")
|
|
39
|
+
except Exception as e:
|
|
40
|
+
error(f"Failed to set secret: {e}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@secrets_group.command(name="get", help="Get a secret value")
|
|
44
|
+
@click.argument("key")
|
|
45
|
+
@click.option("-n", "--namespace", default="default", help="Namespace for the secret")
|
|
46
|
+
@click.option("-s", "--show", is_flag=True, help="Show the full value (not masked)")
|
|
47
|
+
def secrets_get(key: str, namespace: str, show: bool):
|
|
48
|
+
"""Get a secret value."""
|
|
49
|
+
manager = SecretsManager()
|
|
50
|
+
value = manager.get(key, namespace)
|
|
51
|
+
|
|
52
|
+
if value is not None:
|
|
53
|
+
if show:
|
|
54
|
+
click.echo(value)
|
|
55
|
+
else:
|
|
56
|
+
# Mask the value
|
|
57
|
+
masked = (
|
|
58
|
+
value[:3] + "*" * (len(value) - 6) + value[-3:]
|
|
59
|
+
if len(value) > 6
|
|
60
|
+
else "*" * len(value)
|
|
61
|
+
)
|
|
62
|
+
info(f"{key} = {masked}")
|
|
63
|
+
info("Use --show to display the full value")
|
|
64
|
+
else:
|
|
65
|
+
warning(f"Secret '{key}' not found in namespace '{namespace}'")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@secrets_group.command(name="list", help="List all secrets")
|
|
69
|
+
@click.option("-n", "--namespace", help="Filter by namespace")
|
|
70
|
+
def secrets_list(namespace: Optional[str]):
|
|
71
|
+
"""List all secrets."""
|
|
72
|
+
manager = SecretsManager()
|
|
73
|
+
secrets = manager.list(namespace)
|
|
74
|
+
|
|
75
|
+
if secrets:
|
|
76
|
+
info("Secrets:")
|
|
77
|
+
for secret in secrets:
|
|
78
|
+
click.echo(f" • {secret}")
|
|
79
|
+
else:
|
|
80
|
+
info("No secrets found")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@secrets_group.command(name="delete", help="Delete a secret")
|
|
84
|
+
@click.argument("key")
|
|
85
|
+
@click.option("-n", "--namespace", default="default", help="Namespace for the secret")
|
|
86
|
+
@click.confirmation_option(prompt="Are you sure you want to delete this secret?")
|
|
87
|
+
def secrets_delete(key: str, namespace: str):
|
|
88
|
+
"""Delete a secret."""
|
|
89
|
+
manager = SecretsManager()
|
|
90
|
+
if manager.delete(key, namespace):
|
|
91
|
+
success(f"Secret '{key}' deleted from namespace '{namespace}'")
|
|
92
|
+
else:
|
|
93
|
+
warning(f"Secret '{key}' not found in namespace '{namespace}'")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@secrets_group.command(name="export", help="Export secrets as environment variables")
|
|
97
|
+
@click.option("-n", "--namespace", help="Namespace to export")
|
|
98
|
+
@click.option("-o", "--output", type=click.Path(), help="Output file (defaults to stdout)")
|
|
99
|
+
def secrets_export(namespace: Optional[str], output: Optional[str]):
|
|
100
|
+
"""Export secrets as environment variables."""
|
|
101
|
+
manager = SecretsManager()
|
|
102
|
+
env_vars = manager.export_env(namespace)
|
|
103
|
+
|
|
104
|
+
if env_vars:
|
|
105
|
+
if output:
|
|
106
|
+
with open(output, "w") as f:
|
|
107
|
+
for key, value in env_vars.items():
|
|
108
|
+
f.write(f"export {key}={value}\n")
|
|
109
|
+
success(f"Exported {len(env_vars)} secrets to {output}")
|
|
110
|
+
else:
|
|
111
|
+
for key, value in env_vars.items():
|
|
112
|
+
click.echo(f"export {key}={value}")
|
|
113
|
+
else:
|
|
114
|
+
info("No secrets to export")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@secrets_group.command(name="import", help="Import secrets from environment file")
|
|
118
|
+
@click.argument("env_file", type=click.Path(exists=True))
|
|
119
|
+
@click.option("-n", "--namespace", default="default", help="Namespace to import into")
|
|
120
|
+
def secrets_import(env_file: str, namespace: str):
|
|
121
|
+
"""Import secrets from environment file."""
|
|
122
|
+
manager = SecretsManager()
|
|
123
|
+
count = manager.import_env(Path(env_file), namespace)
|
|
124
|
+
success(f"Imported {count} secrets into namespace '{namespace}'")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@secrets_group.group(name="store", help="Git-based secrets synchronization")
|
|
128
|
+
def store_group():
|
|
129
|
+
"""Store management commands."""
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@store_group.command(name="init", help="Initialize secrets store")
|
|
134
|
+
@click.option("-r", "--remote", help="Git remote URL")
|
|
135
|
+
def store_init(remote: Optional[str]):
|
|
136
|
+
"""Initialize the secrets store."""
|
|
137
|
+
store = SecretsStore()
|
|
138
|
+
store.init(remote)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@store_group.command(name="push", help="Push secrets to store")
|
|
142
|
+
@click.option("-m", "--message", help="Commit message")
|
|
143
|
+
def store_push(message: Optional[str]):
|
|
144
|
+
"""Push secrets to store."""
|
|
145
|
+
manager = SecretsManager()
|
|
146
|
+
store = SecretsStore()
|
|
147
|
+
store.push(manager.secrets_dir, message)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@store_group.command(name="pull", help="Pull secrets from store")
|
|
151
|
+
def store_pull():
|
|
152
|
+
"""Pull secrets from store."""
|
|
153
|
+
manager = SecretsManager()
|
|
154
|
+
store = SecretsStore()
|
|
155
|
+
store.pull(manager.secrets_dir)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@store_group.command(name="sync", help="Sync secrets with store")
|
|
159
|
+
@click.option("-m", "--message", help="Commit message")
|
|
160
|
+
def store_sync(message: Optional[str]):
|
|
161
|
+
"""Sync secrets with store."""
|
|
162
|
+
manager = SecretsManager()
|
|
163
|
+
store = SecretsStore()
|
|
164
|
+
store.sync(manager.secrets_dir, message)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@store_group.command(name="status", help="Show store status")
|
|
168
|
+
def store_status():
|
|
169
|
+
"""Show store status."""
|
|
170
|
+
store = SecretsStore()
|
|
171
|
+
status = store.status()
|
|
172
|
+
|
|
173
|
+
info("Secrets Store Status:")
|
|
174
|
+
click.echo(f" Initialized: {status['initialized']}")
|
|
175
|
+
click.echo(f" Path: {status['store_path']}")
|
|
176
|
+
|
|
177
|
+
if status["initialized"]:
|
|
178
|
+
click.echo(f" Branch: {status['branch']}")
|
|
179
|
+
click.echo(f" Commit: {status['commit']}")
|
|
180
|
+
click.echo(f" Clean: {status['clean']}")
|
|
181
|
+
|
|
182
|
+
if status["has_remote"]:
|
|
183
|
+
click.echo(f" Remote: {status['remote_url']}")
|
|
184
|
+
else:
|
|
185
|
+
click.echo(" Remote: Not configured")
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Secrets manager for handling secure storage and retrieval of secrets.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
from cryptography.fernet import Fernet
|
|
13
|
+
from cryptography.hazmat.primitives import hashes
|
|
14
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
15
|
+
|
|
16
|
+
from mcli.lib.logger.logger import get_logger
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SecretsManager:
|
|
22
|
+
"""Manages secrets storage with encryption."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, secrets_dir: Optional[Path] = None):
|
|
25
|
+
"""Initialize the secrets manager.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
secrets_dir: Directory to store secrets. Defaults to ~/.mcli/secrets/
|
|
29
|
+
"""
|
|
30
|
+
self.secrets_dir = secrets_dir or Path.home() / ".mcli" / "secrets"
|
|
31
|
+
self.secrets_dir.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
self._cipher_suite = self._get_cipher_suite()
|
|
33
|
+
|
|
34
|
+
def _get_cipher_suite(self) -> Fernet:
|
|
35
|
+
"""Get or create encryption key."""
|
|
36
|
+
key_file = self.secrets_dir / ".key"
|
|
37
|
+
|
|
38
|
+
if key_file.exists():
|
|
39
|
+
with open(key_file, "rb") as f:
|
|
40
|
+
key = f.read()
|
|
41
|
+
else:
|
|
42
|
+
# Generate a new key from a password
|
|
43
|
+
password = click.prompt("Enter a password for secrets encryption", hide_input=True)
|
|
44
|
+
password_bytes = password.encode()
|
|
45
|
+
|
|
46
|
+
# Use PBKDF2 to derive a key from the password
|
|
47
|
+
kdf = PBKDF2HMAC(
|
|
48
|
+
algorithm=hashes.SHA256(),
|
|
49
|
+
length=32,
|
|
50
|
+
salt=b"mcli-secrets-salt", # In production, use a random salt
|
|
51
|
+
iterations=100000,
|
|
52
|
+
)
|
|
53
|
+
key = base64.urlsafe_b64encode(kdf.derive(password_bytes))
|
|
54
|
+
|
|
55
|
+
# Save the key (in production, this should be stored more securely)
|
|
56
|
+
with open(key_file, "wb") as f:
|
|
57
|
+
f.write(key)
|
|
58
|
+
|
|
59
|
+
# Set restrictive permissions
|
|
60
|
+
os.chmod(key_file, 0o600)
|
|
61
|
+
|
|
62
|
+
return Fernet(key)
|
|
63
|
+
|
|
64
|
+
def set(self, key: str, value: str, namespace: Optional[str] = None) -> None:
|
|
65
|
+
"""Set a secret value.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
key: Secret key
|
|
69
|
+
value: Secret value
|
|
70
|
+
namespace: Optional namespace for grouping secrets
|
|
71
|
+
"""
|
|
72
|
+
namespace = namespace or "default"
|
|
73
|
+
namespace_dir = self.secrets_dir / namespace
|
|
74
|
+
namespace_dir.mkdir(exist_ok=True)
|
|
75
|
+
|
|
76
|
+
# Encrypt the value
|
|
77
|
+
encrypted_value = self._cipher_suite.encrypt(value.encode())
|
|
78
|
+
|
|
79
|
+
# Store the encrypted value
|
|
80
|
+
secret_file = namespace_dir / f"{key}.secret"
|
|
81
|
+
with open(secret_file, "wb") as f:
|
|
82
|
+
f.write(encrypted_value)
|
|
83
|
+
|
|
84
|
+
# Set restrictive permissions
|
|
85
|
+
os.chmod(secret_file, 0o600)
|
|
86
|
+
|
|
87
|
+
logger.debug(f"Secret '{key}' stored in namespace '{namespace}'")
|
|
88
|
+
|
|
89
|
+
def get(self, key: str, namespace: Optional[str] = None) -> Optional[str]:
|
|
90
|
+
"""Get a secret value.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
key: Secret key
|
|
94
|
+
namespace: Optional namespace
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Decrypted secret value or None if not found
|
|
98
|
+
"""
|
|
99
|
+
namespace = namespace or "default"
|
|
100
|
+
secret_file = self.secrets_dir / namespace / f"{key}.secret"
|
|
101
|
+
|
|
102
|
+
if not secret_file.exists():
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
with open(secret_file, "rb") as f:
|
|
106
|
+
encrypted_value = f.read()
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
decrypted_value = self._cipher_suite.decrypt(encrypted_value)
|
|
110
|
+
return decrypted_value.decode()
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"Failed to decrypt secret '{key}': {e}")
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def list(self, namespace: Optional[str] = None) -> List[str]:
|
|
116
|
+
"""List all secret keys.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
namespace: Optional namespace filter
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
List of secret keys
|
|
123
|
+
"""
|
|
124
|
+
if namespace:
|
|
125
|
+
namespace_dirs = [self.secrets_dir / namespace]
|
|
126
|
+
else:
|
|
127
|
+
namespace_dirs = [
|
|
128
|
+
d for d in self.secrets_dir.iterdir() if d.is_dir() and not d.name.startswith(".")
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
secrets = []
|
|
132
|
+
for namespace_dir in namespace_dirs:
|
|
133
|
+
if namespace_dir.exists():
|
|
134
|
+
for secret_file in namespace_dir.glob("*.secret"):
|
|
135
|
+
key = secret_file.stem
|
|
136
|
+
ns = namespace_dir.name
|
|
137
|
+
secrets.append(f"{ns}/{key}" if not namespace else key)
|
|
138
|
+
|
|
139
|
+
return sorted(secrets)
|
|
140
|
+
|
|
141
|
+
def delete(self, key: str, namespace: Optional[str] = None) -> bool:
|
|
142
|
+
"""Delete a secret.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
key: Secret key
|
|
146
|
+
namespace: Optional namespace
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
True if deleted, False if not found
|
|
150
|
+
"""
|
|
151
|
+
namespace = namespace or "default"
|
|
152
|
+
secret_file = self.secrets_dir / namespace / f"{key}.secret"
|
|
153
|
+
|
|
154
|
+
if secret_file.exists():
|
|
155
|
+
secret_file.unlink()
|
|
156
|
+
logger.debug(f"Secret '{key}' deleted from namespace '{namespace}'")
|
|
157
|
+
return True
|
|
158
|
+
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
def export_env(self, namespace: Optional[str] = None) -> Dict[str, str]:
|
|
162
|
+
"""Export secrets as environment variables.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
namespace: Optional namespace filter
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dictionary of key-value pairs
|
|
169
|
+
"""
|
|
170
|
+
env_vars = {}
|
|
171
|
+
|
|
172
|
+
for secret_key in self.list(namespace):
|
|
173
|
+
if "/" in secret_key:
|
|
174
|
+
ns, key = secret_key.split("/", 1)
|
|
175
|
+
value = self.get(key, ns)
|
|
176
|
+
else:
|
|
177
|
+
value = self.get(secret_key, namespace)
|
|
178
|
+
|
|
179
|
+
if value:
|
|
180
|
+
# Convert to uppercase for environment variable convention
|
|
181
|
+
if "/" in secret_key:
|
|
182
|
+
env_key = key.upper().replace("-", "_")
|
|
183
|
+
else:
|
|
184
|
+
env_key = secret_key.upper().replace("-", "_")
|
|
185
|
+
env_vars[env_key] = value
|
|
186
|
+
|
|
187
|
+
return env_vars
|
|
188
|
+
|
|
189
|
+
def import_env(self, env_file: Path, namespace: Optional[str] = None) -> int:
|
|
190
|
+
"""Import secrets from an environment file.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
env_file: Path to .env file
|
|
194
|
+
namespace: Optional namespace
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Number of secrets imported
|
|
198
|
+
"""
|
|
199
|
+
namespace = namespace or "default"
|
|
200
|
+
count = 0
|
|
201
|
+
|
|
202
|
+
with open(env_file) as f:
|
|
203
|
+
for line in f:
|
|
204
|
+
line = line.strip()
|
|
205
|
+
if line and not line.startswith("#") and "=" in line:
|
|
206
|
+
key, value = line.split("=", 1)
|
|
207
|
+
key = key.strip()
|
|
208
|
+
value = value.strip().strip('"').strip("'")
|
|
209
|
+
|
|
210
|
+
self.set(key.lower().replace("_", "-"), value, namespace)
|
|
211
|
+
count += 1
|
|
212
|
+
|
|
213
|
+
return count
|