ellf-cli 19.0.18__tar.gz → 20.0.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.
- {ellf_cli-19.0.18/ellf_cli.egg-info → ellf_cli-20.0.0}/PKG-INFO +1 -1
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/README.md +12 -3
- ellf_cli-20.0.0/ellf_cli/agents.py +367 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/cli.py +1 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/__init__.py +2 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/general.py +93 -70
- ellf_cli-20.0.0/ellf_cli/commands/mcp.py +44 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/support.py +31 -21
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf.json +92 -61
- ellf_cli-20.0.0/ellf_cli/ellf_skills/render.py +278 -0
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/SKILL.assistant.md +6 -6
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/SKILL.coding.md +10 -12
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/builtin_ellf_annotation_recipes.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_ellf_annotation_recipes.assistant.md +1 -1
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_ellf_annotation_recipes.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_ellf_annotation_recipes.coding.md +1 -1
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-ask/SKILL.md +0 -2
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/SKILL.assistant.md +6 -6
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/SKILL.coding.md +15 -15
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/training_monitoring.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/references/training_monitoring.coding.md +4 -4
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.coding/scripts → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/scripts.coding}/check_training.py +2 -2
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-ops.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-ops/SKILL.coding.md +2 -4
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-patterns/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-patterns/SKILL.coding.md +14 -8
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-prodigy/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-prodigy/SKILL.coding.md +26 -28
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.assistant/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project/SKILL.assistant.md +7 -7
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project/SKILL.coding.md +8 -10
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-support.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-support/SKILL.coding.md +35 -35
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-todo/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-todo/SKILL.coding.md +7 -6
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/SKILL.assistant.md +10 -10
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/SKILL.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/SKILL.coding.md +14 -16
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/workflow.md → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/workflow.coding.md +4 -4
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/interactivity.py +1 -1
- ellf_cli-20.0.0/ellf_cli/mcp_proxy.py +176 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/messages.py +7 -1
- ellf_cli-20.0.0/ellf_cli/version/19.0.18_2026-10-10-07-29-38_major_02601a1e-9bdb-45bf-ad67-a07b7dcd0002 +3 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0/ellf_cli.egg-info}/PKG-INFO +1 -1
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/SOURCES.txt +54 -56
- ellf_cli-20.0.0/tests/test_agents.py +262 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_login.py +203 -175
- ellf_cli-20.0.0/tests/test_mcp_proxy.py +248 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_support.py +71 -0
- ellf_cli-19.0.18/ellf_cli/ellf_skills/.claude-plugin/plugin.json +0 -12
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skill_variants.json +0 -39
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.coding/references/annotation_agents.md +0 -100
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.coding/references/consulting_patterns.md +0 -444
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.coding/references/explosion_strategy.md +0 -478
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/diagnostics.md +0 -278
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/evaluation_guide.md +0 -709
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/model_selection.md +0 -468
- ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_paradigms.md +0 -322
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/LICENSE +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/MANIFEST.in +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/__main__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/about.json +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/about.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/appdirs.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/auth.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/cloud/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/cloud/gcp.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/cluster_config.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_cluster_select.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_org_select.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_project_scope.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_recipe_file.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_recipe_subcommand.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_state.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/_usage.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/actions.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/agents.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/assets.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/auth.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/clusters.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/config.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/datasets.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/cp.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/ls.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/rm.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/rsync.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/files/stats.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/import_export.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/_config_io.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/_helpers.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/configure.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/deploy.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/hibernate.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/init.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/init_values.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/pause.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/provision.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/register.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/setup.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/start.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/terraform.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/infra/tls.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/jobs.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/packages.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/paths.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/plans.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/projects.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/publish_code.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/publish_data.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/recipes.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/secrets.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/services.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/sessions.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/tasks.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/todos.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/commands/users.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/config.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/.gitignore +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/annotation_audit.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/annotation_audit.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/annotation_audit.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/annotation_audit.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_prodigy_recipes.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_prodigy_recipes.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/label_schemes.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/label_schemes.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/label_schemes.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-annotate/references/label_schemes.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-handoff/SKILL.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-handoff/SKILL.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/annotation_metrics.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/references/annotation_metrics.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/annotation_metrics.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/references/annotation_metrics.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/training_monitoring.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-monitor/references/training_monitoring.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-ops.assistant/SKILL.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-ops/SKILL.assistant.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-ops.coding/references → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-ops/references.coding}/data_infra_cli.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-ops.coding/scripts → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-ops/scripts.coding}/run_job.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-patterns/references/pattern_strategies.md +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_action_recipe.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_agent_recipe.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_blocks_ui.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_correct.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_custom_ui.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_manual.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_pages_ui.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_routing.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_service_recipe.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_task_recipe.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_teach.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/builtin_recipes.md +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/ellf_recipe_sdk.md +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/lint_recipe.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/prodigy_recipe_api.md +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/template_index.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project}/references/annotation_agents.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project}/references/consulting_patterns.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project}/references/explosion_strategy.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/label_schemes.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project/references/label_schemes.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-project.coding/references/label_schemes.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-project/references/label_schemes.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-support.assistant/SKILL.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-support/SKILL.assistant.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_advanced.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/config_advanced.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_architectures.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/config_architectures.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_training.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/config_training.coding.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train}/references/diagnostics.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train}/references/evaluation_guide.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/experiment_patterns.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/experiment_patterns.coding.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train}/references/model_selection.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train}/references/training_paradigms.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_troubleshooting.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/training_troubleshooting.coding.md +0 -0
- /ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/workflow.md → /ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/references/workflow.assistant.md +0 -0
- {ellf_cli-19.0.18/ellf_cli/ellf_skills/skills/ellf-train.coding/scripts → ellf_cli-20.0.0/ellf_cli/ellf_skills/skills/ellf-train/scripts.coding}/ellf_logger.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/errors.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/helm.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/key_pair.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/main.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/pypi_auth.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/query.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/cookiecutter.json +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/.gitignore +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/README.md.tmpl +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements-dev.in +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements.in +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/setup.py.tmpl +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/about.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/example_task.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/testing/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ty.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/ui.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/url.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/util.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.114_2026-08-19-08-36-57__1a4e37c1-471e-4a81-b4d5-1ffe7dec3a61 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.114_2026-08-19-09-25-21_patch_33ff1e26-0e5e-46d8-8052-ab1d032e8b6c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.115_2026-08-19-09-27-13_patch_4ac728c3-0342-4a36-adbc-e28d2d99b1ba +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.116_2026-08-19-09-30-47_patch_c706fef6-6813-4183-b268-12e7b00d7d0b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.117_2026-08-19-09-39-14_patch_c6b0495f-2f88-4aa8-9ebf-0a235b4c407e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.118_2026-08-19-09-52-00_patch_b395655a-8d78-4344-9266-6901c20f6517 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.119_2026-08-19-10-22-38_patch_8f95c49d-aedc-41b8-816d-ccb95f048831 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.120_2026-08-19-10-26-58_patch_7fbf35e6-cc01-4b75-8c9a-f5d054bcaf93 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.121_2026-08-19-10-42-02_patch_31a81b02-a886-4dea-84e0-67cc6ca412d5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.122_2026-08-19-11-16-49_patch_1c4d7307-48d4-493e-936d-80af799d644b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.123_2026-08-19-11-47-32_patch_d3d78d04-9989-45b1-91b1-93b571d8814a +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.124_2026-08-20-08-03-17_patch_57f4c389-2d19-41ce-aca4-13b61c62f387 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.125_2026-08-20-08-25-05_patch_7f368148-0d1c-4525-bbdf-c6d257ad861a +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.126_2026-08-20-14-51-36_patch_a99abcc8-3371-4c63-a759-bb7ea5b32432 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.127_2026-08-21-05-48-58_patch_34b4ccee-7596-4f57-93e9-774973cca58e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.128_2026-08-21-10-47-20_patch_693112b9-927c-4a8f-8553-b06eef86079d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.129_2026-08-21-11-16-54_patch_7a981666-01d9-4d1b-9ba3-2129744e3bd5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.130_2026-08-21-13-09-36_patch_b7ad1a76-ce70-4d70-9d1a-7c414eba5bb4 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.131_2026-08-21-14-31-10_patch_9128ef66-193e-4caf-8710-afd86128e638 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.132_2026-08-24-08-59-34_patch_c600fc14-86a5-460f-9c4e-f0177056f756 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.133_2026-08-24-10-28-29_patch_b6ce3e32-9d7b-48ac-981a-270c22c180dd +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.134_2026-08-24-11-00-51_patch_a4fc0484-4a64-46a2-94f8-aa805254c7b0 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.135_2026-08-24-12-12-41_patch_a870a56f-9a65-49eb-92da-f572b26667d8 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.136_2026-08-24-12-42-46_patch_9b399356-6482-4291-8da7-e748a99c4b53 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.137_2026-08-24-12-53-57_patch_f7979348-1910-40cd-a535-90299eca84ee +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.138_2026-08-24-14-36-30_patch_ed0f8750-f663-498b-85e7-0d3f2213fcfe +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.139_2026-08-25-08-37-26_patch_3ba87e19-902b-4f76-b64c-90e5c0ca1fc6 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.140_2026-08-25-09-52-45_patch_abc830f2-df15-4385-b797-cdaf72c10752 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.141_2026-08-25-11-37-20_patch_1d9ec01e-06f6-4c8e-b095-af17d5b62b00 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.142_2026-08-26-07-38-49_patch_3dd23e36-e7df-494c-986f-a412861a8d40 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.143_2026-08-26-09-32-32_patch_7b7ebd34-de27-4b73-98a7-3e1501e16cd5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.144_2026-08-26-10-56-43_patch_166064f2-2208-4c9b-9e25-25dc4cd32084 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.145_2026-08-26-11-37-29_patch_b997f3ee-d7d3-4408-9f2f-c8b6d08bdb3b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.146_2026-08-26-12-15-20_patch_afbbb893-25db-468c-81db-2663ca373068 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.147_2026-08-26-14-10-50_patch_fd753b1f-2fa1-4ddb-a9e7-de690da85254 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.148_2026-08-27-09-08-35_patch_23814c0b-7f77-489c-b4a8-ceadd18146e3 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.149_2026-08-27-09-40-17_patch_8879d72e-a3d8-4abc-a16a-d9dcf75f0fa1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.150_2026-08-27-10-57-25_patch_afbe60ed-3e23-4d88-be3c-f800d7002a7d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.151_2026-08-28-09-02-46_patch_1d4ca23b-aeae-4ea8-96b1-8cf57371f29d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.152_2026-08-28-15-37-24_patch_c9d0bdc1-a7e1-432b-92b9-92dc76fe0c78 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.153_2026-08-29-09-03-27_patch_7531573a-1b33-4092-aa9c-0e65f47b201f +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.154_2026-08-29-11-56-35_patch_919f5787-39c8-4dc1-ae6a-f27c28380f21 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.155_2026-08-29-15-15-59_patch_822f9ed8-c366-4e5f-9791-dee8467cf3ce +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.156_2026-08-29-16-19-01_patch_3ac2bf36-20f7-4c9f-9fdb-295d4466d59e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.157_2026-08-30-17-32-17_patch_4302354c-c9c5-4be7-acd3-542872a748d8 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.158_2026-08-31-09-28-33_patch_3523774f-c25d-4102-8c1a-92fff046a48d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.159_2026-08-31-10-31-01_patch_fe3e6290-2553-4154-a0a0-8b8a418280ed +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.160_2026-08-31-11-23-39_patch_e701a085-3d23-4212-b0af-73b1d419a4c1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.161_2026-08-31-12-41-01_patch_074d7bde-c493-44db-bc15-e81fd91e2921 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.162_2026-08-31-13-58-06_patch_84db1d60-4280-433b-bd3a-22e5611cd315 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.163_2026-08-31-15-25-54_patch_1931c5ba-73df-48cb-8dcb-555ace0af267 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.163_2026-08-31-15-44-37_patch_3962e805-2a92-494a-a87b-b6e6d66c40a0 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.165_2026-08-31-19-48-59_patch_86e5b923-2b99-4b86-b542-469b197614be +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.166_2026-09-01-07-39-57_patch_c344892f-d542-4e7b-8f27-02365a411e15 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.167_2026-09-01-08-21-53_patch_e199d419-282a-4dbb-8756-cf98b7037e2b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.168_2026-09-01-09-12-31_patch_235c9fe0-da15-431d-bb56-01e2b9b15f4b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.169_2026-09-01-11-54-19_patch_98b617ab-d130-42b5-93f2-19cae56d4c4c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.170_2026-09-02-09-27-28_patch_e448d2e6-b7ec-4235-96bf-0173b3623c87 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.171_2026-09-02-12-52-44_patch_e6a241c2-1d62-482c-a9eb-9e3373395c50 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.172_2026-09-04-08-47-04_patch_daae079f-c104-4fcd-bb57-7bff68e80ad9 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.173_2026-09-04-12-34-42_patch_399c4cbd-0c28-4dfd-a4ec-e569420a36e4 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.174_2026-09-04-13-08-48_patch_f5cfe3d5-808e-45e4-bafc-00d0554838ee +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.175_2026-09-04-17-20-46_patch_1ef542fa-5d8e-4d90-aa15-9fc4cea3dfec +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.176_2026-09-05-08-25-05_patch_ced5521f-f9da-4640-a921-95fcb5cd2e6d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.177_2026-09-05-09-00-16_patch_803c1ad4-a9af-4953-92c5-d882dec03ea2 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.178_2026-09-05-09-30-34_patch_012f6259-2e3f-4591-9806-1920fd06cb1f +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.179_2026-09-05-09-33-43_patch_f4bdf28c-d584-47a5-b699-8c883330162c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.180_2026-09-05-12-02-21_patch_34a14b01-d22d-44a8-ac63-be0370a61422 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.181_2026-09-05-12-47-46_patch_56b18867-99f6-4d5c-8215-7b9d60d34010 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.182_2026-09-05-13-35-18_patch_61b7d4d1-73c8-4603-9b0c-593e7405587f +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.183_2026-09-06-07-27-09_patch_d76331b2-e3a3-4c0b-8412-ecd131b6ac02 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.184_2026-09-06-10-21-47_patch_7680b7a1-49f0-4eef-b12e-4c854407448c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.185_2026-09-06-10-30-40_patch_e56c2183-77f8-44ef-a92e-7377ea6ce8c1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.186_2026-09-07-10-00-51_patch_67de5683-d208-4bc0-8fb6-7677377908e7 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.187_2026-09-07-10-18-13_patch_2086cee2-276b-48f7-80ce-6a17397b9541 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.188_2026-09-07-12-51-28_patch_d6590822-068f-4a19-814d-34bbf204ba6e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.189_2026-09-07-12-55-23_patch_7e0fb04b-4d40-4490-974f-c74ba2ae55a1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.190_2026-09-08-08-58-03_patch_15e3ac1e-4475-4272-bdd8-d00bb0db8f17 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.191_2026-09-08-09-55-58_patch_3d350e50-ee53-4282-bc75-d2251142c46e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.192_2026-09-08-11-12-21_patch_0733223b-1ae2-4b5b-897f-dfc57574ff83 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.193_2026-09-08-21-48-17_patch_8d07d4e6-3555-4720-85c9-9452570fae2d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.194_2026-09-09-07-53-43_patch_69559429-aa42-4b62-9bd7-cdfded1c00d0 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.195_2026-09-09-09-55-40_patch_bbf67f1d-3b9a-43a2-b1bc-22df3fed8a34 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.196_2026-09-09-09-59-47_patch_70d76812-7b3c-4192-ad49-fcaccc29b0da +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.197_2026-09-09-13-06-06_patch_d455be0b-5421-492a-b952-fab0fd8110f8 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.198_2026-09-09-13-14-34_patch_267f54e5-311e-435e-882f-8e19191325ea +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.199_2026-09-09-22-24-18_patch_81e3e453-ca0e-42fa-9c21-8f94d43c05f2 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.200_2026-09-10-07-19-50_patch_911714fa-1fa3-4165-bfe6-d10c650bf5bf +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.201_2026-09-10-10-14-19_patch_864015f2-b0b0-4563-a1c8-155629cb9126 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.202_2026-09-10-11-00-05_patch_18270ecf-e770-4e69-8bcf-e5143c39929b +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.203_2026-09-10-11-10-41_patch_ff273ab1-44f3-4bc0-b184-3396e943df04 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.204_2026-09-10-13-02-02_patch_d4ee41e2-d13c-4941-8605-3f1a42b56b22 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.205_2026-09-10-13-57-50_patch_284df67e-5957-4b0c-bc64-5581db6ddecc +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.206_2026-09-11-10-18-50_patch_1ac7e410-0e62-4eef-bbe4-ebf93c9d0869 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/17.0.207_2026-09-11-15-26-02_major_3f1b3ed7-eaac-41f5-b740-0af3331595d9 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.0_2026-09-12-10-01-10_patch_8995783a-a9fa-4c4e-90b3-6386a4c481eb +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.10_2026-09-14-16-09-38_patch_9403d562-eed0-4125-a8b3-09cd92a13298 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.11_2026-09-15-09-05-57_patch_8b22dba2-d931-4c4d-ae60-db3238d5e73d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.12_2026-09-15-11-18-52_patch_81314afa-e70d-4ad8-b45b-3f8d62b983e7 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.13_2026-09-16-08-00-55_patch_bfa30fc0-3281-4de6-bb56-d7290c98d1c3 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.14_2026-09-16-14-38-26_patch_aae6e9b0-88f4-4bcf-b611-3308c7fcd6eb +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.15_2026-09-17-07-58-54_patch_43d40582-effd-4925-a8bd-e70fecf1faab +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.16_2026-09-17-08-12-37_patch_b4db2d23-88f1-45c1-82d9-78d38014fcb6 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.17_2026-09-18-09-38-19_patch_25697fc3-e9a8-4980-962b-e6cb0a4760c5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.18_2026-09-18-09-54-33_patch_d37d9c71-c469-4d94-90d7-4898915ee991 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.19_2026-09-18-10-47-33_patch_47607b3c-d1b6-4864-b9b0-00a2a8d2ac32 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.1_2026-09-12-17-33-30_patch_f6ea2c99-a715-4c4d-876a-23ed8c62a83d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.20_2026-09-18-11-07-21_patch_5a336f91-63a6-4877-97ed-da89395cc8f5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.21_2026-09-18-13-34-52_patch_c56462e1-63d9-498f-a912-c80c5f0171d1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.22_2026-09-20-08-10-45_patch_6afa2c20-bcef-4b7d-8685-2c9815d8683f +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.23_2026-09-20-08-38-35_patch_a7f169e5-37ab-4ec0-bf89-d14770181303 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.24_2026-09-20-15-49-27_patch_c1222081-ff44-4f20-aea2-5840b6d76efd +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.25_2026-09-21-06-11-40_patch_6df46dd9-e7d3-4e71-bec4-e5c93b4ac863 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.26_2026-09-21-07-54-11_patch_cc52dd36-5eba-4094-a1b0-d6f79f103441 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.27_2026-09-21-08-36-49_patch_a25fa125-9bcd-4317-8da5-851c1c329631 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.28_2026-09-21-09-44-01_patch_4430a721-0b3c-4f6a-b9bc-a53e667161bb +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.29_2026-09-21-10-58-07_patch_83b2b942-60a4-4bef-afd1-99690ba52b69 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.2_2026-09-13-06-36-33_patch_176bb944-1c49-4dd3-a001-8fce908825a0 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.30_2026-09-21-12-51-16_patch_519b9a65-d400-4234-b113-36b46e315507 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.31_2026-09-22-06-53-35_patch_5c45a235-81b6-4d05-801a-07dc7db61400 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.32_2026-09-22-07-42-04_patch_f12c6415-8166-4063-9e5d-26601b929d63 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.33_2026-09-22-08-12-32_patch_cec31bb0-a6cb-43e6-8407-25aba322b54c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.34_2026-09-23-07-09-16_patch_659fccbb-c0a0-4f6f-bc87-e6abaa8815a7 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.35_2026-09-23-09-38-52_patch_023f904d-807a-4833-8a40-570365e8ec06 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.36_2026-09-23-10-05-33_patch_846fb491-2b1b-47ed-ac1f-ba40e744e199 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.37_2026-09-23-13-08-30_patch_8e4b1d24-156e-4ffe-8e4a-b8740ec18588 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.38_2026-09-24-06-41-37_patch_67adb1d6-3f49-4357-a67f-b1d48f23a972 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.39_2026-09-24-15-24-32_patch_e5dd375d-5643-4514-9b65-8d877c4a2bb2 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.3_2026-09-13-12-32-46_patch_58e5ce3a-f2a7-4789-b2cd-5cc75c72b6ec +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.40_2026-09-24-19-58-14_patch_ff18824b-be51-4a3d-a621-e96279e53c3e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.41_2026-09-26-09-24-52_patch_b9979267-30f9-440a-a4ce-c611991d4886 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.42_2026-09-28-12-39-34_patch_dda535d9-8922-4eb9-ab51-6ecff0650c10 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.43_2026-09-28-13-35-27_minor_aca1168a-1286-4326-9d0c-2f2587c9fe92 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.4_2026-09-13-12-45-14_patch_b6c79d55-8f85-4f47-a304-df52b122c38c +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.5_2026-09-13-14-11-18_patch_9b111116-5e62-472a-b72c-d1bbafa22c97 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.5_2026-09-13-17-01-11_patch_d4bf61c0-83ac-4dd3-b512-a65805d298c8 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.6_2026-09-14-11-31-04_patch_fd2ebda6-22cb-4e7d-9452-2f6f2640e828 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.7_2026-09-13-17-06-08_patch_428af161-0b27-43c2-8751-e5f7874df120 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.0.9_2026-09-14-12-37-42_patch_b2ca0529-4b67-4fa4-8fdc-5f5e9f5d5166 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.1.0_2026-09-28-14-27-54_patch_324444f7-d24e-4189-b21f-1188894a3109 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/18.1.1_2026-09-28-21-03-07_major_e266a14a-7d96-4ece-92a3-8f34e64438a5 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.0_2026-09-29-11-05-31_patch_77d6f9f8-ead3-4d79-a4b2-b084b2dffc98 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.10_2026-10-02-12-56-52_patch_14e97576-73ca-44b8-82c9-7dad6f1789ab +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.11_2026-10-04-10-31-19_patch_088eb371-1799-4949-a119-286cf1cd55d1 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.12_2026-10-06-18-00-25_patch_36554bed-49c5-41cb-9fd4-48cc6af74c09 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.13_2026-10-07-12-24-08_patch_a540a364-3a0d-4960-b278-06ba2c7cc258 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.14_2026-10-07-12-52-39_patch_e3a6fc5c-2ee4-414c-a2dd-4910a655a7dd +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.15_2026-10-09-04-15-56_patch_bd7a9b06-867b-4fea-9678-973a05e3022d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.16_2026-10-09-16-11-56_patch_a1135435-7dea-4f00-8c98-203ba3974382 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.17_2026-10-09-17-44-55_patch_faeacad8-541a-40f2-ab9c-abcd66fcd00e +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.1_2026-09-29-11-59-38_patch_bbf4753c-d641-4c2f-ac7c-02be6bd8e7c2 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.2_2026-09-29-12-44-07_patch_19fdaa94-60dc-464b-93b8-c17607ebc7b6 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.3_2026-09-29-14-16-00_patch_3cb60272-95cf-4311-8897-721e1b5c2c88 +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.4_2026-09-29-16-24-53_patch_9fe8ad2b-e3ec-4558-a5fc-9c44c5c266dc +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.5_2026-09-29-17-13-16_patch_e48d2dd2-f41a-402e-a441-756b23c01dcb +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.6_2026-09-29-17-22-11_patch_3b1c79e9-9002-4e96-ba78-10668c33be6a +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.7_2026-09-30-07-50-58_patch_e8b1f046-d819-499c-9cd5-3e1a20fc9acf +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.8_2026-10-01-13-41-44_patch_7d63af18-e0af-4127-ab58-aede2407490f +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/19.0.9_2026-10-01-15-57-35_patch_143863cb-8f63-4ef7-bd78-c1114fc93a2d +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/__init__.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli/version/read_version.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/dependency_links.txt +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/entry_points.txt +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/not-zip-safe +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/requires.txt +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/ellf_cli.egg-info/top_level.txt +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/pyproject.toml +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/setup.cfg +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/setup.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_agents_info_stats.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_appdirs.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_auth.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_clusters_info_stats.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_config.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_datasets_export.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_errors.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_files_cp.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_files_cp_helpers.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_helm.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_import_export.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_info.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_config_io.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_configure.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_deploy_node_labels.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_destroy.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_get_terraform.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_hibernate.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_init.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_pause.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_provision.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_start_fixes.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_start_validation.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_state_bucket.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_infra_terraform_init.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_invalid_secrets.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_job_list_project_filter.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_jobs_info_hides_creator.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_jobs_list_unmatched.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_key_pair.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_logout.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_main.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_org_select.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_plans.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_projects.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_projects_delete_confirm.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_publish_build_poll.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_publish_data.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_publish_import_root.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_publish_requirements.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_pypi_auth.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_query.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_recipe_file.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_recipe_required_args.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_recipes.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_sessions.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_state.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_todos.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_ty.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_ui.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_ui_extras.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_usage_counts.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_users_assign.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_users_info_stats.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_users_list.py +0 -0
- {ellf_cli-19.0.18 → ellf_cli-20.0.0}/tests/test_util.py +0 -0
|
@@ -939,6 +939,14 @@ Stop a job on the cluster by its ID. Works for workloads that have no matching j
|
|
|
939
939
|
| `--type` | `str` | Job type, if the cluster does not report one | `None` |
|
|
940
940
|
| `--json` | `bool` | Output the result as JSON | `False` |
|
|
941
941
|
|
|
942
|
+
### `ellf mcp`
|
|
943
|
+
|
|
944
|
+
MCP servers that coding agents start themselves after 'ellf login --agent'
|
|
945
|
+
|
|
946
|
+
#### `ellf mcp kb`
|
|
947
|
+
|
|
948
|
+
Run the Ellf knowledge base MCP server over stdio, using your ellf login. Coding agents start this themselves once 'ellf login --agent' has set them up.
|
|
949
|
+
|
|
942
950
|
### `ellf packages`
|
|
943
951
|
|
|
944
952
|
View and manage Python packages on the cluster
|
|
@@ -1401,8 +1409,8 @@ Send a support request to the Ellf team.
|
|
|
1401
1409
|
| `--project` | `str` | Name, slug, or ID of support request's project or the last project if not set | `None` |
|
|
1402
1410
|
| `--no-project` | `bool` | Explicitly send the request without any project association | `False` |
|
|
1403
1411
|
| `--conversation` | `UUID` | Conversation ID to attach from PAM when available | `None` |
|
|
1404
|
-
| `--session-id` | `str` |
|
|
1405
|
-
| `--transcript-path` | `str` | Path to a
|
|
1412
|
+
| `--session-id` | `str` | Agent session ID to use for transcript/debug attachment lookup (defaults to the current session) | `None` |
|
|
1413
|
+
| `--transcript-path` | `str` | Path to a session transcript file to attach explicitly | `None` |
|
|
1406
1414
|
| `--transcript-consent` | `str` | Explicit transcript consent mode: 'summary_only' or 'attach_full_transcript' | `'summary_only'` |
|
|
1407
1415
|
| `--json` | `bool` | Output the result as JSON | `False` |
|
|
1408
1416
|
|
|
@@ -1671,7 +1679,8 @@ Log in to your Ellf account. You normally don't need to call this manually. It w
|
|
|
1671
1679
|
| `--org` | `str` | Name or ID of the organization to log into. If omitted: auto-select when only one is available, or prompt interactively | `None` |
|
|
1672
1680
|
| `--cluster` | `str` | Name or ID of the cluster to log into. If omitted: auto-select when only one is available, or prompt interactively | `None` |
|
|
1673
1681
|
| `--json` | `bool` | Output the result as JSON | `False` |
|
|
1674
|
-
| `--
|
|
1682
|
+
| `--agent` | `str` | Set up coding agents to work with Ellf: install the Ellf skills and the knowledge base MCP server. One of claude, codex, opencode, copilot; repeat the option or comma-separate them for several | `None` |
|
|
1683
|
+
| `--claude` | `bool` | Shortcut for --agent claude | `False` |
|
|
1675
1684
|
|
|
1676
1685
|
### `ellf logout`
|
|
1677
1686
|
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""Local coding agents: where their skills and MCP servers are configured, and
|
|
2
|
+
where they keep session transcripts."""
|
|
3
|
+
|
|
4
|
+
import importlib.util
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import shutil
|
|
9
|
+
import sys
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from types import ModuleType
|
|
13
|
+
from typing import Any, Callable, Optional, Union
|
|
14
|
+
|
|
15
|
+
AGENTS = ("claude", "codex", "opencode", "copilot")
|
|
16
|
+
AGENT_NAMES = {
|
|
17
|
+
"claude": "Claude Code",
|
|
18
|
+
"codex": "Codex",
|
|
19
|
+
"opencode": "OpenCode",
|
|
20
|
+
"copilot": "GitHub Copilot",
|
|
21
|
+
}
|
|
22
|
+
MCP_SERVER_NAME = "ellf-kb"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _home() -> Path:
|
|
26
|
+
return Path.home()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _env_dir(var: str, default: Path) -> Path:
|
|
30
|
+
value = (os.environ.get(var) or "").strip()
|
|
31
|
+
return Path(value).expanduser() if value else default
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _codex_home() -> Path:
|
|
35
|
+
return _env_dir("CODEX_HOME", _home() / ".codex")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _copilot_home() -> Path:
|
|
39
|
+
return _env_dir("COPILOT_HOME", _home() / ".copilot")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _opencode_config_dir() -> Path:
|
|
43
|
+
return _env_dir("XDG_CONFIG_HOME", _home() / ".config") / "opencode"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _vscode_user_dir() -> Path:
|
|
47
|
+
if sys.platform == "darwin":
|
|
48
|
+
return _home() / "Library" / "Application Support" / "Code" / "User"
|
|
49
|
+
if sys.platform == "win32":
|
|
50
|
+
return _env_dir("APPDATA", _home() / "AppData" / "Roaming") / "Code" / "User"
|
|
51
|
+
return _env_dir("XDG_CONFIG_HOME", _home() / ".config") / "Code" / "User"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def skills_dirs(agent: str) -> list[Path]:
|
|
55
|
+
"""The user-level skill directories an agent reads ellf skills from."""
|
|
56
|
+
if agent == "claude":
|
|
57
|
+
return [_home() / ".claude" / "skills"]
|
|
58
|
+
# Codex, OpenCode and Copilot (CLI and VS Code) all read ~/.agents/skills.
|
|
59
|
+
dirs = [_home() / ".agents" / "skills"]
|
|
60
|
+
if agent == "copilot" and os.environ.get("COPILOT_HOME"):
|
|
61
|
+
# Copilot CLI stops reading ~/.agents/skills when COPILOT_HOME is set.
|
|
62
|
+
dirs.append(_copilot_home() / "skills")
|
|
63
|
+
return dirs
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ellf_skills_dir() -> Optional[Path]:
|
|
67
|
+
path = Path(__file__).resolve().parent / "ellf_skills"
|
|
68
|
+
return path if (path / "render.py").exists() else None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _load_renderer(skills_dir: Path) -> ModuleType:
|
|
72
|
+
spec = importlib.util.spec_from_file_location(
|
|
73
|
+
"ellf_skills_render", skills_dir / "render.py"
|
|
74
|
+
)
|
|
75
|
+
assert spec is not None and spec.loader is not None
|
|
76
|
+
module = importlib.util.module_from_spec(spec)
|
|
77
|
+
spec.loader.exec_module(module)
|
|
78
|
+
return module
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def install_skills(
|
|
82
|
+
agents: list[str],
|
|
83
|
+
skills_dir: Path,
|
|
84
|
+
confirm_removal: Callable[[list[Path]], bool],
|
|
85
|
+
) -> dict[Path, list[str]]:
|
|
86
|
+
"""Render the coding skills into every directory the agents read.
|
|
87
|
+
|
|
88
|
+
Skill folders left by an install from before the renderer kept a record
|
|
89
|
+
are passed to ``confirm_removal`` and only removed if it returns True.
|
|
90
|
+
"""
|
|
91
|
+
renderer = _load_renderer(skills_dir)
|
|
92
|
+
dests: list[Path] = []
|
|
93
|
+
for agent in agents:
|
|
94
|
+
for path in skills_dirs(agent):
|
|
95
|
+
if path not in dests:
|
|
96
|
+
dests.append(path)
|
|
97
|
+
installed = {}
|
|
98
|
+
for dest in dests:
|
|
99
|
+
stale = renderer.unrecorded_skills("coding", dest)
|
|
100
|
+
if stale and not confirm_removal([dest / name for name in stale]):
|
|
101
|
+
stale = []
|
|
102
|
+
installed[dest] = renderer.render_skills("coding", dest, remove=stale)
|
|
103
|
+
return installed
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# MCP configuration
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def mcp_command() -> Optional[list[str]]:
|
|
110
|
+
"""How agents start the knowledge base server: this install's ellf script
|
|
111
|
+
by absolute path, as agents don't run it from the user's shell. Not
|
|
112
|
+
``python -m ellf_cli``, which puts the agent's working directory first on
|
|
113
|
+
sys.path, where a project's own modules would shadow the CLI's imports."""
|
|
114
|
+
script = Path(sys.argv[0])
|
|
115
|
+
if not (script.stem == "ellf" and script.is_file()):
|
|
116
|
+
found = shutil.which("ellf")
|
|
117
|
+
if found is None:
|
|
118
|
+
return None
|
|
119
|
+
script = Path(found)
|
|
120
|
+
return [str(script.absolute()), "mcp", "kb"]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class MCPConfigError(Exception):
|
|
124
|
+
"""The agent's config file couldn't be updated; ``snippet`` is what to add
|
|
125
|
+
by hand."""
|
|
126
|
+
|
|
127
|
+
def __init__(self, path: Path, reason: str, snippet: str) -> None:
|
|
128
|
+
super().__init__(f"Could not update {path}: {reason}")
|
|
129
|
+
self.path = path
|
|
130
|
+
self.snippet = snippet
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _write_private(path: Path, text: str) -> None:
|
|
134
|
+
"""Replace a config file atomically. Agent configs often hold other MCP
|
|
135
|
+
servers' tokens, so the file is readable by the user only, from the moment
|
|
136
|
+
it's created. A symlinked config is written through to its target."""
|
|
137
|
+
path = path.resolve()
|
|
138
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
139
|
+
tmp_path = path.with_name(path.name + ".ellf.tmp")
|
|
140
|
+
tmp_path.unlink(missing_ok=True)
|
|
141
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0)
|
|
142
|
+
with open(os.open(tmp_path, flags, 0o600), "w", encoding="utf-8") as f:
|
|
143
|
+
f.write(text)
|
|
144
|
+
tmp_path.replace(path)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _set_json_entry(path: Path, keys: tuple[str, ...], entry: dict) -> None:
|
|
148
|
+
nested: dict[str, Any] = entry
|
|
149
|
+
for key in reversed(keys):
|
|
150
|
+
nested = {key: nested}
|
|
151
|
+
snippet = json.dumps(nested, indent=2)
|
|
152
|
+
config: dict[str, Any] = {}
|
|
153
|
+
if path.exists():
|
|
154
|
+
try:
|
|
155
|
+
config = json.loads(path.read_text(encoding="utf-8") or "{}")
|
|
156
|
+
except json.JSONDecodeError as e:
|
|
157
|
+
raise MCPConfigError(path, f"not plain JSON ({e})", snippet) from e
|
|
158
|
+
if not isinstance(config, dict):
|
|
159
|
+
raise MCPConfigError(path, "not a JSON object", snippet)
|
|
160
|
+
parent = config
|
|
161
|
+
for key in keys[:-1]:
|
|
162
|
+
child = parent.setdefault(key, {})
|
|
163
|
+
if not isinstance(child, dict):
|
|
164
|
+
raise MCPConfigError(path, f"'{key}' is not an object", snippet)
|
|
165
|
+
parent = child
|
|
166
|
+
parent[keys[-1]] = entry
|
|
167
|
+
_write_private(path, json.dumps(config, indent=2, ensure_ascii=False) + "\n")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
_TOML_HEADER_RE = re.compile(r"^\s*\[")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _is_server_table(line: str, name: str) -> bool:
|
|
174
|
+
quoted = rf"(?:{re.escape(name)}|\"{re.escape(name)}\"|'{re.escape(name)}')"
|
|
175
|
+
return bool(
|
|
176
|
+
re.match(
|
|
177
|
+
rf"^\s*\[\s*mcp_servers\s*\.\s*{quoted}\s*(\.[^\]]*)?\]\s*(#.*)?$", line
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _trailing_comments(lines: list[str]) -> list[str]:
|
|
183
|
+
start = len(lines)
|
|
184
|
+
while start > 0 and lines[start - 1].strip()[:1] in ("", "#"):
|
|
185
|
+
start -= 1
|
|
186
|
+
return lines[start:]
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def set_codex_mcp_server(text: str, name: str, command: list[str]) -> str:
|
|
190
|
+
"""Return config.toml with the ``[mcp_servers.<name>]`` table replaced.
|
|
191
|
+
|
|
192
|
+
Edited as text so the user's formatting and comments survive; the result
|
|
193
|
+
is re-parsed and refused unless it holds exactly the new server.
|
|
194
|
+
"""
|
|
195
|
+
table = (
|
|
196
|
+
f"[mcp_servers.{name}]\n"
|
|
197
|
+
f"command = {json.dumps(command[0])}\n"
|
|
198
|
+
f"args = {json.dumps(command[1:])}\n"
|
|
199
|
+
)
|
|
200
|
+
kept: list[str] = []
|
|
201
|
+
dropped: list[str] = []
|
|
202
|
+
skipping = False
|
|
203
|
+
for line in text.splitlines(keepends=True):
|
|
204
|
+
if _TOML_HEADER_RE.match(line):
|
|
205
|
+
ours = _is_server_table(line, name)
|
|
206
|
+
if skipping and not ours:
|
|
207
|
+
# Comments right above the next table belong to it.
|
|
208
|
+
kept.extend(_trailing_comments(dropped))
|
|
209
|
+
skipping = ours
|
|
210
|
+
dropped = []
|
|
211
|
+
(dropped if skipping else kept).append(line)
|
|
212
|
+
body = "".join(kept).rstrip("\n")
|
|
213
|
+
result = (body + "\n\n" if body else "") + table
|
|
214
|
+
try:
|
|
215
|
+
import tomllib
|
|
216
|
+
except ImportError:
|
|
217
|
+
if body.strip():
|
|
218
|
+
raise ValueError("can't check the edited file without Python 3.11+")
|
|
219
|
+
return result
|
|
220
|
+
try:
|
|
221
|
+
parsed = tomllib.loads(result)
|
|
222
|
+
except tomllib.TOMLDecodeError as e:
|
|
223
|
+
raise ValueError(f"not valid TOML after the edit ({e})") from e
|
|
224
|
+
server = parsed.get("mcp_servers", {}).get(name)
|
|
225
|
+
if server != {"command": command[0], "args": command[1:]}:
|
|
226
|
+
raise ValueError(f"mcp_servers.{name} is also defined outside its own table")
|
|
227
|
+
return result
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _configure_codex(command: list[str]) -> Path:
|
|
231
|
+
path = _codex_home() / "config.toml"
|
|
232
|
+
text = path.read_text(encoding="utf-8") if path.exists() else ""
|
|
233
|
+
try:
|
|
234
|
+
updated = set_codex_mcp_server(text, MCP_SERVER_NAME, command)
|
|
235
|
+
except ValueError as e:
|
|
236
|
+
snippet = set_codex_mcp_server("", MCP_SERVER_NAME, command)
|
|
237
|
+
raise MCPConfigError(path, str(e), snippet) from e
|
|
238
|
+
_write_private(path, updated)
|
|
239
|
+
return path
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _configure_claude(command: list[str]) -> Path:
|
|
243
|
+
# Claude Code keeps user-scoped MCP servers at the top level of
|
|
244
|
+
# ~/.claude.json, which makes the server available in every project.
|
|
245
|
+
path = _home() / ".claude.json"
|
|
246
|
+
entry = {"type": "stdio", "command": command[0], "args": command[1:]}
|
|
247
|
+
_set_json_entry(path, ("mcpServers", MCP_SERVER_NAME), entry)
|
|
248
|
+
return path
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _configure_opencode(command: list[str]) -> Path:
|
|
252
|
+
config_dir = _opencode_config_dir()
|
|
253
|
+
candidates = [
|
|
254
|
+
config_dir / n for n in ("opencode.json", "opencode.jsonc", "config.json")
|
|
255
|
+
]
|
|
256
|
+
path = next((p for p in candidates if p.exists()), candidates[0])
|
|
257
|
+
entry = {"type": "local", "command": command, "enabled": True}
|
|
258
|
+
_set_json_entry(path, ("mcp", MCP_SERVER_NAME), entry)
|
|
259
|
+
return path
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _configure_copilot_cli(command: list[str]) -> Path:
|
|
263
|
+
path = _copilot_home() / "mcp-config.json"
|
|
264
|
+
entry = {
|
|
265
|
+
"type": "local",
|
|
266
|
+
"command": command[0],
|
|
267
|
+
"args": command[1:],
|
|
268
|
+
"tools": ["*"],
|
|
269
|
+
}
|
|
270
|
+
_set_json_entry(path, ("mcpServers", MCP_SERVER_NAME), entry)
|
|
271
|
+
return path
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _configure_vscode(command: list[str]) -> Optional[Path]:
|
|
275
|
+
# VS Code keeps its own user mcp.json; only touch it when VS Code is there.
|
|
276
|
+
vscode_dir = _vscode_user_dir()
|
|
277
|
+
if not vscode_dir.is_dir():
|
|
278
|
+
return None
|
|
279
|
+
path = vscode_dir / "mcp.json"
|
|
280
|
+
entry = {"type": "stdio", "command": command[0], "args": command[1:]}
|
|
281
|
+
_set_json_entry(path, ("servers", MCP_SERVER_NAME), entry)
|
|
282
|
+
return path
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
_MCP_CONFIGURERS: dict[str, list[Callable[[list[str]], Optional[Path]]]] = {
|
|
286
|
+
"claude": [_configure_claude],
|
|
287
|
+
"codex": [_configure_codex],
|
|
288
|
+
"opencode": [_configure_opencode],
|
|
289
|
+
"copilot": [_configure_copilot_cli, _configure_vscode],
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def configure_mcp(agent: str, command: list[str]) -> list[Union[Path, MCPConfigError]]:
|
|
294
|
+
"""Point the agent's user MCP configs at the knowledge base ``command``.
|
|
295
|
+
|
|
296
|
+
Returns, per config file, the path written or the error that left it as
|
|
297
|
+
it was, so one file that can't be edited doesn't hide the others.
|
|
298
|
+
"""
|
|
299
|
+
results: list[Union[Path, MCPConfigError]] = []
|
|
300
|
+
for configure in _MCP_CONFIGURERS[agent]:
|
|
301
|
+
try:
|
|
302
|
+
path = configure(command)
|
|
303
|
+
except MCPConfigError as e:
|
|
304
|
+
results.append(e)
|
|
305
|
+
else:
|
|
306
|
+
if path is not None:
|
|
307
|
+
results.append(path)
|
|
308
|
+
return results
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# Session transcripts
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
@dataclass
|
|
315
|
+
class AgentSession:
|
|
316
|
+
agent: str
|
|
317
|
+
session_id: str
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
# Ordered: Codex sets both, and its rollout files are named after the thread.
|
|
321
|
+
_SESSION_ENV_VARS = (
|
|
322
|
+
("CLAUDE_CODE_SESSION_ID", "claude"),
|
|
323
|
+
("CODEX_THREAD_ID", "codex"),
|
|
324
|
+
("CODEX_SESSION_ID", "codex"),
|
|
325
|
+
("COPILOT_AGENT_SESSION_ID", "copilot"),
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def current_session() -> Optional[AgentSession]:
|
|
330
|
+
"""The agent session this process runs in, from the variables agents set
|
|
331
|
+
for the commands they run. OpenCode sets none.
|
|
332
|
+
|
|
333
|
+
An agent started from another agent's shell inherits the outer agent's
|
|
334
|
+
variables too, and nothing says which one is running this command. Rather
|
|
335
|
+
than attach the wrong conversation, that case counts as no session.
|
|
336
|
+
"""
|
|
337
|
+
sessions = {}
|
|
338
|
+
for var, agent in _SESSION_ENV_VARS:
|
|
339
|
+
value = (os.environ.get(var) or "").strip()
|
|
340
|
+
if value and agent not in sessions:
|
|
341
|
+
sessions[agent] = AgentSession(agent=agent, session_id=value)
|
|
342
|
+
return next(iter(sessions.values())) if len(sessions) == 1 else None
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def find_transcript(session: AgentSession) -> Optional[Path]:
|
|
346
|
+
if session.agent == "claude":
|
|
347
|
+
root = _home() / ".claude" / "projects"
|
|
348
|
+
pattern = f"{session.session_id}.jsonl"
|
|
349
|
+
elif session.agent == "codex":
|
|
350
|
+
root = _codex_home() / "sessions"
|
|
351
|
+
pattern = f"rollout-*-{session.session_id}.jsonl"
|
|
352
|
+
elif session.agent == "copilot":
|
|
353
|
+
path = _copilot_home() / "session-state" / session.session_id / "events.jsonl"
|
|
354
|
+
return path if path.exists() else None
|
|
355
|
+
else:
|
|
356
|
+
return None
|
|
357
|
+
if not root.exists():
|
|
358
|
+
return None
|
|
359
|
+
matches = sorted(root.rglob(pattern))
|
|
360
|
+
return matches[0] if matches else None
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def debug_log_path(session: AgentSession) -> Optional[Path]:
|
|
364
|
+
"""Only Claude Code keeps a per-session debug log."""
|
|
365
|
+
if session.agent != "claude":
|
|
366
|
+
return None
|
|
367
|
+
return _home() / ".claude" / "debug" / f"{session.session_id}.txt"
|
|
@@ -114,6 +114,7 @@ cli.placeholder("files", description=Messages.doc_files)
|
|
|
114
114
|
cli.placeholder("gcp", description=Messages.doc_gcp)
|
|
115
115
|
cli.placeholder("infra", description=Messages.doc_infra)
|
|
116
116
|
cli.placeholder("jobs", description=Messages.doc_jobs)
|
|
117
|
+
cli.placeholder("mcp", description=Messages.doc_mcp)
|
|
117
118
|
cli.placeholder("packages", description=Messages.doc_packages)
|
|
118
119
|
cli.placeholder("plans", description="Manage project plans")
|
|
119
120
|
cli.placeholder("paths", description=Messages.doc_paths)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import os
|
|
3
|
-
import
|
|
2
|
+
import shlex
|
|
3
|
+
import sys
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import Any, Dict, List, Literal, Optional, Union
|
|
6
6
|
from uuid import UUID
|
|
@@ -12,91 +12,111 @@ from wasabi import msg
|
|
|
12
12
|
from ellf_pam_sdk.models import OrgMembership
|
|
13
13
|
|
|
14
14
|
from .. import about
|
|
15
|
+
from ..agents import (
|
|
16
|
+
AGENT_NAMES,
|
|
17
|
+
AGENTS,
|
|
18
|
+
MCP_SERVER_NAME,
|
|
19
|
+
MCPConfigError,
|
|
20
|
+
configure_mcp,
|
|
21
|
+
ellf_skills_dir,
|
|
22
|
+
install_skills,
|
|
23
|
+
mcp_command,
|
|
24
|
+
)
|
|
15
25
|
from ..auth import AuthState
|
|
16
26
|
from ..cli import cli
|
|
17
27
|
from ..config import SavedSettings, global_config_dir
|
|
18
28
|
from ..errors import CLIError, EllfError, NoClustersError
|
|
19
29
|
from ..messages import CLUSTER_DOCS_URL, Messages
|
|
20
|
-
from ..ui import is_silent, print_as_json, print_mutation_result
|
|
30
|
+
from ..ui import is_silent, isatty, print_as_json, print_mutation_result
|
|
21
31
|
from ..util import URL
|
|
22
32
|
from ._cluster_select import select_cluster
|
|
23
33
|
from ._org_select import list_person_orgs, select_org
|
|
24
34
|
from ._state import get_auth_state, get_root_cfg, get_saved_settings
|
|
25
35
|
|
|
26
36
|
|
|
27
|
-
def
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
def _resolve_agents(agent: Optional[List[str]], claude: bool) -> List[str]:
|
|
38
|
+
agents = [
|
|
39
|
+
name.strip().lower()
|
|
40
|
+
for value in agent or []
|
|
41
|
+
for name in value.split(",")
|
|
42
|
+
if name.strip()
|
|
43
|
+
]
|
|
44
|
+
if claude:
|
|
45
|
+
agents.append("claude")
|
|
46
|
+
unknown = sorted(set(agents) - set(AGENTS))
|
|
47
|
+
if unknown:
|
|
48
|
+
raise CLIError(
|
|
49
|
+
f"Unknown agent: {', '.join(unknown)}",
|
|
50
|
+
f"Choose from: {', '.join(AGENTS)}",
|
|
51
|
+
)
|
|
52
|
+
return [a for a in AGENTS if a in agents]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _confirm_skill_removal(paths: List[Path]) -> bool:
|
|
56
|
+
"""Ask before removing skills an older ellf login installed. They're
|
|
57
|
+
named after Ellf skills but may hold the user's own edits."""
|
|
58
|
+
msg.warn("Found Ellf skills that Ellf no longer installs:")
|
|
59
|
+
for path in paths:
|
|
60
|
+
print(f" - {path}")
|
|
61
|
+
if isatty(sys.stdin) and isatty(sys.stdout):
|
|
62
|
+
if input("Remove them? [y/N]: ").strip().lower() in ("y", "yes"):
|
|
63
|
+
return True
|
|
64
|
+
print(
|
|
65
|
+
"Kept them. To remove them later, run: rm -rf "
|
|
66
|
+
+ " ".join(shlex.quote(str(path)) for path in paths)
|
|
67
|
+
)
|
|
68
|
+
return False
|
|
38
69
|
|
|
39
70
|
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
if
|
|
71
|
+
def _install_agent_skills(agents: List[str]) -> None:
|
|
72
|
+
skills_dir = ellf_skills_dir()
|
|
73
|
+
if skills_dir is None:
|
|
43
74
|
msg.warn(
|
|
44
|
-
"
|
|
45
|
-
"
|
|
75
|
+
"Packaged Ellf skills not found; skipping skill installation. "
|
|
76
|
+
"Reinstall ellf-cli to get them."
|
|
46
77
|
)
|
|
47
78
|
return
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
return
|
|
62
|
-
config.setdefault("mcpServers", {})
|
|
63
|
-
config["mcpServers"]["ellf-kb"] = {
|
|
64
|
-
"type": "http",
|
|
65
|
-
"url": mcp_url,
|
|
66
|
-
"headers": {"Authorization": f"Bearer {ellf_core_token}"},
|
|
67
|
-
}
|
|
68
|
-
tmp_path = claude_json_path.with_suffix(".json.tmp")
|
|
69
|
-
tmp_path.write_text(
|
|
70
|
-
json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8"
|
|
71
|
-
)
|
|
72
|
-
tmp_path.replace(claude_json_path)
|
|
73
|
-
msg.good(f"Configured ellf-kb MCP server in {claude_json_path}")
|
|
79
|
+
try:
|
|
80
|
+
installed = install_skills(agents, skills_dir, _confirm_skill_removal)
|
|
81
|
+
except (OSError, ValueError) as e:
|
|
82
|
+
msg.fail(
|
|
83
|
+
f"Could not install the Ellf skills: {e}",
|
|
84
|
+
"Fix that, then re-run 'ellf login --agent <agent>'.",
|
|
85
|
+
)
|
|
86
|
+
return
|
|
87
|
+
for dest, names in installed.items():
|
|
88
|
+
msg.good(f"Installed {len(names)} Ellf skills to {dest}")
|
|
89
|
+
for name in names:
|
|
90
|
+
print(f" - {name}")
|
|
74
91
|
|
|
75
92
|
|
|
76
|
-
def
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
def _configure_agent_mcp(auth: AuthState, agents: List[str]) -> None:
|
|
94
|
+
if not auth.get_ellf_core_token():
|
|
95
|
+
msg.warn(
|
|
96
|
+
"Could not get an ellf-core token, so the knowledge base MCP server "
|
|
97
|
+
"won't work until a fresh 'ellf login'."
|
|
98
|
+
)
|
|
99
|
+
command = mcp_command()
|
|
100
|
+
if command is None:
|
|
79
101
|
msg.warn(
|
|
80
|
-
"
|
|
81
|
-
"
|
|
102
|
+
"Could not find the ellf command; skipping MCP server configuration. "
|
|
103
|
+
"Run 'ellf login --agent <agent>' from the environment it's installed in."
|
|
82
104
|
)
|
|
83
105
|
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
for canonical_name in sorted(selected_skills):
|
|
99
|
-
print(f" - {canonical_name}")
|
|
106
|
+
for agent in agents:
|
|
107
|
+
try:
|
|
108
|
+
results = configure_mcp(agent, command)
|
|
109
|
+
except (OSError, ValueError) as e:
|
|
110
|
+
msg.fail(f"Could not configure {AGENT_NAMES[agent]}: {e}")
|
|
111
|
+
continue
|
|
112
|
+
for result in results:
|
|
113
|
+
if isinstance(result, MCPConfigError):
|
|
114
|
+
msg.fail(str(result), f"Add this to it by hand:\n{result.snippet}")
|
|
115
|
+
else:
|
|
116
|
+
msg.good(
|
|
117
|
+
f"Configured {MCP_SERVER_NAME} MCP server for "
|
|
118
|
+
f"{AGENT_NAMES[agent]} in {result}"
|
|
119
|
+
)
|
|
100
120
|
|
|
101
121
|
|
|
102
122
|
def _configure_venv_pypi(auth: AuthState, *, as_json: bool = False) -> None:
|
|
@@ -158,6 +178,7 @@ def _configure_venv_pypi(auth: AuthState, *, as_json: bool = False) -> None:
|
|
|
158
178
|
org=Arg("--org", help=Messages.login_org),
|
|
159
179
|
cluster=Arg("--cluster", help=Messages.login_cluster),
|
|
160
180
|
as_json=Arg("--json", help=Messages.as_json),
|
|
181
|
+
agent=Arg("--agent", help=Messages.login_agent),
|
|
161
182
|
claude=Arg("--claude", help=Messages.claude),
|
|
162
183
|
)
|
|
163
184
|
def login(
|
|
@@ -167,12 +188,14 @@ def login(
|
|
|
167
188
|
org: Optional[Union[str, UUID]] = None,
|
|
168
189
|
cluster: Optional[Union[str, UUID]] = None,
|
|
169
190
|
as_json: bool = False,
|
|
191
|
+
agent: Optional[List[str]] = None,
|
|
170
192
|
claude: bool = False,
|
|
171
193
|
) -> None:
|
|
172
194
|
"""
|
|
173
195
|
Log in to your Ellf account. You normally don't need to call this
|
|
174
196
|
manually. It will automatically authenticate when needed.
|
|
175
197
|
"""
|
|
198
|
+
agents = _resolve_agents(agent, claude)
|
|
176
199
|
auth = get_auth_state()
|
|
177
200
|
auth.no_browser = no_browser
|
|
178
201
|
auth._ensure_readable_secrets()
|
|
@@ -187,14 +210,14 @@ def login(
|
|
|
187
210
|
# --no-org keeps whatever org the device flow landed in, so the role
|
|
188
211
|
# check has to look that org's membership up itself.
|
|
189
212
|
_require_cli_role(_active_org_membership(auth))
|
|
190
|
-
if
|
|
191
|
-
#
|
|
213
|
+
if agents:
|
|
214
|
+
# Agent setup needs only the packaged skill assets and the
|
|
192
215
|
# ellf-core token minted by the device flow above — not the
|
|
193
216
|
# cluster. Run it before cluster selection so cluster failures
|
|
194
217
|
# (token mint errors, unreachable broker, no cluster registered)
|
|
195
218
|
# can't block skill installation.
|
|
196
|
-
|
|
197
|
-
|
|
219
|
+
_install_agent_skills(agents)
|
|
220
|
+
_configure_agent_mcp(auth, agents)
|
|
198
221
|
# Best-effort: needs only the api token minted above, and must not
|
|
199
222
|
# block login (or cluster selection below) when it fails.
|
|
200
223
|
_configure_venv_pypi(auth, as_json=as_json)
|