mcli-framework 7.9.1__tar.gz → 7.9.5__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.9.1 → mcli_framework-7.9.5}/PKG-INFO +1 -1
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/pyproject.toml +1 -1
- mcli_framework-7.9.5/src/mcli/workflow/doc_convert.py +666 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/PKG-INFO +1 -1
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/SOURCES.txt +2 -0
- mcli_framework-7.9.5/tests/unit/test_doc_convert_workflow.py +290 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/dependabot.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/build.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/ci.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/ml-pipeline.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/publish-self-hosted.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/publish.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/release.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/security.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/.github/workflows/test.yml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/LICENSE +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/MANIFEST.in +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/README.md +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/Cargo.toml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/src/command_parser.rs +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/src/file_watcher.rs +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/src/lib.rs +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/src/process_manager.rs +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/mcli_rust/src/tfidf.rs +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/setup.cfg +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/commands_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/completion_helpers.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/main.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/model/model.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/model_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/app/video/video.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/chat/chat.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/chat/command_rag.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/chat/enhanced_chat.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/chat/system_controller.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/chat/system_integration.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/cli.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/config.toml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/api/api.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/api/daemon_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/api/daemon_client_local.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/api/daemon_decorator.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/api/mcli_decorators.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/auth.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/aws_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/azure_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/credential_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/gcp_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/key_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/mcli_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/token_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/auth/token_util.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/config/config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/custom_commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/discovery/__init__.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/discovery/command_discovery.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/erd/erd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/erd/generate_graph.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/files/files.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/fs/fs.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/lib.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/logger/logger.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/paths.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/performance/optimizer.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/performance/rust_bridge.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/performance/uvloop_config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/pickles/pickles.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/search/cached_vectorizer.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/secrets/commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/secrets/manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/secrets/repl.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/secrets/store.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/services/data_pipeline.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/services/lsh_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/services/redis_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/shell/shell.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/toml/toml.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/ui/styling.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/ui/visual_effects.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/lib/watcher/watcher.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/app.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/middleware.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/admin_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/auth_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/backtest_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/data_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/model_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/monitoring_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/portfolio_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/prediction_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/trade_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/routers/websocket_router.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/api/schemas.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/auth/auth_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/auth/models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/auth/permissions.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/backtesting/backtest_engine.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/backtesting/performance_metrics.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/backtesting/run.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/cache.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/cli/main.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/config/settings.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/configs/dvc_config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/configs/mlflow_config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/configs/mlops_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/app.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/app_integrated.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/app_supabase.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/app_training.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/cli.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/common.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/components/charts.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/components/metrics.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/components/tables.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/overview.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/cicd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/debug_dependencies.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/gravity_viz.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/monte_carlo_predictions.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/predictions_enhanced.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/scrapers_and_logs.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/test_portfolio.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/trading.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/pages/workflows.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/streamlit_extras_utils.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/styles.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/utils.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/dashboard/warning_suppression.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/data_ingestion/api_connectors.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/data_ingestion/data_pipeline.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/data_ingestion/stream_processor.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/database/migrations/env.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/database/models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/database/session.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/experimentation/ab_testing.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/features/ensemble_features.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/features/political_features.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/features/recommendation_engine.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/features/stock_features.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/features/test_feature_engineering.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/logging.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/mlops/data_versioning.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/mlops/experiment_tracker.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/mlops/model_serving.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/mlops/pipeline_orchestrator.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/models/base_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/models/ensemble_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/models/recommendation_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/models/test_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/monitoring/drift_detection.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/monitoring/metrics.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/optimization/optimize.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/optimization/portfolio_optimizer.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/predictions/monte_carlo.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/predictions/prediction_engine.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/preprocessing/data_cleaners.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/preprocessing/feature_extractors.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/preprocessing/ml_pipeline.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/preprocessing/politician_trading_preprocessor.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/preprocessing/test_preprocessing.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/scripts/populate_sample_data.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/serving/serve.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/tasks.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/tests/test_integration.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/tests/test_training_dashboard.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/alpaca_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/migrations.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/paper_trading.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/risk_management.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/trading/trading_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/training/train.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/ml/training/train_model.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/mygroup/test_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/public/oi/oi.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/public/public.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/completion_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/logs_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/redis_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/self_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/store_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/test_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/visual_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/self/zsh_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/async_command_database.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/async_process_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/daemon.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/daemon_api.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/enhanced_daemon.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/process_cli.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/process_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/daemon/test_daemon.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/dashboard/dashboard_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/docker/docker.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/gcloud/config.toml +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/gcloud/gcloud.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/git_commit/ai_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/lsh_integration.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/download_and_run_efficient_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/lightweight_embedder.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/lightweight_model_server.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/lightweight_test.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/model_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/ollama_efficient_runner.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/openai_adapter.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/pdf_processor.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/test_efficient_runner.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/test_example.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/test_integration.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/model_service/test_new_features.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/openai/openai.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/connectivity.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/data_sources.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/database.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/demo.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/monitoring.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_california.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_corporate_registry.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_eu.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_free_sources.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_third_party.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_uk.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/scrapers_us_states.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/seed_database.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/supabase_functions.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/politician_trading/workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/registry/registry.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/repo/repo.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/scheduler/cron_parser.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/scheduler/job.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/scheduler/monitor.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/scheduler/persistence.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/scheduler/scheduler.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/sync/test_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/wakatime/wakatime.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli/workflow/workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/dependency_links.txt +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/entry_points.txt +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/requires.txt +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/src/mcli_framework.egg-info/top_level.txt +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_all_commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_app_logs_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_app_redis_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_logs_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_main_app.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_model_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_self_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_self_cmd_commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_self_cmd_plugins.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_self_cmd_utilities.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_workflow_file.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_workflow_gcloud.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/cli/test_workflow_registry.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/conftest.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/demo_generate_graph.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/demo_hierarchical_transform.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/e2e/test_complete_workflows.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/e2e/test_model_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/e2e/test_new_user_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/e2e/test_update_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/fixtures/chat_fixtures.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/fixtures/cli_fixtures.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/fixtures/data_fixtures.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/fixtures/db_fixtures.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/fixtures/model_fixtures.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_agent.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_california_scraper.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_chat_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_chat_system.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_congress_scraper.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_daemon_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_daemon_server.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_e2e_dashboard_lsh_supabase.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_flask_webapp.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_gcloud_services.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_lsh_client.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_lsh_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_ml_auth.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_ml_data_pipeline.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_ml_models.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_ml_pipeline.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_module_imports.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_oi_service.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_politician_trading.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_repo_operations.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_scheduler_integration.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_service_registry.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_supabase_live_connection.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_uk_scraper.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_us_states_scraper.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_video_processing.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_wakatime_api.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_webapp_full.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/integration/test_workflow_commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/run_tests.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/test_harness.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/test_openai_adapter.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_api_utils.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_async_process_manager.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_auth_modules.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_bug_fixes.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_config.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_custom_commands.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_daemon_api.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_dashboard_components.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_dashboard_functions.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_dashboard_pages.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_dependencies.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_emulator_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_erd_generation.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_erd_generic.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_erd_imports.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_git_commit_workflow.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_lib_auth.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_lib_files.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_lib_utils.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_logger.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_ml_preprocessing.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_paths.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_pdf_compress.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_prediction_engine.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_regression.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_scheduler.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_scheduler_cron_parser.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_scheduler_job.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_scheduler_monitor.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_scheduler_persistence.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_self_update.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_store_cmd.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_supabase_connection.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_supabase_pagination.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_toml_utils.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_trading_imports.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/tests/unit/test_ui_rich.py +0 -0
- {mcli_framework-7.9.1 → mcli_framework-7.9.5}/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.9.
|
|
3
|
+
Version: 7.9.5
|
|
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>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mcli-framework"
|
|
3
|
-
version = "7.9.
|
|
3
|
+
version = "7.9.5"
|
|
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"
|
|
@@ -0,0 +1,666 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Document conversion workflow with multiple fallback strategies and temp directory isolation.
|
|
3
|
+
|
|
4
|
+
A robust wrapper around pandoc, nbconvert, and other conversion tools
|
|
5
|
+
with automatic fallback to alternative methods when the primary method fails.
|
|
6
|
+
Uses temporary directory with hard links to avoid path issues.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import shutil
|
|
11
|
+
import subprocess
|
|
12
|
+
import tempfile
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from glob import glob as file_glob
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import List, Optional, Tuple
|
|
18
|
+
|
|
19
|
+
import click
|
|
20
|
+
|
|
21
|
+
from mcli.lib.logger.logger import get_logger
|
|
22
|
+
from mcli.lib.paths import get_custom_commands_dir
|
|
23
|
+
from mcli.lib.ui.styling import error, info, success, warning
|
|
24
|
+
|
|
25
|
+
logger = get_logger()
|
|
26
|
+
|
|
27
|
+
# Format aliases to handle common abbreviations and file extensions
|
|
28
|
+
FORMAT_ALIASES = {
|
|
29
|
+
# Markdown variants
|
|
30
|
+
"md": "markdown",
|
|
31
|
+
"markdown": "markdown",
|
|
32
|
+
"gfm": "gfm", # GitHub Flavored Markdown
|
|
33
|
+
# Document formats
|
|
34
|
+
"doc": "docx",
|
|
35
|
+
"docx": "docx",
|
|
36
|
+
"odt": "odt",
|
|
37
|
+
# Markup formats
|
|
38
|
+
"html": "html",
|
|
39
|
+
"htm": "html",
|
|
40
|
+
"xhtml": "html",
|
|
41
|
+
# PDF
|
|
42
|
+
"pdf": "pdf",
|
|
43
|
+
# LaTeX
|
|
44
|
+
"tex": "latex",
|
|
45
|
+
"latex": "latex",
|
|
46
|
+
# Jupyter
|
|
47
|
+
"ipynb": "ipynb",
|
|
48
|
+
"notebook": "ipynb",
|
|
49
|
+
# Text formats
|
|
50
|
+
"txt": "plain",
|
|
51
|
+
"text": "plain",
|
|
52
|
+
"plain": "plain",
|
|
53
|
+
# Presentation formats
|
|
54
|
+
"pptx": "pptx",
|
|
55
|
+
"ppt": "pptx",
|
|
56
|
+
# Other formats
|
|
57
|
+
"rst": "rst",
|
|
58
|
+
"org": "org",
|
|
59
|
+
"mediawiki": "mediawiki",
|
|
60
|
+
"textile": "textile",
|
|
61
|
+
"rtf": "rtf",
|
|
62
|
+
"epub": "epub",
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ConversionMethod(Enum):
|
|
67
|
+
"""Available conversion methods"""
|
|
68
|
+
PANDOC = "pandoc"
|
|
69
|
+
NBCONVERT = "nbconvert"
|
|
70
|
+
PANDOC_LATEX = "pandoc_latex"
|
|
71
|
+
PANDOC_HTML_INTERMEDIATE = "pandoc_html_intermediate"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class ConversionStrategy:
|
|
76
|
+
"""Represents a conversion strategy with command and description"""
|
|
77
|
+
method: ConversionMethod
|
|
78
|
+
description: str
|
|
79
|
+
check_command: Optional[str] = None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_temp_conversion_dir() -> Path:
|
|
83
|
+
"""Get or create temporary conversion directory in ~/.mcli/commands/temp/"""
|
|
84
|
+
commands_dir = get_custom_commands_dir()
|
|
85
|
+
temp_dir = commands_dir / "temp" / "conversions"
|
|
86
|
+
temp_dir.mkdir(parents=True, exist_ok=True)
|
|
87
|
+
return temp_dir
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def create_temp_hardlink(source_path: Path) -> Tuple[Path, Path]:
|
|
91
|
+
"""
|
|
92
|
+
Create a hard link to the source file in temp directory.
|
|
93
|
+
|
|
94
|
+
Returns: (temp_file_path, temp_dir_path)
|
|
95
|
+
"""
|
|
96
|
+
temp_base = get_temp_conversion_dir()
|
|
97
|
+
|
|
98
|
+
# Create unique temp directory for this conversion
|
|
99
|
+
temp_dir = temp_base / f"conv_{os.getpid()}_{source_path.stem}"
|
|
100
|
+
temp_dir.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
|
|
102
|
+
# Create hard link with simple name (avoids path issues)
|
|
103
|
+
temp_file = temp_dir / source_path.name
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
# Try hard link first (most efficient)
|
|
107
|
+
os.link(source_path, temp_file)
|
|
108
|
+
logger.debug(f"Created hard link: {temp_file}")
|
|
109
|
+
except (OSError, NotImplementedError):
|
|
110
|
+
# Fall back to copy if hard link not supported (e.g., across filesystems)
|
|
111
|
+
shutil.copy2(source_path, temp_file)
|
|
112
|
+
logger.debug(f"Created copy (hard link not available): {temp_file}")
|
|
113
|
+
|
|
114
|
+
return temp_file, temp_dir
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def cleanup_temp_conversion(temp_dir: Path, preserve_output: Optional[Path] = None):
|
|
118
|
+
"""
|
|
119
|
+
Clean up temporary conversion directory.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
temp_dir: Temporary directory to clean up
|
|
123
|
+
preserve_output: If specified, copy this file out before cleanup
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
if preserve_output and preserve_output.exists():
|
|
127
|
+
# Output file is already in temp_dir, we'll handle it separately
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
# Remove the entire temp directory
|
|
131
|
+
if temp_dir.exists():
|
|
132
|
+
shutil.rmtree(temp_dir)
|
|
133
|
+
logger.debug(f"Cleaned up temp directory: {temp_dir}")
|
|
134
|
+
except Exception as e:
|
|
135
|
+
logger.warning(f"Failed to clean up temp directory {temp_dir}: {e}")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_conversion_strategies(
|
|
139
|
+
input_path: Path,
|
|
140
|
+
output_path: Path,
|
|
141
|
+
from_format: str,
|
|
142
|
+
to_format: str,
|
|
143
|
+
pandoc_args: str = ""
|
|
144
|
+
) -> List[ConversionStrategy]:
|
|
145
|
+
"""
|
|
146
|
+
Get ordered list of conversion strategies to try based on input/output formats.
|
|
147
|
+
|
|
148
|
+
Returns strategies in priority order (most likely to succeed first).
|
|
149
|
+
"""
|
|
150
|
+
strategies = []
|
|
151
|
+
|
|
152
|
+
# Special handling for Jupyter notebook to PDF (notoriously problematic)
|
|
153
|
+
if from_format == "ipynb" and to_format == "pdf":
|
|
154
|
+
# Strategy 1: nbconvert (most reliable for notebooks)
|
|
155
|
+
strategies.append(ConversionStrategy(
|
|
156
|
+
method=ConversionMethod.NBCONVERT,
|
|
157
|
+
description="jupyter nbconvert (best for notebooks)",
|
|
158
|
+
check_command="jupyter-nbconvert"
|
|
159
|
+
))
|
|
160
|
+
|
|
161
|
+
# Strategy 2: pandoc with pdflatex
|
|
162
|
+
strategies.append(ConversionStrategy(
|
|
163
|
+
method=ConversionMethod.PANDOC_LATEX,
|
|
164
|
+
description="pandoc with pdflatex engine"
|
|
165
|
+
))
|
|
166
|
+
|
|
167
|
+
# Strategy 3: pandoc via HTML intermediate
|
|
168
|
+
strategies.append(ConversionStrategy(
|
|
169
|
+
method=ConversionMethod.PANDOC_HTML_INTERMEDIATE,
|
|
170
|
+
description="pandoc via HTML intermediate (wkhtmltopdf)"
|
|
171
|
+
))
|
|
172
|
+
|
|
173
|
+
# Strategy 4: standard pandoc
|
|
174
|
+
strategies.append(ConversionStrategy(
|
|
175
|
+
method=ConversionMethod.PANDOC,
|
|
176
|
+
description="pandoc default method"
|
|
177
|
+
))
|
|
178
|
+
|
|
179
|
+
# Jupyter to other formats
|
|
180
|
+
elif from_format == "ipynb":
|
|
181
|
+
# Try nbconvert first for notebooks
|
|
182
|
+
strategies.append(ConversionStrategy(
|
|
183
|
+
method=ConversionMethod.NBCONVERT,
|
|
184
|
+
description="jupyter nbconvert",
|
|
185
|
+
check_command="jupyter-nbconvert"
|
|
186
|
+
))
|
|
187
|
+
strategies.append(ConversionStrategy(
|
|
188
|
+
method=ConversionMethod.PANDOC,
|
|
189
|
+
description="pandoc"
|
|
190
|
+
))
|
|
191
|
+
|
|
192
|
+
# PDF output (general)
|
|
193
|
+
elif to_format == "pdf":
|
|
194
|
+
strategies.append(ConversionStrategy(
|
|
195
|
+
method=ConversionMethod.PANDOC_LATEX,
|
|
196
|
+
description="pandoc with LaTeX"
|
|
197
|
+
))
|
|
198
|
+
strategies.append(ConversionStrategy(
|
|
199
|
+
method=ConversionMethod.PANDOC,
|
|
200
|
+
description="pandoc default"
|
|
201
|
+
))
|
|
202
|
+
|
|
203
|
+
# Default: just use pandoc
|
|
204
|
+
else:
|
|
205
|
+
strategies.append(ConversionStrategy(
|
|
206
|
+
method=ConversionMethod.PANDOC,
|
|
207
|
+
description="pandoc"
|
|
208
|
+
))
|
|
209
|
+
|
|
210
|
+
return strategies
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def execute_conversion_strategy(
|
|
214
|
+
strategy: ConversionStrategy,
|
|
215
|
+
input_path: Path,
|
|
216
|
+
output_path: Path,
|
|
217
|
+
from_format: str,
|
|
218
|
+
to_format: str,
|
|
219
|
+
pandoc_args: str = ""
|
|
220
|
+
) -> Tuple[bool, str]:
|
|
221
|
+
"""
|
|
222
|
+
Execute a specific conversion strategy in a temp directory.
|
|
223
|
+
|
|
224
|
+
Returns: (success: bool, error_message: str)
|
|
225
|
+
"""
|
|
226
|
+
# Create temp hard link for conversion
|
|
227
|
+
temp_input, temp_dir = create_temp_hardlink(input_path)
|
|
228
|
+
temp_output = temp_dir / f"{input_path.stem}.{to_format.lower()}"
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
if strategy.method == ConversionMethod.NBCONVERT:
|
|
232
|
+
# Check if nbconvert is available
|
|
233
|
+
check = subprocess.run(
|
|
234
|
+
["jupyter", "nbconvert", "--version"],
|
|
235
|
+
capture_output=True,
|
|
236
|
+
timeout=5
|
|
237
|
+
)
|
|
238
|
+
if check.returncode != 0:
|
|
239
|
+
return False, "jupyter nbconvert not available"
|
|
240
|
+
|
|
241
|
+
# Build nbconvert command (run in temp directory)
|
|
242
|
+
cmd = [
|
|
243
|
+
"jupyter", "nbconvert",
|
|
244
|
+
"--to", to_format,
|
|
245
|
+
"--output", str(temp_output),
|
|
246
|
+
str(temp_input)
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
# Run in temp directory
|
|
250
|
+
result = subprocess.run(
|
|
251
|
+
cmd,
|
|
252
|
+
capture_output=True,
|
|
253
|
+
text=True,
|
|
254
|
+
check=True,
|
|
255
|
+
timeout=120,
|
|
256
|
+
cwd=str(temp_dir)
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
elif strategy.method == ConversionMethod.PANDOC_LATEX:
|
|
260
|
+
# Pandoc with explicit LaTeX engine
|
|
261
|
+
cmd = [
|
|
262
|
+
"pandoc",
|
|
263
|
+
str(temp_input),
|
|
264
|
+
"-f", from_format,
|
|
265
|
+
"-t", "latex" if to_format == "pdf" else to_format,
|
|
266
|
+
"-o", str(temp_output),
|
|
267
|
+
"--pdf-engine=pdflatex"
|
|
268
|
+
]
|
|
269
|
+
if pandoc_args:
|
|
270
|
+
cmd.extend(pandoc_args.split())
|
|
271
|
+
|
|
272
|
+
result = subprocess.run(
|
|
273
|
+
cmd,
|
|
274
|
+
capture_output=True,
|
|
275
|
+
text=True,
|
|
276
|
+
check=True,
|
|
277
|
+
timeout=120,
|
|
278
|
+
cwd=str(temp_dir)
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
elif strategy.method == ConversionMethod.PANDOC_HTML_INTERMEDIATE:
|
|
282
|
+
# Convert to HTML first, then to PDF
|
|
283
|
+
html_temp = temp_dir / f"{input_path.stem}_temp.html"
|
|
284
|
+
|
|
285
|
+
# Step 1: Convert to HTML
|
|
286
|
+
cmd_html = [
|
|
287
|
+
"pandoc",
|
|
288
|
+
str(temp_input),
|
|
289
|
+
"-f", from_format,
|
|
290
|
+
"-t", "html",
|
|
291
|
+
"-o", str(html_temp),
|
|
292
|
+
"--standalone"
|
|
293
|
+
]
|
|
294
|
+
result = subprocess.run(
|
|
295
|
+
cmd_html,
|
|
296
|
+
capture_output=True,
|
|
297
|
+
text=True,
|
|
298
|
+
timeout=120,
|
|
299
|
+
cwd=str(temp_dir)
|
|
300
|
+
)
|
|
301
|
+
if result.returncode != 0:
|
|
302
|
+
return False, f"HTML intermediate failed: {result.stderr}"
|
|
303
|
+
|
|
304
|
+
# Step 2: Convert HTML to PDF
|
|
305
|
+
cmd = [
|
|
306
|
+
"pandoc",
|
|
307
|
+
str(html_temp),
|
|
308
|
+
"-f", "html",
|
|
309
|
+
"-t", "pdf",
|
|
310
|
+
"-o", str(temp_output)
|
|
311
|
+
]
|
|
312
|
+
|
|
313
|
+
result = subprocess.run(
|
|
314
|
+
cmd,
|
|
315
|
+
capture_output=True,
|
|
316
|
+
text=True,
|
|
317
|
+
check=True,
|
|
318
|
+
timeout=120,
|
|
319
|
+
cwd=str(temp_dir)
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
else: # PANDOC
|
|
323
|
+
# Standard pandoc conversion
|
|
324
|
+
cmd = [
|
|
325
|
+
"pandoc",
|
|
326
|
+
str(temp_input),
|
|
327
|
+
"-f", from_format,
|
|
328
|
+
"-t", to_format,
|
|
329
|
+
"-o", str(temp_output)
|
|
330
|
+
]
|
|
331
|
+
if pandoc_args:
|
|
332
|
+
cmd.extend(pandoc_args.split())
|
|
333
|
+
|
|
334
|
+
result = subprocess.run(
|
|
335
|
+
cmd,
|
|
336
|
+
capture_output=True,
|
|
337
|
+
text=True,
|
|
338
|
+
check=True,
|
|
339
|
+
timeout=120,
|
|
340
|
+
cwd=str(temp_dir)
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# Copy output file to final destination
|
|
344
|
+
if temp_output.exists():
|
|
345
|
+
shutil.copy2(temp_output, output_path)
|
|
346
|
+
return True, ""
|
|
347
|
+
else:
|
|
348
|
+
return False, "Output file not created"
|
|
349
|
+
|
|
350
|
+
except subprocess.TimeoutExpired:
|
|
351
|
+
return False, "Conversion timed out (>120s)"
|
|
352
|
+
except subprocess.CalledProcessError as e:
|
|
353
|
+
return False, e.stderr or str(e)
|
|
354
|
+
except Exception as e:
|
|
355
|
+
return False, str(e)
|
|
356
|
+
finally:
|
|
357
|
+
# Always clean up temp directory
|
|
358
|
+
cleanup_temp_conversion(temp_dir)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
@click.group(name="doc-convert")
|
|
362
|
+
def doc_convert():
|
|
363
|
+
"""Document conversion with automatic fallback strategies"""
|
|
364
|
+
pass
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@doc_convert.command()
|
|
368
|
+
def init():
|
|
369
|
+
"""
|
|
370
|
+
Install all necessary dependencies for document conversion via Homebrew.
|
|
371
|
+
|
|
372
|
+
This will install:
|
|
373
|
+
- pandoc: Universal document converter
|
|
374
|
+
- basictex: LaTeX distribution for PDF generation
|
|
375
|
+
- jupyter & nbconvert: Best for converting Jupyter notebooks
|
|
376
|
+
"""
|
|
377
|
+
info("=" * 60)
|
|
378
|
+
info("📦 Installing doc-convert dependencies")
|
|
379
|
+
info("=" * 60)
|
|
380
|
+
info("")
|
|
381
|
+
|
|
382
|
+
# Check if Homebrew is installed
|
|
383
|
+
try:
|
|
384
|
+
subprocess.run(["brew", "--version"], capture_output=True, check=True)
|
|
385
|
+
success("✅ Homebrew is installed")
|
|
386
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
387
|
+
error("❌ Homebrew is not installed. Install it from https://brew.sh")
|
|
388
|
+
return
|
|
389
|
+
|
|
390
|
+
info("")
|
|
391
|
+
|
|
392
|
+
# Install pandoc
|
|
393
|
+
info("📥 Installing pandoc...")
|
|
394
|
+
try:
|
|
395
|
+
result = subprocess.run(["brew", "install", "pandoc"], capture_output=True, text=True)
|
|
396
|
+
if result.returncode == 0:
|
|
397
|
+
success(" ✅ pandoc installed successfully")
|
|
398
|
+
else:
|
|
399
|
+
check = subprocess.run(["which", "pandoc"], capture_output=True)
|
|
400
|
+
if check.returncode == 0:
|
|
401
|
+
info(" ℹ️ pandoc is already installed")
|
|
402
|
+
else:
|
|
403
|
+
error(f" ❌ Failed to install pandoc: {result.stderr}")
|
|
404
|
+
except Exception as e:
|
|
405
|
+
error(f" ❌ Error installing pandoc: {e}")
|
|
406
|
+
|
|
407
|
+
info("")
|
|
408
|
+
|
|
409
|
+
# Install Jupyter and nbconvert
|
|
410
|
+
info("📥 Installing Jupyter & nbconvert (for notebook conversion)...")
|
|
411
|
+
try:
|
|
412
|
+
# Check if already installed
|
|
413
|
+
check = subprocess.run(["jupyter", "nbconvert", "--version"], capture_output=True)
|
|
414
|
+
if check.returncode == 0:
|
|
415
|
+
info(" ℹ️ jupyter nbconvert is already installed")
|
|
416
|
+
else:
|
|
417
|
+
# Try installing via pip
|
|
418
|
+
result = subprocess.run(
|
|
419
|
+
["pip3", "install", "jupyter", "nbconvert"],
|
|
420
|
+
capture_output=True,
|
|
421
|
+
text=True
|
|
422
|
+
)
|
|
423
|
+
if result.returncode == 0:
|
|
424
|
+
success(" ✅ jupyter & nbconvert installed successfully")
|
|
425
|
+
else:
|
|
426
|
+
warning(" ⚠️ Could not install jupyter via pip")
|
|
427
|
+
info(" ℹ️ You can install manually: pip3 install jupyter nbconvert")
|
|
428
|
+
except Exception as e:
|
|
429
|
+
warning(f" ⚠️ Error installing jupyter: {e}")
|
|
430
|
+
info(" ℹ️ Jupyter is optional but recommended for .ipynb conversions")
|
|
431
|
+
|
|
432
|
+
info("")
|
|
433
|
+
|
|
434
|
+
# Install BasicTeX (lightweight LaTeX for PDF support)
|
|
435
|
+
info("📥 Installing BasicTeX (for PDF generation)...")
|
|
436
|
+
info(" ℹ️ This is a large download (~100MB) and may take a few minutes")
|
|
437
|
+
try:
|
|
438
|
+
result = subprocess.run(
|
|
439
|
+
["brew", "install", "--cask", "basictex"],
|
|
440
|
+
capture_output=True,
|
|
441
|
+
text=True
|
|
442
|
+
)
|
|
443
|
+
if result.returncode == 0:
|
|
444
|
+
success(" ✅ BasicTeX installed successfully")
|
|
445
|
+
info(" ℹ️ You may need to restart your terminal or run: eval $(/usr/libexec/path_helper)")
|
|
446
|
+
info("")
|
|
447
|
+
info(" 📦 Installing LaTeX packages for document conversion...")
|
|
448
|
+
info(" ℹ️ This requires sudo access and may take a few minutes")
|
|
449
|
+
info("")
|
|
450
|
+
info(" RECOMMENDED (installs all common packages + fonts):")
|
|
451
|
+
info(" sudo tlmgr install collection-latexextra collection-fontsrecommended")
|
|
452
|
+
info(" sudo mktexlsr")
|
|
453
|
+
info("")
|
|
454
|
+
info(" OR install individual packages:")
|
|
455
|
+
info(" sudo tlmgr install tcolorbox environ pgf tools pdfcol \\")
|
|
456
|
+
info(" adjustbox collectbox xkeyval \\")
|
|
457
|
+
info(" booktabs ulem titling enumitem soul \\")
|
|
458
|
+
info(" jknapltx rsfs")
|
|
459
|
+
info(" sudo tlmgr install collection-fontsrecommended")
|
|
460
|
+
info(" sudo mktexlsr")
|
|
461
|
+
else:
|
|
462
|
+
check = subprocess.run(["which", "pdflatex"], capture_output=True)
|
|
463
|
+
if check.returncode == 0:
|
|
464
|
+
info(" ℹ️ LaTeX is already installed")
|
|
465
|
+
else:
|
|
466
|
+
warning(" ⚠️ BasicTeX installation may have failed")
|
|
467
|
+
info(" ℹ️ You can skip this for non-PDF conversions")
|
|
468
|
+
except Exception as e:
|
|
469
|
+
warning(f" ⚠️ Error installing BasicTeX: {e}")
|
|
470
|
+
info(" ℹ️ BasicTeX is only needed for PDF conversions")
|
|
471
|
+
|
|
472
|
+
info("")
|
|
473
|
+
info("=" * 60)
|
|
474
|
+
success("✨ Installation complete!")
|
|
475
|
+
info("=" * 60)
|
|
476
|
+
info("")
|
|
477
|
+
info("Installed tools:")
|
|
478
|
+
info(" • pandoc - Universal document converter")
|
|
479
|
+
info(" • jupyter nbconvert - Best for Jupyter notebooks")
|
|
480
|
+
info(" • basictex - LaTeX for PDF generation")
|
|
481
|
+
info("")
|
|
482
|
+
info("⚠️ IMPORTANT: For Jupyter notebook → PDF conversions:")
|
|
483
|
+
info(" Install required LaTeX packages (requires sudo):")
|
|
484
|
+
info("")
|
|
485
|
+
info(" RECOMMENDED (installs all common packages + fonts):")
|
|
486
|
+
info(" sudo tlmgr install collection-latexextra collection-fontsrecommended")
|
|
487
|
+
info(" sudo mktexlsr")
|
|
488
|
+
info("")
|
|
489
|
+
info(" OR install individual packages:")
|
|
490
|
+
info(" sudo tlmgr install tcolorbox environ pgf tools pdfcol \\")
|
|
491
|
+
info(" adjustbox collectbox xkeyval \\")
|
|
492
|
+
info(" booktabs ulem titling enumitem soul \\")
|
|
493
|
+
info(" jknapltx rsfs")
|
|
494
|
+
info(" sudo tlmgr install collection-fontsrecommended")
|
|
495
|
+
info(" sudo mktexlsr")
|
|
496
|
+
info("")
|
|
497
|
+
info("You can now use: mcli workflow doc-convert convert <from> <to> <file>")
|
|
498
|
+
info("Example: mcli workflow doc-convert convert ipynb pdf notebook.ipynb")
|
|
499
|
+
info("")
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
@doc_convert.command()
|
|
503
|
+
@click.argument("from_format")
|
|
504
|
+
@click.argument("to_format")
|
|
505
|
+
@click.argument("path")
|
|
506
|
+
@click.option("--output-dir", "-o", help="Output directory (defaults to same directory as input)")
|
|
507
|
+
@click.option("--pandoc-args", "-a", help="Additional pandoc arguments", default="")
|
|
508
|
+
@click.option("--no-fallback", is_flag=True, help="Disable fallback strategies (use only primary method)")
|
|
509
|
+
def convert(from_format, to_format, path, output_dir, pandoc_args, no_fallback):
|
|
510
|
+
"""
|
|
511
|
+
Convert documents with automatic fallback strategies.
|
|
512
|
+
|
|
513
|
+
FROM_FORMAT: Source format (e.g., ipynb, md, docx, html)
|
|
514
|
+
|
|
515
|
+
TO_FORMAT: Target format (e.g., pdf, html, md, docx)
|
|
516
|
+
|
|
517
|
+
PATH: File path or glob pattern (e.g., "*.ipynb" or "./notebook.ipynb")
|
|
518
|
+
|
|
519
|
+
The converter will try multiple conversion methods automatically:
|
|
520
|
+
- For Jupyter notebooks: tries nbconvert, then pandoc with various engines
|
|
521
|
+
- For PDF output: tries LaTeX engine, then alternative methods
|
|
522
|
+
- Falls back gracefully when primary method fails
|
|
523
|
+
|
|
524
|
+
All conversions are performed in a temporary directory to avoid path issues
|
|
525
|
+
with spaces or special characters.
|
|
526
|
+
|
|
527
|
+
Examples:
|
|
528
|
+
|
|
529
|
+
# Convert Jupyter notebook to PDF (tries nbconvert first)
|
|
530
|
+
mcli workflow doc-convert convert ipynb pdf notebook.ipynb
|
|
531
|
+
|
|
532
|
+
# Convert markdown to HTML
|
|
533
|
+
mcli workflow doc-convert convert md html README.md
|
|
534
|
+
|
|
535
|
+
# Convert all markdown files with custom output directory
|
|
536
|
+
mcli workflow doc-convert convert md pdf "*.md" -o ./pdfs
|
|
537
|
+
"""
|
|
538
|
+
# Check if pandoc is installed (primary tool)
|
|
539
|
+
has_pandoc = False
|
|
540
|
+
try:
|
|
541
|
+
subprocess.run(["pandoc", "--version"], capture_output=True, check=True)
|
|
542
|
+
has_pandoc = True
|
|
543
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
544
|
+
pass
|
|
545
|
+
|
|
546
|
+
# Check if nbconvert is available
|
|
547
|
+
has_nbconvert = False
|
|
548
|
+
try:
|
|
549
|
+
subprocess.run(["jupyter", "nbconvert", "--version"], capture_output=True, check=True)
|
|
550
|
+
has_nbconvert = True
|
|
551
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
552
|
+
pass
|
|
553
|
+
|
|
554
|
+
# Require at least one conversion tool
|
|
555
|
+
if not has_pandoc and not has_nbconvert:
|
|
556
|
+
error("❌ No conversion tools found!")
|
|
557
|
+
error(" Install with: mcli workflow doc-convert init")
|
|
558
|
+
error(" Or: brew install pandoc")
|
|
559
|
+
return
|
|
560
|
+
|
|
561
|
+
# Map format aliases
|
|
562
|
+
from_format_mapped = FORMAT_ALIASES.get(from_format.lower(), from_format)
|
|
563
|
+
to_format_mapped = FORMAT_ALIASES.get(to_format.lower(), to_format)
|
|
564
|
+
output_ext = to_format.lower()
|
|
565
|
+
|
|
566
|
+
# Expand path
|
|
567
|
+
expanded_path = os.path.expanduser(path)
|
|
568
|
+
|
|
569
|
+
# Handle glob patterns
|
|
570
|
+
if "*" in expanded_path or "?" in expanded_path or "[" in expanded_path:
|
|
571
|
+
files = file_glob(expanded_path, recursive=True)
|
|
572
|
+
if not files:
|
|
573
|
+
error(f"❌ No files found matching pattern: {path}")
|
|
574
|
+
return
|
|
575
|
+
info(f"📁 Found {len(files)} file(s) matching pattern: {path}")
|
|
576
|
+
else:
|
|
577
|
+
files = [expanded_path]
|
|
578
|
+
|
|
579
|
+
# Process each file
|
|
580
|
+
success_count = 0
|
|
581
|
+
error_count = 0
|
|
582
|
+
conversion_methods_used = {}
|
|
583
|
+
|
|
584
|
+
for input_file in files:
|
|
585
|
+
input_path = Path(input_file).resolve() # Get absolute path
|
|
586
|
+
|
|
587
|
+
if not input_path.exists():
|
|
588
|
+
warning(f"⚠️ File not found: {input_file}")
|
|
589
|
+
error_count += 1
|
|
590
|
+
continue
|
|
591
|
+
|
|
592
|
+
# Determine output path
|
|
593
|
+
if output_dir:
|
|
594
|
+
output_path = Path(output_dir) / f"{input_path.stem}.{output_ext}"
|
|
595
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
596
|
+
else:
|
|
597
|
+
output_path = input_path.parent / f"{input_path.stem}.{output_ext}"
|
|
598
|
+
|
|
599
|
+
info(f"🔄 Converting: {input_path.name} → {output_path.name}")
|
|
600
|
+
info(f" 📁 Using temp directory: ~/.mcli/commands/temp/conversions/")
|
|
601
|
+
|
|
602
|
+
# Get conversion strategies
|
|
603
|
+
strategies = get_conversion_strategies(
|
|
604
|
+
input_path, output_path, from_format_mapped, to_format_mapped, pandoc_args
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
# Limit to first strategy if no-fallback is set
|
|
608
|
+
if no_fallback:
|
|
609
|
+
strategies = strategies[:1]
|
|
610
|
+
|
|
611
|
+
# Try each strategy in order
|
|
612
|
+
conversion_succeeded = False
|
|
613
|
+
last_error = ""
|
|
614
|
+
|
|
615
|
+
for i, strategy in enumerate(strategies):
|
|
616
|
+
if i > 0:
|
|
617
|
+
info(f" ⚙️ Trying fallback method: {strategy.description}")
|
|
618
|
+
else:
|
|
619
|
+
info(f" ⚙️ Using: {strategy.description}")
|
|
620
|
+
|
|
621
|
+
success_flag, error_msg = execute_conversion_strategy(
|
|
622
|
+
strategy, input_path, output_path,
|
|
623
|
+
from_format_mapped, to_format_mapped, pandoc_args
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
if success_flag:
|
|
627
|
+
conversion_succeeded = True
|
|
628
|
+
method_name = strategy.description
|
|
629
|
+
conversion_methods_used[method_name] = conversion_methods_used.get(method_name, 0) + 1
|
|
630
|
+
success(f" ✅ Created: {output_path}")
|
|
631
|
+
if i > 0:
|
|
632
|
+
info(f" ℹ️ Succeeded with fallback method #{i + 1}")
|
|
633
|
+
break
|
|
634
|
+
else:
|
|
635
|
+
last_error = error_msg
|
|
636
|
+
if i < len(strategies) - 1:
|
|
637
|
+
warning(f" ⚠️ {strategy.description} failed, trying next method...")
|
|
638
|
+
|
|
639
|
+
if conversion_succeeded:
|
|
640
|
+
success_count += 1
|
|
641
|
+
else:
|
|
642
|
+
error(f" ❌ All conversion methods failed")
|
|
643
|
+
if last_error:
|
|
644
|
+
error(f" ℹ️ Last error: {last_error[:200]}")
|
|
645
|
+
error_count += 1
|
|
646
|
+
|
|
647
|
+
# Summary
|
|
648
|
+
info("")
|
|
649
|
+
info("=" * 60)
|
|
650
|
+
success("✨ Conversion complete!")
|
|
651
|
+
info(f" ✅ Successful: {success_count}")
|
|
652
|
+
if error_count > 0:
|
|
653
|
+
error(f" ❌ Failed: {error_count}")
|
|
654
|
+
|
|
655
|
+
# Show which methods were used
|
|
656
|
+
if conversion_methods_used:
|
|
657
|
+
info("")
|
|
658
|
+
info("Methods used:")
|
|
659
|
+
for method, count in conversion_methods_used.items():
|
|
660
|
+
info(f" • {method}: {count} file(s)")
|
|
661
|
+
|
|
662
|
+
info("=" * 60)
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
if __name__ == "__main__":
|
|
666
|
+
doc_convert()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcli-framework
|
|
3
|
-
Version: 7.9.
|
|
3
|
+
Version: 7.9.5
|
|
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>
|