ellf-cli 4.0.151__tar.gz → 5.0.7__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.
Files changed (182) hide show
  1. {ellf_cli-4.0.151/ellf_cli.egg-info → ellf_cli-5.0.7}/PKG-INFO +1 -1
  2. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/README.md +11 -10
  3. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/about.json +1 -1
  4. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/auth.py +17 -4
  5. ellf_cli-5.0.7/ellf_cli/commands/_cluster_select.py +96 -0
  6. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/clusters.py +132 -8
  7. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/config.py +0 -20
  8. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/general.py +27 -2
  9. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf.json +50 -37
  10. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/messages.py +3 -3
  11. {ellf_cli-4.0.151 → ellf_cli-5.0.7/ellf_cli.egg-info}/PKG-INFO +1 -1
  12. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/SOURCES.txt +1 -0
  13. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/LICENSE +0 -0
  14. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/MANIFEST.in +0 -0
  15. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/__init__.py +0 -0
  16. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/__main__.py +0 -0
  17. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/about.py +0 -0
  18. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/appdirs.py +0 -0
  19. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/cli.py +0 -0
  20. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/cloud/__init__.py +0 -0
  21. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/cloud/gcp.py +0 -0
  22. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/cluster_config.py +0 -0
  23. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/__init__.py +0 -0
  24. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/_recipe_file.py +0 -0
  25. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/_recipe_subcommand.py +0 -0
  26. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/_state.py +0 -0
  27. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/actions.py +0 -0
  28. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/agents.py +0 -0
  29. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/assets.py +0 -0
  30. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/auth.py +0 -0
  31. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/datasets.py +0 -0
  32. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/__init__.py +0 -0
  33. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/cp.py +0 -0
  34. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/ls.py +0 -0
  35. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/rm.py +0 -0
  36. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/rsync.py +0 -0
  37. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/files/stats.py +0 -0
  38. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/import_export.py +0 -0
  39. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/__init__.py +0 -0
  40. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/_helpers.py +0 -0
  41. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/deploy.py +0 -0
  42. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/init_values.py +0 -0
  43. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/provision.py +0 -0
  44. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/register.py +0 -0
  45. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/setup.py +0 -0
  46. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/start.py +0 -0
  47. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/terraform.py +0 -0
  48. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/infra/tls.py +0 -0
  49. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/jobs.py +0 -0
  50. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/packages.py +0 -0
  51. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/paths.py +0 -0
  52. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/plans.py +0 -0
  53. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/projects.py +0 -0
  54. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/publish_code.py +0 -0
  55. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/publish_data.py +0 -0
  56. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/recipes.py +0 -0
  57. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/secrets.py +0 -0
  58. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/support.py +0 -0
  59. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/tasks.py +0 -0
  60. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/commands/todos.py +0 -0
  61. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/config.py +0 -0
  62. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/.claude-plugin/plugin.json +0 -0
  63. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/.gitignore +0 -0
  64. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/bin/write-current-session.py +0 -0
  65. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/hooks/hooks.json +0 -0
  66. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skill_variants.json +0 -0
  67. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/SKILL.md +0 -0
  68. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/annotation_audit.md +0 -0
  69. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/builtin_ellf_annotation_recipes.md +0 -0
  70. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/SKILL.md +0 -0
  71. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/annotation_audit.md +0 -0
  72. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_ellf_annotation_recipes.md +0 -0
  73. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_prodigy_recipes.md +0 -0
  74. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-ask/SKILL.md +0 -0
  75. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-handoff/SKILL.md +0 -0
  76. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/SKILL.md +0 -0
  77. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/annotation_metrics.md +0 -0
  78. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/training_monitoring.md +0 -0
  79. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/SKILL.md +0 -0
  80. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/annotation_metrics.md +0 -0
  81. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/training_monitoring.md +0 -0
  82. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/scripts/check_training.py +0 -0
  83. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-ops.assistant/SKILL.md +0 -0
  84. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-ops.coding/SKILL.md +0 -0
  85. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-ops.coding/scripts/run_job.py +0 -0
  86. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-patterns/SKILL.md +0 -0
  87. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-patterns/references/pattern_strategies.md +0 -0
  88. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/SKILL.md +0 -0
  89. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_action_recipe.py +0 -0
  90. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_agent_recipe.py +0 -0
  91. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_blocks_ui.py +0 -0
  92. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_correct.py +0 -0
  93. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_custom_ui.py +0 -0
  94. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_manual.py +0 -0
  95. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_pages_ui.py +0 -0
  96. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_routing.py +0 -0
  97. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_task_recipe.py +0 -0
  98. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_teach.py +0 -0
  99. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/builtin_recipes.md +0 -0
  100. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/ellf_recipe_sdk.md +0 -0
  101. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/lint_recipe.py +0 -0
  102. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/prodigy_recipe_api.md +0 -0
  103. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/template_index.md +0 -0
  104. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.assistant/SKILL.md +0 -0
  105. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/consulting_patterns.md +0 -0
  106. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/explosion_strategy.md +0 -0
  107. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/prodigy_llm_bot.md +0 -0
  108. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.coding/SKILL.md +0 -0
  109. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/consulting_patterns.md +0 -0
  110. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/explosion_strategy.md +0 -0
  111. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/prodigy_llm_bot.md +0 -0
  112. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-support.assistant/SKILL.md +0 -0
  113. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-support.coding/SKILL.md +0 -0
  114. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-todo/SKILL.md +0 -0
  115. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/SKILL.md +0 -0
  116. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/diagnostics.md +0 -0
  117. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/evaluation_guide.md +0 -0
  118. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/model_selection.md +0 -0
  119. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/training_paradigms.md +0 -0
  120. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/workflow.md +0 -0
  121. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/SKILL.md +0 -0
  122. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_advanced.md +0 -0
  123. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_architectures.md +0 -0
  124. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_training.md +0 -0
  125. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/diagnostics.md +0 -0
  126. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/evaluation_guide.md +0 -0
  127. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/experiment_patterns.md +0 -0
  128. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/model_selection.md +0 -0
  129. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_paradigms.md +0 -0
  130. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_troubleshooting.md +0 -0
  131. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/workflow.md +0 -0
  132. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ellf_skills/skills/ellf-train.coding/scripts/ellf_logger.py +0 -0
  133. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/errors.py +0 -0
  134. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/helm.py +0 -0
  135. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/key_pair.py +0 -0
  136. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/main.py +0 -0
  137. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/query.py +0 -0
  138. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/cookiecutter.json +0 -0
  139. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/.gitignore +0 -0
  140. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/README.md.tmpl +0 -0
  141. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements-dev.in +0 -0
  142. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements.in +0 -0
  143. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/setup.py.tmpl +0 -0
  144. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/__init__.py +0 -0
  145. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/about.py +0 -0
  146. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/__init__.py +0 -0
  147. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/example_task.py +0 -0
  148. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/testing/__init__.py +0 -0
  149. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ty.py +0 -0
  150. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/ui.py +0 -0
  151. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/url.py +0 -0
  152. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli/util.py +0 -0
  153. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/dependency_links.txt +0 -0
  154. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/entry_points.txt +0 -0
  155. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/not-zip-safe +0 -0
  156. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/requires.txt +0 -0
  157. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/ellf_cli.egg-info/top_level.txt +0 -0
  158. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/pyproject.toml +0 -0
  159. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/setup.cfg +0 -0
  160. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/setup.py +0 -0
  161. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_appdirs.py +0 -0
  162. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_auth.py +0 -0
  163. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_config.py +0 -0
  164. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_errors.py +0 -0
  165. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_files_cp.py +0 -0
  166. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_files_cp_helpers.py +0 -0
  167. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_info.py +0 -0
  168. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_invalid_secrets.py +0 -0
  169. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_key_pair.py +0 -0
  170. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_login.py +0 -0
  171. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_main.py +0 -0
  172. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_plans.py +0 -0
  173. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_projects.py +0 -0
  174. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_query.py +0 -0
  175. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_recipe_file.py +0 -0
  176. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_recipes.py +0 -0
  177. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_state.py +0 -0
  178. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_support.py +0 -0
  179. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_ty.py +0 -0
  180. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_ui.py +0 -0
  181. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_ui_extras.py +0 -0
  182. {ellf_cli-4.0.151 → ellf_cli-5.0.7}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ellf-cli
3
- Version: 4.0.151
3
+ Version: 5.0.7
4
4
  Summary: Ellf Command Line Interface
5
5
  Home-page: https://prodi.gy
6
6
  Author: ExplosionAI GmbH
@@ -326,6 +326,15 @@ List resources on the cluster
326
326
  | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'org_id', 'name', 'address', 'state'] | `['id', 'name', 'status', 'address']` |
327
327
  | `--json` | `bool` | Output the result as JSON | `False` |
328
328
 
329
+ #### `ellf clusters use`
330
+
331
+ Switch the active cluster. Looks up the cluster by name or ID via PAM. With no argument and multiple clusters available, prompts interactively in a TTY.
332
+
333
+ | Argument | Type | Description | Default |
334
+ | --- | --- | --- | --- |
335
+ | `name_or_id` | `str` | Name or ID of the cluster | `None` |
336
+ | `--json` | `bool` | Output the result as JSON | `False` |
337
+
329
338
  #### `ellf clusters info`
330
339
 
331
340
  Get detailed info for a cluster
@@ -357,7 +366,7 @@ Delete a cluster from PAM. This only removes PAM's record of it. The cluster its
357
366
 
358
367
  #### `ellf clusters check`
359
368
 
360
- Check the health of a cluster deployment. Runs CLI-side connectivity checks against the cluster and PAM. Use --deep to also trigger cluster-side deployment checks (K8s API, NFS, database, etc.).
369
+ Check the health of a cluster deployment. Runs CLI-side connectivity checks against the cluster and PAM. Use --deep (or supply --s3-bucket / --nfs-path / --recipe) to also trigger cluster-side deployment checks via the broker's /v1/check endpoints (K8s API, NFS, S3, recipe execution, DB).
361
370
 
362
371
  | Argument | Type | Description | Default |
363
372
  | --- | --- | --- | --- |
@@ -473,15 +482,6 @@ Set the default agent.
473
482
  | `cluster_id` | `UUID` | ID of the cluster to search for agent name (or the last cluster if not set) | `None` |
474
483
  | `--json` | `bool` | Output the result as JSON | `False` |
475
484
 
476
- #### `ellf config set-cluster-host`
477
-
478
- Set the cluster cluster host.
479
-
480
- | Argument | Type | Description | Default |
481
- | --- | --- | --- | --- |
482
- | `host` | `str` | Host or URL of the cluster | |
483
- | `--json` | `bool` | Output the result as JSON | `False` |
484
-
485
485
  #### `ellf config set-pam-host`
486
486
 
487
487
  Set the PAM host.
@@ -1070,6 +1070,7 @@ Log in to your Ellf account. You normally don't need to call this manually. It w
1070
1070
  | --- | --- | --- | --- |
1071
1071
  | `--no-cluster` | `bool` | Don't use a cluster | `False` |
1072
1072
  | `--no-browser` | `bool` | Don't open a browser, just print the login URL | `False` |
1073
+ | `--cluster` | `str` | Name or ID of the cluster to log into. If omitted: auto-select when only one is available, or prompt interactively | `None` |
1073
1074
  | `--json` | `bool` | Output the result as JSON | `False` |
1074
1075
  | `--claude` | `bool` | Install Ellf Claude Code skills and transcript hook into ~/.claude/ | `False` |
1075
1076
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "Ellf CLI",
3
3
  "name": "ellf-cli",
4
- "version": "4.0.151",
4
+ "version": "5.0.7",
5
5
  "summary": "Ellf Command Line Interface",
6
6
  "uri": "https://prodi.gy",
7
7
  "prog": "ellf",
@@ -164,6 +164,8 @@ class AuthState(Protocol):
164
164
 
165
165
  def _ensure_broker_host(self) -> None: ...
166
166
 
167
+ def set_active_cluster(self, cluster_id: UUID, broker_url: URL) -> None: ...
168
+
167
169
  def get_id_token(self, force_refresh: bool = False) -> str: ...
168
170
 
169
171
  def get_api_token(self, force_refresh: bool = False) -> AccessTokenCredential: ...
@@ -341,13 +343,24 @@ class AuthStateImpl:
341
343
  raise CLIError(Messages.E106)
342
344
  elif len(clusters) == 1:
343
345
  self._broker_url = URL.parse(clusters[0].address)
344
- get_saved_settings().update(
345
- "broker_host",
346
- self.broker_host,
347
- )
346
+ self._cluster_id = clusters[0].id
347
+ settings = get_saved_settings()
348
+ settings.update("broker_host", self.broker_host)
349
+ settings.update("cluster_id", self._cluster_id)
348
350
  else:
349
351
  raise CLIError(Messages.E107)
350
352
 
353
+ def set_active_cluster(self, cluster_id: UUID, broker_url: URL) -> None:
354
+ """Switch the active cluster in-memory.
355
+
356
+ Persisting to ``SavedSettings`` is the caller's responsibility — this
357
+ only updates the auth state so the next ``broker_client`` /
358
+ ``get_cluster_token`` call targets the new cluster.
359
+ """
360
+ self._broker_url = broker_url
361
+ self._cluster_id = cluster_id
362
+ self._cluster_client = None
363
+
351
364
  @staticmethod
352
365
  def _check_token_expired(
353
366
  token: AccessTokenCredential | BrokerAccessTokenCredential | str,
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+
3
+ import builtins
4
+ import sys
5
+ from typing import Union
6
+ from uuid import UUID
7
+
8
+ from wasabi import msg
9
+
10
+ from ellf_pam_sdk import Client
11
+ from ellf_pam_sdk.models import ClusterSummary
12
+
13
+ from ..errors import CLIError
14
+ from ..messages import Messages
15
+ from ..ui import isatty
16
+ from ..url import URL, URLError
17
+
18
+
19
+ def _normalize_address(address: str) -> str | None:
20
+ """Normalize an address-shaped string. Returns ``None`` when unparseable.
21
+
22
+ Pam-side and user-supplied URLs vary on trailing slashes and implicit
23
+ schemes, so we compare them in canonical form before deciding a
24
+ `--cluster <url>` argument matches a registered cluster.
25
+ """
26
+ try:
27
+ return str(URL.parse(address))
28
+ except URLError:
29
+ return None
30
+
31
+
32
+ def _match_cluster(
33
+ clusters: builtins.list[ClusterSummary],
34
+ name_or_id: Union[str, UUID],
35
+ ) -> ClusterSummary | None:
36
+ if isinstance(name_or_id, UUID):
37
+ for c in clusters:
38
+ if c.id == name_or_id:
39
+ return c
40
+ return None
41
+ needle = str(name_or_id)
42
+ for c in clusters:
43
+ if str(c.id) == needle or c.name == needle or c.address == needle:
44
+ return c
45
+ needle_url = _normalize_address(needle)
46
+ if needle_url is None:
47
+ return None
48
+ for c in clusters:
49
+ canonical = _normalize_address(c.address)
50
+ if canonical is not None and canonical == needle_url:
51
+ return c
52
+ return None
53
+
54
+
55
+ def _prompt_for_cluster(
56
+ clusters: builtins.list[ClusterSummary],
57
+ ) -> ClusterSummary:
58
+ if not isatty(sys.stdin) or not isatty(sys.stdout):
59
+ raise CLIError(Messages.E107)
60
+ msg.info("Multiple clusters are available:")
61
+ for idx, cluster in enumerate(clusters, start=1):
62
+ print(f" [{idx}] {cluster.name} ({cluster.address})")
63
+ while True:
64
+ raw = input(f"Pick a cluster [1-{len(clusters)}]: ").strip()
65
+ if raw.isdigit():
66
+ choice = int(raw)
67
+ if 1 <= choice <= len(clusters):
68
+ return clusters[choice - 1]
69
+ matched = _match_cluster(clusters, raw)
70
+ if matched is not None:
71
+ return matched
72
+ msg.warn(f"Invalid selection: {raw!r}")
73
+
74
+
75
+ def select_cluster(
76
+ client: Client,
77
+ name_or_id: Union[str, UUID, None] = None,
78
+ ) -> ClusterSummary:
79
+ """Pick a cluster the user has access to.
80
+
81
+ When ``name_or_id`` is provided, looks it up exactly. Otherwise:
82
+ auto-selects the only cluster, or prompts in a TTY when there are
83
+ multiple. Raises ``CLIError`` if no cluster is accessible or the
84
+ caller is non-interactive with multiple clusters.
85
+ """
86
+ clusters = builtins.list(client.cluster.all(page_size=100))
87
+ if not clusters:
88
+ raise CLIError(Messages.E106)
89
+ if name_or_id is not None:
90
+ matched = _match_cluster(clusters, name_or_id)
91
+ if matched is None:
92
+ raise CLIError(Messages.E038.format(noun="cluster", name_or_id=name_or_id))
93
+ return matched
94
+ if len(clusters) == 1:
95
+ return clusters[0]
96
+ return _prompt_for_cluster(clusters)
@@ -1,6 +1,8 @@
1
1
  import base64
2
2
  import builtins
3
+ import json
3
4
  import subprocess
5
+ import time
4
6
  import uuid
5
7
  from typing import Any, Optional, Union
6
8
  from uuid import UUID
@@ -10,6 +12,7 @@ import uuid_utils
10
12
  from radicli import Arg
11
13
  from wasabi import msg
12
14
 
15
+ from ellf_broker_sdk.models import CheckProgressRequest, CheckStartRequest
13
16
  from ellf_pam_sdk import models as ellf_pam_sdk_models
14
17
  from ellf_pam_sdk.models import (
15
18
  ClusterUpdating,
@@ -24,11 +27,12 @@ from ..errors import (
24
27
  RequestError,
25
28
  )
26
29
  from ..messages import Messages
27
- from ..query import resolve_cluster, resolve_cluster_id
30
+ from ..query import resolve_cluster, resolve_cluster_id, resolve_recipe
28
31
  from ..ty import ClusterStatusCheck
29
- from ..ui import print_info_table, print_table_with_select
32
+ from ..ui import print_info_table, print_mutation_result, print_table_with_select
30
33
  from ..util import URL
31
- from ._state import get_auth_state
34
+ from ._cluster_select import select_cluster
35
+ from ._state import get_auth_state, get_root_cfg, get_saved_settings
32
36
 
33
37
 
34
38
  def uuid7() -> uuid.UUID:
@@ -129,6 +133,42 @@ def list(
129
133
  return res
130
134
 
131
135
 
136
+ @cli.subcommand(
137
+ "clusters",
138
+ "use",
139
+ name_or_id=Arg(help=Messages.name_or_id.format(noun="cluster")),
140
+ as_json=Arg("--json", help=Messages.as_json),
141
+ )
142
+ def use(
143
+ name_or_id: Optional[Union[str, UUID]] = None,
144
+ as_json: bool = False,
145
+ ) -> UUID:
146
+ """Switch the active cluster.
147
+
148
+ Looks up the cluster by name or ID via PAM. With no argument and
149
+ multiple clusters available, prompts interactively in a TTY.
150
+ """
151
+ auth = get_auth_state()
152
+ chosen = select_cluster(auth.client, name_or_id)
153
+ broker_url = URL.parse(chosen.address)
154
+ settings = get_saved_settings()
155
+ settings.update("broker_host", str(broker_url))
156
+ settings.update("cluster_id", chosen.id)
157
+ settings.save(get_root_cfg().saved_settings_path)
158
+ auth.set_active_cluster(chosen.id, broker_url)
159
+ print_mutation_result(
160
+ {
161
+ "status": "ok",
162
+ "cluster_id": str(chosen.id),
163
+ "cluster_name": chosen.name,
164
+ "cluster_host": str(broker_url),
165
+ },
166
+ Messages.T019.format(noun="cluster", name=chosen.name),
167
+ as_json=as_json,
168
+ )
169
+ return chosen.id
170
+
171
+
132
172
  @cli.subcommand(
133
173
  "clusters",
134
174
  "info",
@@ -235,12 +275,12 @@ def check(
235
275
  """Check the health of a cluster deployment.
236
276
 
237
277
  Runs CLI-side connectivity checks against the cluster and PAM.
238
- Use --deep to also trigger cluster-side deployment checks (K8s API,
239
- NFS, database, etc.).
278
+ Use --deep (or supply --s3-bucket / --nfs-path / --recipe) to also
279
+ trigger cluster-side deployment checks via the broker's /v1/check
280
+ endpoints (K8s API, NFS, S3, recipe execution, DB).
240
281
  """
241
282
  auth = get_auth_state()
242
283
  results: builtins.list[tuple[str, bool]] = []
243
- # Resolve the cluster to check
244
284
  if name_or_id:
245
285
  cluster = resolve_cluster(name_or_id)
246
286
  else:
@@ -252,7 +292,6 @@ def check(
252
292
  raise SystemExit(1)
253
293
  cluster = clusters[0]
254
294
  broker_url = URL.parse(cluster.address)
255
- # 1. Cluster API responding
256
295
  try:
257
296
  r = httpx.get(f"{broker_url}/api/v1/status", timeout=10)
258
297
  r.raise_for_status()
@@ -260,7 +299,6 @@ def check(
260
299
  api_ok = payload.get("status") == "Ready"
261
300
  cluster_ok = payload.get("cluster") == "Ready"
262
301
  results.append(_check_result(f"Cluster API responding on {broker_url}", api_ok))
263
- # 2. Cluster status (K8s connectivity from cluster)
264
302
  if api_ok:
265
303
  results.append(
266
304
  _check_result(
@@ -292,6 +330,92 @@ def check(
292
330
  )
293
331
  )
294
332
 
333
+ if deep or s3_bucket or nfs_path or recipe_name_or_id:
334
+ results.extend(
335
+ _run_deep_checks(
336
+ s3_bucket=s3_bucket,
337
+ nfs_path=nfs_path,
338
+ recipe_name_or_id=recipe_name_or_id,
339
+ recipe_args=recipe_args,
340
+ )
341
+ )
342
+
343
+ if any(not ok for _, ok in results):
344
+ raise SystemExit(1)
345
+
346
+
347
+ def _parse_recipe_args(recipe_args: Optional[str]) -> dict[str, Any]:
348
+ if not recipe_args:
349
+ return {}
350
+ try:
351
+ parsed = json.loads(recipe_args)
352
+ except json.JSONDecodeError as exc:
353
+ msg.fail(f"--recipe-args must be valid JSON: {exc}")
354
+ raise SystemExit(1)
355
+ if not isinstance(parsed, dict):
356
+ msg.fail("--recipe-args must be a JSON object")
357
+ raise SystemExit(1)
358
+ return parsed
359
+
360
+
361
+ def _run_deep_checks(
362
+ *,
363
+ s3_bucket: Optional[str],
364
+ nfs_path: Optional[str],
365
+ recipe_name_or_id: Optional[Union[str, UUID]],
366
+ recipe_args: Optional[str],
367
+ ) -> builtins.list[tuple[str, bool]]:
368
+ """Drive the broker's /v1/check/start + /v1/check/progress polling loop.
369
+
370
+ Returns one (label, ok) tuple per individual sub-check that ran on the
371
+ cluster. "skip" results are reported as ok=True with a "skipped"
372
+ detail — they mean the broker didn't have enough config to run that
373
+ particular check, not that anything failed.
374
+ """
375
+ auth = get_auth_state()
376
+ recipe_name: Optional[str] = None
377
+ if recipe_name_or_id is not None:
378
+ recipe = resolve_recipe(recipe_name_or_id, cluster_id=None)
379
+ recipe_name = recipe.name
380
+ body = CheckStartRequest(
381
+ s3_bucket=s3_bucket,
382
+ nfs_path=nfs_path,
383
+ recipe_name=recipe_name,
384
+ recipe_args=_parse_recipe_args(recipe_args) if recipe_args else None,
385
+ package_environment=None,
386
+ )
387
+ msg.info("Starting cluster-side deployment checks...")
388
+ started = auth.broker_client.check.start(body)
389
+ deadline = time.time() + 300
390
+ poll_interval = 2.0
391
+ report: Optional[dict[str, str]] = None
392
+ while time.time() < deadline:
393
+ progress = auth.broker_client.check.progress(
394
+ CheckProgressRequest(id=started.id)
395
+ )
396
+ if progress.status.value == "done":
397
+ report = progress.report if isinstance(progress.report, dict) else None
398
+ break
399
+ time.sleep(poll_interval)
400
+ if report is None:
401
+ return [
402
+ _check_result(
403
+ "Cluster-side deployment checks",
404
+ False,
405
+ detail="timed out waiting for broker to finish",
406
+ )
407
+ ]
408
+ rows: builtins.list[tuple[str, bool]] = []
409
+ for name, outcome in sorted(report.items()):
410
+ label = f"cluster: {name}"
411
+ if outcome == "success":
412
+ rows.append(_check_result(label, True))
413
+ elif outcome == "skip":
414
+ rows.append(_check_result(label, True, detail="skipped"))
415
+ else:
416
+ rows.append(_check_result(label, False, detail=str(outcome)))
417
+ return rows
418
+
295
419
 
296
420
  @cli.subcommand(
297
421
  "clusters",
@@ -149,26 +149,6 @@ def agent(
149
149
  return agent_id
150
150
 
151
151
 
152
- @cli.subcommand(
153
- "config",
154
- "set-cluster-host",
155
- host=Arg(help=Messages.cluster_host_config),
156
- as_json=Arg("--json", help=Messages.as_json),
157
- )
158
- def set_broker_host(host: str, as_json: bool = False) -> None:
159
- """Set the cluster cluster host."""
160
- root_cfg = get_root_cfg()
161
- host_url = URL.parse(host)
162
- settings = get_saved_settings()
163
- settings.update("broker_host", str(host_url))
164
- settings.save(root_cfg.saved_settings_path)
165
- print_mutation_result(
166
- {"status": "ok", "cluster_host": str(host_url)},
167
- Messages.T019.format(noun="cluster host", name=host),
168
- as_json=as_json,
169
- )
170
-
171
-
172
152
  @cli.subcommand(
173
153
  "config",
174
154
  "set-pam-host",
@@ -1,7 +1,8 @@
1
1
  import json
2
2
  import shutil
3
3
  from pathlib import Path
4
- from typing import Any, Dict, List, Literal, Optional
4
+ from typing import Any, Dict, List, Literal, Optional, Union
5
+ from uuid import UUID
5
6
 
6
7
  import httpx
7
8
  from radicli import Arg
@@ -14,7 +15,9 @@ from ..config import SavedSettings, global_config_dir
14
15
  from ..errors import CLIError, EllfError
15
16
  from ..messages import Messages
16
17
  from ..ui import print_as_json, print_mutation_result
17
- from ._state import get_auth_state, get_root_cfg
18
+ from ..util import URL
19
+ from ._cluster_select import select_cluster
20
+ from ._state import get_auth_state, get_root_cfg, get_saved_settings
18
21
 
19
22
 
20
23
  def _ellf_claude_plugin_dir() -> Path | None:
@@ -60,12 +63,14 @@ def _install_claude_skills() -> None:
60
63
  "login",
61
64
  no_cluster=Arg("--no-cluster", help=Messages.no_cluster),
62
65
  no_browser=Arg("--no-browser", help=Messages.no_browser),
66
+ cluster=Arg("--cluster", help=Messages.login_cluster),
63
67
  as_json=Arg("--json", help=Messages.as_json),
64
68
  claude=Arg("--claude", help=Messages.claude),
65
69
  )
66
70
  def login(
67
71
  no_cluster: bool = False,
68
72
  no_browser: bool = False,
73
+ cluster: Optional[Union[str, UUID]] = None,
69
74
  as_json: bool = False,
70
75
  claude: bool = False,
71
76
  ) -> None:
@@ -79,6 +84,7 @@ def login(
79
84
  auth.get_api_token(force_refresh=True)
80
85
  if not no_cluster:
81
86
  try:
87
+ _select_and_persist_cluster(auth, cluster)
82
88
  auth.get_cluster_token(force_refresh=True)
83
89
  except EllfError as e:
84
90
  err = Messages.E116.format(command=f"{cli.prog} login --no-cluster")
@@ -92,6 +98,25 @@ def login(
92
98
  _install_claude_skills()
93
99
 
94
100
 
101
+ def _select_and_persist_cluster(
102
+ auth: AuthState,
103
+ name_or_id: Optional[Union[str, UUID]] = None,
104
+ ) -> UUID:
105
+ """Pick a cluster via pam and write it into SavedSettings.
106
+
107
+ Mutates ``auth`` so subsequent ``get_cluster_token`` / ``broker_client``
108
+ calls in the same process use the chosen cluster without re-querying.
109
+ """
110
+ chosen = select_cluster(auth.client, name_or_id)
111
+ broker_url = URL.parse(chosen.address)
112
+ settings = get_saved_settings()
113
+ settings.update("broker_host", str(broker_url))
114
+ settings.update("cluster_id", chosen.id)
115
+ settings.save(get_root_cfg().saved_settings_path)
116
+ auth.set_active_cluster(chosen.id, broker_url)
117
+ return chosen.id
118
+
119
+
95
120
  @cli.command("info", field=Arg(help=Messages.select_field))
96
121
  def info(field: Optional[Literal["config-dir", "code", "defaults"]] = None) -> Any:
97
122
  """Print information about the CLI"""
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "prog": "ellf",
3
3
  "help": "Ellf Command Line Interface.",
4
- "version": "4.0.150",
4
+ "version": "5.0.6",
5
5
  "extra_key": "_extra",
6
6
  "commands": {
7
7
  "actions": {
@@ -177,6 +177,19 @@
177
177
  "type": null,
178
178
  "orig_type": "bool"
179
179
  },
180
+ {
181
+ "id": "cluster",
182
+ "option": "--cluster",
183
+ "short": null,
184
+ "orig_help": "Name or ID of the cluster to log into. If omitted: auto-select when only one is available, or prompt interactively",
185
+ "default": null,
186
+ "help": "Name or ID of the cluster to log into. If omitted: auto-select when only one is available, or prompt interactively (str)",
187
+ "action": null,
188
+ "choices": null,
189
+ "has_converter": false,
190
+ "type": "str",
191
+ "orig_type": "str"
192
+ },
180
193
  {
181
194
  "id": "as_json",
182
195
  "option": "--json",
@@ -1777,6 +1790,41 @@
1777
1790
  "parent": "clusters",
1778
1791
  "is_placeholder": false
1779
1792
  },
1793
+ "use": {
1794
+ "name": "use",
1795
+ "args": [
1796
+ {
1797
+ "id": "name_or_id",
1798
+ "option": null,
1799
+ "short": null,
1800
+ "orig_help": "Name or ID of the cluster",
1801
+ "default": null,
1802
+ "help": "Name or ID of the cluster (str)",
1803
+ "action": null,
1804
+ "choices": null,
1805
+ "has_converter": false,
1806
+ "type": "str",
1807
+ "orig_type": "str"
1808
+ },
1809
+ {
1810
+ "id": "as_json",
1811
+ "option": "--json",
1812
+ "short": null,
1813
+ "orig_help": "Output the result as JSON",
1814
+ "default": false,
1815
+ "help": "Output the result as JSON (bool)",
1816
+ "action": "store_true",
1817
+ "choices": null,
1818
+ "has_converter": false,
1819
+ "type": null,
1820
+ "orig_type": "bool"
1821
+ }
1822
+ ],
1823
+ "description": "Switch the active cluster.\n\nLooks up the cluster by name or ID via PAM. With no argument and\nmultiple clusters available, prompts interactively in a TTY.\n",
1824
+ "allow_extra": false,
1825
+ "parent": "clusters",
1826
+ "is_placeholder": false
1827
+ },
1780
1828
  "info": {
1781
1829
  "name": "info",
1782
1830
  "args": [
@@ -1990,7 +2038,7 @@
1990
2038
  "orig_type": "bool"
1991
2039
  }
1992
2040
  ],
1993
- "description": "Check the health of a cluster deployment.\n\nRuns CLI-side connectivity checks against the cluster and PAM.\nUse --deep to also trigger cluster-side deployment checks (K8s API,\nNFS, database, etc.).\n",
2041
+ "description": "Check the health of a cluster deployment.\n\nRuns CLI-side connectivity checks against the cluster and PAM.\nUse --deep (or supply --s3-bucket / --nfs-path / --recipe) to also\ntrigger cluster-side deployment checks via the broker's /v1/check\nendpoints (K8s API, NFS, S3, recipe execution, DB).\n",
1994
2042
  "allow_extra": false,
1995
2043
  "parent": "clusters",
1996
2044
  "is_placeholder": false
@@ -2490,41 +2538,6 @@
2490
2538
  "parent": "config",
2491
2539
  "is_placeholder": false
2492
2540
  },
2493
- "set-cluster-host": {
2494
- "name": "set-cluster-host",
2495
- "args": [
2496
- {
2497
- "id": "host",
2498
- "option": null,
2499
- "short": null,
2500
- "orig_help": "Host or URL of the cluster",
2501
- "default": "==SUPPRESS==",
2502
- "help": "Host or URL of the cluster (str)",
2503
- "action": null,
2504
- "choices": null,
2505
- "has_converter": false,
2506
- "type": "str",
2507
- "orig_type": "str"
2508
- },
2509
- {
2510
- "id": "as_json",
2511
- "option": "--json",
2512
- "short": null,
2513
- "orig_help": "Output the result as JSON",
2514
- "default": false,
2515
- "help": "Output the result as JSON (bool)",
2516
- "action": "store_true",
2517
- "choices": null,
2518
- "has_converter": false,
2519
- "type": null,
2520
- "orig_type": "bool"
2521
- }
2522
- ],
2523
- "description": "Set the cluster cluster host.",
2524
- "allow_extra": false,
2525
- "parent": "config",
2526
- "is_placeholder": false
2527
- },
2528
2541
  "set-pam-host": {
2529
2542
  "name": "set-pam-host",
2530
2543
  "args": [
@@ -36,7 +36,7 @@ class Messages:
36
36
  E032 = "Login failed: the device authentication API sent an incomplete response"
37
37
  E033 = "Login failed: unable to load CLI config from {url}"
38
38
  E034 = "{code} {reason} for URL {url}"
39
- E035 = "Cluster host unset: use the config set-cluster-host command to provide a cluster URL"
39
+ E035 = "No active cluster: run `ellf login` to pick one (or `ellf clusters use <name>` to switch)"
40
40
  E036 = "Cluster ID unset"
41
41
  E038 = "Could not find {noun}: {name_or_id}"
42
42
  E039 = "Authentication error: {message}"
@@ -168,10 +168,10 @@ ellf secret create my-credentials OPENAI_API_KEY="sk-..." CUSTOM_SECRET=-
168
168
  asset_kind = "Kind of the asset. Generally one of: ['Input', 'Model', 'Patterns]"
169
169
  asset_meta = "Asset meta, formatted as a JSON string"
170
170
  output_dir = "Output directory for the {noun}"
171
- cluster_host_config = "Host or URL of the cluster"
172
171
  pam_host_config = "Host or URL of the Prodigy Annotation Manager (PAM) app"
173
172
  no_cluster = "Don't use a cluster"
174
173
  no_browser = "Don't open a browser, just print the login URL"
174
+ login_cluster = "Name or ID of the cluster to log into. If omitted: auto-select when only one is available, or prompt interactively"
175
175
  claude = "Install Ellf Claude Code skills and transcript hook into ~/.claude/"
176
176
  use_active_venv = "Use the currently active virtualenv, instead of making a temporary one"
177
177
  filter_by = "Filter by {filter}"
@@ -211,7 +211,7 @@ ellf secret create my-credentials OPENAI_API_KEY="sk-..." CUSTOM_SECRET=-
211
211
  E104 = "Error authenticating device and user with Ellf"
212
212
  E105 = "Error communicating with Ellf API"
213
213
  E106 = "No clusters registered"
214
- E107 = "Multiple clusters registered, pick one with --cluster-host"
214
+ E107 = "Multiple clusters available. Run `ellf login --cluster <name>` (or `ellf clusters use <name>`) to pick one"
215
215
  E116 = "Could not login to cluster. Run {command} to log in to without connecting to a cluster"
216
216
  E117 = "Unrecognized token type {token_type!r}"
217
217
  E118 = "Error requesting recipe schemas"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ellf-cli
3
- Version: 4.0.151
3
+ Version: 5.0.7
4
4
  Summary: Ellf Command Line Interface
5
5
  Home-page: https://prodi.gy
6
6
  Author: ExplosionAI GmbH
@@ -34,6 +34,7 @@ ellf_cli.egg-info/top_level.txt
34
34
  ellf_cli/cloud/__init__.py
35
35
  ellf_cli/cloud/gcp.py
36
36
  ellf_cli/commands/__init__.py
37
+ ellf_cli/commands/_cluster_select.py
37
38
  ellf_cli/commands/_recipe_file.py
38
39
  ellf_cli/commands/_recipe_subcommand.py
39
40
  ellf_cli/commands/_state.py
File without changes
File without changes
File without changes