ellf-cli 22.0.4__tar.gz → 22.0.6__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 (431) hide show
  1. {ellf_cli-22.0.4/ellf_cli.egg-info → ellf_cli-22.0.6}/PKG-INFO +1 -1
  2. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/README.md +15 -15
  3. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/cli.py +40 -3
  4. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/cluster_config.py +1 -13
  5. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/clusters.py +31 -6
  6. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/_helpers.py +51 -44
  7. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/deploy.py +119 -50
  8. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/init.py +3 -5
  9. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/init_values.py +47 -53
  10. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/register.py +19 -27
  11. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/start.py +8 -12
  12. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/plans.py +3 -2
  13. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/sessions.py +5 -1
  14. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf.json +55 -55
  15. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/helm.py +21 -28
  16. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/messages.py +2 -1
  17. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ty.py +2 -0
  18. ellf_cli-22.0.6/ellf_cli/version/22.0.4_2026-11-01-12-41-57_patch_1af4ec08-f257-4eb8-99ba-3ad69b89f4e7 +3 -0
  19. ellf_cli-22.0.6/ellf_cli/version/22.0.5_2026-11-02-09-07-46_patch_9f15d4c1-bb21-4582-bdc7-b950c6d02f92 +3 -0
  20. {ellf_cli-22.0.4 → ellf_cli-22.0.6/ellf_cli.egg-info}/PKG-INFO +1 -1
  21. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/SOURCES.txt +3 -0
  22. ellf_cli-22.0.6/tests/test_cluster_status.py +46 -0
  23. ellf_cli-22.0.6/tests/test_infra_deploy_registry_key.py +243 -0
  24. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_init.py +6 -5
  25. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_register.py +16 -20
  26. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_start_fixes.py +10 -14
  27. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_tls.py +10 -18
  28. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_sessions.py +10 -6
  29. ellf_cli-22.0.4/tests/test_infra_deploy_registry_key.py +0 -46
  30. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/LICENSE +0 -0
  31. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/MANIFEST.in +0 -0
  32. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/__init__.py +0 -0
  33. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/__main__.py +0 -0
  34. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/about.json +0 -0
  35. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/about.py +0 -0
  36. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/agents.py +0 -0
  37. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/appdirs.py +0 -0
  38. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/auth.py +0 -0
  39. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/cloud/__init__.py +0 -0
  40. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/cloud/gcp.py +0 -0
  41. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/__init__.py +0 -0
  42. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_cluster_select.py +0 -0
  43. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_org_select.py +0 -0
  44. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_project_scope.py +0 -0
  45. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_recipe_file.py +0 -0
  46. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_recipe_subcommand.py +0 -0
  47. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_state.py +0 -0
  48. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/_usage.py +0 -0
  49. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/actions.py +0 -0
  50. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/agents.py +0 -0
  51. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/assets.py +0 -0
  52. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/config.py +0 -0
  53. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/datasets.py +0 -0
  54. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/__init__.py +0 -0
  55. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/cp.py +0 -0
  56. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/ls.py +0 -0
  57. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/rm.py +0 -0
  58. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/rsync.py +0 -0
  59. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/files/stats.py +0 -0
  60. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/general.py +0 -0
  61. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/import_export.py +0 -0
  62. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/__init__.py +0 -0
  63. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/_config_io.py +0 -0
  64. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/configure.py +0 -0
  65. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/hibernate.py +0 -0
  66. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/pause.py +0 -0
  67. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/provision.py +0 -0
  68. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/setup.py +0 -0
  69. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/terraform.py +0 -0
  70. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/infra/tls.py +0 -0
  71. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/jobs.py +0 -0
  72. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/mcp.py +0 -0
  73. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/packages.py +0 -0
  74. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/paths.py +0 -0
  75. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/projects.py +0 -0
  76. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/publish_code.py +0 -0
  77. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/publish_data.py +0 -0
  78. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/recipes.py +0 -0
  79. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/secrets.py +0 -0
  80. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/services.py +0 -0
  81. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/support.py +0 -0
  82. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/tasks.py +0 -0
  83. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/todos.py +0 -0
  84. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/commands/users.py +0 -0
  85. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/config.py +0 -0
  86. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/.gitignore +0 -0
  87. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/render.py +0 -0
  88. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/SKILL.assistant.md +0 -0
  89. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/SKILL.coding.md +0 -0
  90. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/annotation_audit.assistant.md +0 -0
  91. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/annotation_audit.coding.md +0 -0
  92. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_ellf_annotation_recipes.assistant.md +0 -0
  93. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_ellf_annotation_recipes.coding.md +0 -0
  94. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/builtin_prodigy_recipes.coding.md +0 -0
  95. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/label_schemes.assistant.md +0 -0
  96. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-annotate/references/label_schemes.coding.md +0 -0
  97. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-ask/SKILL.md +0 -0
  98. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-handoff/SKILL.assistant.md +0 -0
  99. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/SKILL.assistant.md +0 -0
  100. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/SKILL.coding.md +0 -0
  101. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/references/annotation_metrics.assistant.md +0 -0
  102. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/references/annotation_metrics.coding.md +0 -0
  103. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/references/training_monitoring.assistant.md +0 -0
  104. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/references/training_monitoring.coding.md +0 -0
  105. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-monitor/scripts.coding/check_training.py +0 -0
  106. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-ops/SKILL.assistant.md +0 -0
  107. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-ops/SKILL.coding.md +0 -0
  108. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-ops/references.coding/data_infra_cli.md +0 -0
  109. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-ops/scripts.coding/run_job.py +0 -0
  110. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-patterns/SKILL.coding.md +0 -0
  111. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-patterns/references/pattern_strategies.md +0 -0
  112. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/SKILL.coding.md +0 -0
  113. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_action_recipe.py +0 -0
  114. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_agent_recipe.py +0 -0
  115. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_blocks_ui.py +0 -0
  116. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_correct.py +0 -0
  117. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_custom_ui.py +0 -0
  118. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_manual.py +0 -0
  119. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_pages_ui.py +0 -0
  120. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_routing.py +0 -0
  121. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_service_recipe.py +0 -0
  122. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_task_recipe.py +0 -0
  123. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_teach.py +0 -0
  124. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/builtin_recipes.md +0 -0
  125. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/ellf_recipe_sdk.md +0 -0
  126. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/lint_recipe.py +0 -0
  127. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/prodigy_recipe_api.md +0 -0
  128. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/template_index.md +0 -0
  129. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/SKILL.assistant.md +0 -0
  130. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/SKILL.coding.md +0 -0
  131. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/annotation_agents.md +0 -0
  132. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/consulting_patterns.md +0 -0
  133. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/explosion_strategy.md +0 -0
  134. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/jev.coding.md +0 -0
  135. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/label_schemes.assistant.md +0 -0
  136. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-project/references/label_schemes.coding.md +0 -0
  137. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-support/SKILL.assistant.md +0 -0
  138. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-support/SKILL.coding.md +0 -0
  139. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-template/SKILL.coding.md +0 -0
  140. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-template/references/template_format.md +0 -0
  141. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-template/scripts/placeholders.py +0 -0
  142. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-todo/SKILL.coding.md +0 -0
  143. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/SKILL.assistant.md +0 -0
  144. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/SKILL.coding.md +0 -0
  145. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/config_advanced.coding.md +0 -0
  146. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/config_architectures.coding.md +0 -0
  147. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/config_training.coding.md +0 -0
  148. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/diagnostics.md +0 -0
  149. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/evaluation_guide.md +0 -0
  150. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/experiment_patterns.coding.md +0 -0
  151. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/model_selection.md +0 -0
  152. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/training_paradigms.md +0 -0
  153. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/training_troubleshooting.coding.md +0 -0
  154. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/workflow.assistant.md +0 -0
  155. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/references/workflow.coding.md +0 -0
  156. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ellf_skills/skills/ellf-train/scripts.coding/ellf_logger.py +0 -0
  157. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/errors.py +0 -0
  158. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/interactivity.py +0 -0
  159. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/key_pair.py +0 -0
  160. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/main.py +0 -0
  161. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/mcp_proxy.py +0 -0
  162. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/pypi_auth.py +0 -0
  163. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/query.py +0 -0
  164. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/cookiecutter.json +0 -0
  165. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/.gitignore +0 -0
  166. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/README.md.tmpl +0 -0
  167. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements-dev.in +0 -0
  168. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements.in +0 -0
  169. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/setup.py.tmpl +0 -0
  170. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/__init__.py +0 -0
  171. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/about.py +0 -0
  172. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/__init__.py +0 -0
  173. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/example_task.py +0 -0
  174. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/testing/__init__.py +0 -0
  175. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/ui.py +0 -0
  176. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/url.py +0 -0
  177. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/util.py +0 -0
  178. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.114_2026-08-19-08-36-57__1a4e37c1-471e-4a81-b4d5-1ffe7dec3a61 +0 -0
  179. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.114_2026-08-19-09-25-21_patch_33ff1e26-0e5e-46d8-8052-ab1d032e8b6c +0 -0
  180. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.115_2026-08-19-09-27-13_patch_4ac728c3-0342-4a36-adbc-e28d2d99b1ba +0 -0
  181. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.116_2026-08-19-09-30-47_patch_c706fef6-6813-4183-b268-12e7b00d7d0b +0 -0
  182. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.117_2026-08-19-09-39-14_patch_c6b0495f-2f88-4aa8-9ebf-0a235b4c407e +0 -0
  183. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.118_2026-08-19-09-52-00_patch_b395655a-8d78-4344-9266-6901c20f6517 +0 -0
  184. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.119_2026-08-19-10-22-38_patch_8f95c49d-aedc-41b8-816d-ccb95f048831 +0 -0
  185. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.120_2026-08-19-10-26-58_patch_7fbf35e6-cc01-4b75-8c9a-f5d054bcaf93 +0 -0
  186. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.121_2026-08-19-10-42-02_patch_31a81b02-a886-4dea-84e0-67cc6ca412d5 +0 -0
  187. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.122_2026-08-19-11-16-49_patch_1c4d7307-48d4-493e-936d-80af799d644b +0 -0
  188. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.123_2026-08-19-11-47-32_patch_d3d78d04-9989-45b1-91b1-93b571d8814a +0 -0
  189. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.124_2026-08-20-08-03-17_patch_57f4c389-2d19-41ce-aca4-13b61c62f387 +0 -0
  190. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.125_2026-08-20-08-25-05_patch_7f368148-0d1c-4525-bbdf-c6d257ad861a +0 -0
  191. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.126_2026-08-20-14-51-36_patch_a99abcc8-3371-4c63-a759-bb7ea5b32432 +0 -0
  192. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.127_2026-08-21-05-48-58_patch_34b4ccee-7596-4f57-93e9-774973cca58e +0 -0
  193. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.128_2026-08-21-10-47-20_patch_693112b9-927c-4a8f-8553-b06eef86079d +0 -0
  194. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.129_2026-08-21-11-16-54_patch_7a981666-01d9-4d1b-9ba3-2129744e3bd5 +0 -0
  195. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.130_2026-08-21-13-09-36_patch_b7ad1a76-ce70-4d70-9d1a-7c414eba5bb4 +0 -0
  196. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.131_2026-08-21-14-31-10_patch_9128ef66-193e-4caf-8710-afd86128e638 +0 -0
  197. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.132_2026-08-24-08-59-34_patch_c600fc14-86a5-460f-9c4e-f0177056f756 +0 -0
  198. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.133_2026-08-24-10-28-29_patch_b6ce3e32-9d7b-48ac-981a-270c22c180dd +0 -0
  199. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.134_2026-08-24-11-00-51_patch_a4fc0484-4a64-46a2-94f8-aa805254c7b0 +0 -0
  200. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.135_2026-08-24-12-12-41_patch_a870a56f-9a65-49eb-92da-f572b26667d8 +0 -0
  201. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.136_2026-08-24-12-42-46_patch_9b399356-6482-4291-8da7-e748a99c4b53 +0 -0
  202. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.137_2026-08-24-12-53-57_patch_f7979348-1910-40cd-a535-90299eca84ee +0 -0
  203. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.138_2026-08-24-14-36-30_patch_ed0f8750-f663-498b-85e7-0d3f2213fcfe +0 -0
  204. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.139_2026-08-25-08-37-26_patch_3ba87e19-902b-4f76-b64c-90e5c0ca1fc6 +0 -0
  205. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.140_2026-08-25-09-52-45_patch_abc830f2-df15-4385-b797-cdaf72c10752 +0 -0
  206. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.141_2026-08-25-11-37-20_patch_1d9ec01e-06f6-4c8e-b095-af17d5b62b00 +0 -0
  207. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.142_2026-08-26-07-38-49_patch_3dd23e36-e7df-494c-986f-a412861a8d40 +0 -0
  208. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.143_2026-08-26-09-32-32_patch_7b7ebd34-de27-4b73-98a7-3e1501e16cd5 +0 -0
  209. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.144_2026-08-26-10-56-43_patch_166064f2-2208-4c9b-9e25-25dc4cd32084 +0 -0
  210. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.145_2026-08-26-11-37-29_patch_b997f3ee-d7d3-4408-9f2f-c8b6d08bdb3b +0 -0
  211. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.146_2026-08-26-12-15-20_patch_afbbb893-25db-468c-81db-2663ca373068 +0 -0
  212. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.147_2026-08-26-14-10-50_patch_fd753b1f-2fa1-4ddb-a9e7-de690da85254 +0 -0
  213. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.148_2026-08-27-09-08-35_patch_23814c0b-7f77-489c-b4a8-ceadd18146e3 +0 -0
  214. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.149_2026-08-27-09-40-17_patch_8879d72e-a3d8-4abc-a16a-d9dcf75f0fa1 +0 -0
  215. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.150_2026-08-27-10-57-25_patch_afbe60ed-3e23-4d88-be3c-f800d7002a7d +0 -0
  216. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.151_2026-08-28-09-02-46_patch_1d4ca23b-aeae-4ea8-96b1-8cf57371f29d +0 -0
  217. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.152_2026-08-28-15-37-24_patch_c9d0bdc1-a7e1-432b-92b9-92dc76fe0c78 +0 -0
  218. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.153_2026-08-29-09-03-27_patch_7531573a-1b33-4092-aa9c-0e65f47b201f +0 -0
  219. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.154_2026-08-29-11-56-35_patch_919f5787-39c8-4dc1-ae6a-f27c28380f21 +0 -0
  220. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.155_2026-08-29-15-15-59_patch_822f9ed8-c366-4e5f-9791-dee8467cf3ce +0 -0
  221. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.156_2026-08-29-16-19-01_patch_3ac2bf36-20f7-4c9f-9fdb-295d4466d59e +0 -0
  222. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.157_2026-08-30-17-32-17_patch_4302354c-c9c5-4be7-acd3-542872a748d8 +0 -0
  223. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.158_2026-08-31-09-28-33_patch_3523774f-c25d-4102-8c1a-92fff046a48d +0 -0
  224. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.159_2026-08-31-10-31-01_patch_fe3e6290-2553-4154-a0a0-8b8a418280ed +0 -0
  225. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.160_2026-08-31-11-23-39_patch_e701a085-3d23-4212-b0af-73b1d419a4c1 +0 -0
  226. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.161_2026-08-31-12-41-01_patch_074d7bde-c493-44db-bc15-e81fd91e2921 +0 -0
  227. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.162_2026-08-31-13-58-06_patch_84db1d60-4280-433b-bd3a-22e5611cd315 +0 -0
  228. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.163_2026-08-31-15-25-54_patch_1931c5ba-73df-48cb-8dcb-555ace0af267 +0 -0
  229. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.163_2026-08-31-15-44-37_patch_3962e805-2a92-494a-a87b-b6e6d66c40a0 +0 -0
  230. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.165_2026-08-31-19-48-59_patch_86e5b923-2b99-4b86-b542-469b197614be +0 -0
  231. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.166_2026-09-01-07-39-57_patch_c344892f-d542-4e7b-8f27-02365a411e15 +0 -0
  232. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.167_2026-09-01-08-21-53_patch_e199d419-282a-4dbb-8756-cf98b7037e2b +0 -0
  233. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.168_2026-09-01-09-12-31_patch_235c9fe0-da15-431d-bb56-01e2b9b15f4b +0 -0
  234. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.169_2026-09-01-11-54-19_patch_98b617ab-d130-42b5-93f2-19cae56d4c4c +0 -0
  235. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.170_2026-09-02-09-27-28_patch_e448d2e6-b7ec-4235-96bf-0173b3623c87 +0 -0
  236. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.171_2026-09-02-12-52-44_patch_e6a241c2-1d62-482c-a9eb-9e3373395c50 +0 -0
  237. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.172_2026-09-04-08-47-04_patch_daae079f-c104-4fcd-bb57-7bff68e80ad9 +0 -0
  238. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.173_2026-09-04-12-34-42_patch_399c4cbd-0c28-4dfd-a4ec-e569420a36e4 +0 -0
  239. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.174_2026-09-04-13-08-48_patch_f5cfe3d5-808e-45e4-bafc-00d0554838ee +0 -0
  240. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.175_2026-09-04-17-20-46_patch_1ef542fa-5d8e-4d90-aa15-9fc4cea3dfec +0 -0
  241. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.176_2026-09-05-08-25-05_patch_ced5521f-f9da-4640-a921-95fcb5cd2e6d +0 -0
  242. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.177_2026-09-05-09-00-16_patch_803c1ad4-a9af-4953-92c5-d882dec03ea2 +0 -0
  243. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.178_2026-09-05-09-30-34_patch_012f6259-2e3f-4591-9806-1920fd06cb1f +0 -0
  244. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.179_2026-09-05-09-33-43_patch_f4bdf28c-d584-47a5-b699-8c883330162c +0 -0
  245. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.180_2026-09-05-12-02-21_patch_34a14b01-d22d-44a8-ac63-be0370a61422 +0 -0
  246. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.181_2026-09-05-12-47-46_patch_56b18867-99f6-4d5c-8215-7b9d60d34010 +0 -0
  247. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.182_2026-09-05-13-35-18_patch_61b7d4d1-73c8-4603-9b0c-593e7405587f +0 -0
  248. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.183_2026-09-06-07-27-09_patch_d76331b2-e3a3-4c0b-8412-ecd131b6ac02 +0 -0
  249. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.184_2026-09-06-10-21-47_patch_7680b7a1-49f0-4eef-b12e-4c854407448c +0 -0
  250. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.185_2026-09-06-10-30-40_patch_e56c2183-77f8-44ef-a92e-7377ea6ce8c1 +0 -0
  251. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.186_2026-09-07-10-00-51_patch_67de5683-d208-4bc0-8fb6-7677377908e7 +0 -0
  252. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.187_2026-09-07-10-18-13_patch_2086cee2-276b-48f7-80ce-6a17397b9541 +0 -0
  253. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.188_2026-09-07-12-51-28_patch_d6590822-068f-4a19-814d-34bbf204ba6e +0 -0
  254. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.189_2026-09-07-12-55-23_patch_7e0fb04b-4d40-4490-974f-c74ba2ae55a1 +0 -0
  255. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.190_2026-09-08-08-58-03_patch_15e3ac1e-4475-4272-bdd8-d00bb0db8f17 +0 -0
  256. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.191_2026-09-08-09-55-58_patch_3d350e50-ee53-4282-bc75-d2251142c46e +0 -0
  257. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.192_2026-09-08-11-12-21_patch_0733223b-1ae2-4b5b-897f-dfc57574ff83 +0 -0
  258. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.193_2026-09-08-21-48-17_patch_8d07d4e6-3555-4720-85c9-9452570fae2d +0 -0
  259. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.194_2026-09-09-07-53-43_patch_69559429-aa42-4b62-9bd7-cdfded1c00d0 +0 -0
  260. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.195_2026-09-09-09-55-40_patch_bbf67f1d-3b9a-43a2-b1bc-22df3fed8a34 +0 -0
  261. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.196_2026-09-09-09-59-47_patch_70d76812-7b3c-4192-ad49-fcaccc29b0da +0 -0
  262. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.197_2026-09-09-13-06-06_patch_d455be0b-5421-492a-b952-fab0fd8110f8 +0 -0
  263. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.198_2026-09-09-13-14-34_patch_267f54e5-311e-435e-882f-8e19191325ea +0 -0
  264. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.199_2026-09-09-22-24-18_patch_81e3e453-ca0e-42fa-9c21-8f94d43c05f2 +0 -0
  265. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.200_2026-09-10-07-19-50_patch_911714fa-1fa3-4165-bfe6-d10c650bf5bf +0 -0
  266. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.201_2026-09-10-10-14-19_patch_864015f2-b0b0-4563-a1c8-155629cb9126 +0 -0
  267. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.202_2026-09-10-11-00-05_patch_18270ecf-e770-4e69-8bcf-e5143c39929b +0 -0
  268. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.203_2026-09-10-11-10-41_patch_ff273ab1-44f3-4bc0-b184-3396e943df04 +0 -0
  269. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.204_2026-09-10-13-02-02_patch_d4ee41e2-d13c-4941-8605-3f1a42b56b22 +0 -0
  270. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.205_2026-09-10-13-57-50_patch_284df67e-5957-4b0c-bc64-5581db6ddecc +0 -0
  271. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.206_2026-09-11-10-18-50_patch_1ac7e410-0e62-4eef-bbe4-ebf93c9d0869 +0 -0
  272. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/17.0.207_2026-09-11-15-26-02_major_3f1b3ed7-eaac-41f5-b740-0af3331595d9 +0 -0
  273. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.0_2026-09-12-10-01-10_patch_8995783a-a9fa-4c4e-90b3-6386a4c481eb +0 -0
  274. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.10_2026-09-14-16-09-38_patch_9403d562-eed0-4125-a8b3-09cd92a13298 +0 -0
  275. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.11_2026-09-15-09-05-57_patch_8b22dba2-d931-4c4d-ae60-db3238d5e73d +0 -0
  276. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.12_2026-09-15-11-18-52_patch_81314afa-e70d-4ad8-b45b-3f8d62b983e7 +0 -0
  277. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.13_2026-09-16-08-00-55_patch_bfa30fc0-3281-4de6-bb56-d7290c98d1c3 +0 -0
  278. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.14_2026-09-16-14-38-26_patch_aae6e9b0-88f4-4bcf-b611-3308c7fcd6eb +0 -0
  279. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.15_2026-09-17-07-58-54_patch_43d40582-effd-4925-a8bd-e70fecf1faab +0 -0
  280. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.16_2026-09-17-08-12-37_patch_b4db2d23-88f1-45c1-82d9-78d38014fcb6 +0 -0
  281. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.17_2026-09-18-09-38-19_patch_25697fc3-e9a8-4980-962b-e6cb0a4760c5 +0 -0
  282. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.18_2026-09-18-09-54-33_patch_d37d9c71-c469-4d94-90d7-4898915ee991 +0 -0
  283. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.19_2026-09-18-10-47-33_patch_47607b3c-d1b6-4864-b9b0-00a2a8d2ac32 +0 -0
  284. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.1_2026-09-12-17-33-30_patch_f6ea2c99-a715-4c4d-876a-23ed8c62a83d +0 -0
  285. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.20_2026-09-18-11-07-21_patch_5a336f91-63a6-4877-97ed-da89395cc8f5 +0 -0
  286. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.21_2026-09-18-13-34-52_patch_c56462e1-63d9-498f-a912-c80c5f0171d1 +0 -0
  287. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.22_2026-09-20-08-10-45_patch_6afa2c20-bcef-4b7d-8685-2c9815d8683f +0 -0
  288. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.23_2026-09-20-08-38-35_patch_a7f169e5-37ab-4ec0-bf89-d14770181303 +0 -0
  289. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.24_2026-09-20-15-49-27_patch_c1222081-ff44-4f20-aea2-5840b6d76efd +0 -0
  290. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.25_2026-09-21-06-11-40_patch_6df46dd9-e7d3-4e71-bec4-e5c93b4ac863 +0 -0
  291. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.26_2026-09-21-07-54-11_patch_cc52dd36-5eba-4094-a1b0-d6f79f103441 +0 -0
  292. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.27_2026-09-21-08-36-49_patch_a25fa125-9bcd-4317-8da5-851c1c329631 +0 -0
  293. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.28_2026-09-21-09-44-01_patch_4430a721-0b3c-4f6a-b9bc-a53e667161bb +0 -0
  294. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.29_2026-09-21-10-58-07_patch_83b2b942-60a4-4bef-afd1-99690ba52b69 +0 -0
  295. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.2_2026-09-13-06-36-33_patch_176bb944-1c49-4dd3-a001-8fce908825a0 +0 -0
  296. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.30_2026-09-21-12-51-16_patch_519b9a65-d400-4234-b113-36b46e315507 +0 -0
  297. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.31_2026-09-22-06-53-35_patch_5c45a235-81b6-4d05-801a-07dc7db61400 +0 -0
  298. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.32_2026-09-22-07-42-04_patch_f12c6415-8166-4063-9e5d-26601b929d63 +0 -0
  299. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.33_2026-09-22-08-12-32_patch_cec31bb0-a6cb-43e6-8407-25aba322b54c +0 -0
  300. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.34_2026-09-23-07-09-16_patch_659fccbb-c0a0-4f6f-bc87-e6abaa8815a7 +0 -0
  301. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.35_2026-09-23-09-38-52_patch_023f904d-807a-4833-8a40-570365e8ec06 +0 -0
  302. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.36_2026-09-23-10-05-33_patch_846fb491-2b1b-47ed-ac1f-ba40e744e199 +0 -0
  303. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.37_2026-09-23-13-08-30_patch_8e4b1d24-156e-4ffe-8e4a-b8740ec18588 +0 -0
  304. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.38_2026-09-24-06-41-37_patch_67adb1d6-3f49-4357-a67f-b1d48f23a972 +0 -0
  305. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.39_2026-09-24-15-24-32_patch_e5dd375d-5643-4514-9b65-8d877c4a2bb2 +0 -0
  306. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.3_2026-09-13-12-32-46_patch_58e5ce3a-f2a7-4789-b2cd-5cc75c72b6ec +0 -0
  307. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.40_2026-09-24-19-58-14_patch_ff18824b-be51-4a3d-a621-e96279e53c3e +0 -0
  308. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.41_2026-09-26-09-24-52_patch_b9979267-30f9-440a-a4ce-c611991d4886 +0 -0
  309. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.42_2026-09-28-12-39-34_patch_dda535d9-8922-4eb9-ab51-6ecff0650c10 +0 -0
  310. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.43_2026-09-28-13-35-27_minor_aca1168a-1286-4326-9d0c-2f2587c9fe92 +0 -0
  311. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.4_2026-09-13-12-45-14_patch_b6c79d55-8f85-4f47-a304-df52b122c38c +0 -0
  312. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.5_2026-09-13-14-11-18_patch_9b111116-5e62-472a-b72c-d1bbafa22c97 +0 -0
  313. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.5_2026-09-13-17-01-11_patch_d4bf61c0-83ac-4dd3-b512-a65805d298c8 +0 -0
  314. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.6_2026-09-14-11-31-04_patch_fd2ebda6-22cb-4e7d-9452-2f6f2640e828 +0 -0
  315. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.7_2026-09-13-17-06-08_patch_428af161-0b27-43c2-8751-e5f7874df120 +0 -0
  316. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.0.9_2026-09-14-12-37-42_patch_b2ca0529-4b67-4fa4-8fdc-5f5e9f5d5166 +0 -0
  317. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.1.0_2026-09-28-14-27-54_patch_324444f7-d24e-4189-b21f-1188894a3109 +0 -0
  318. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/18.1.1_2026-09-28-21-03-07_major_e266a14a-7d96-4ece-92a3-8f34e64438a5 +0 -0
  319. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.0_2026-09-29-11-05-31_patch_77d6f9f8-ead3-4d79-a4b2-b084b2dffc98 +0 -0
  320. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.10_2026-10-02-12-56-52_patch_14e97576-73ca-44b8-82c9-7dad6f1789ab +0 -0
  321. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.11_2026-10-04-10-31-19_patch_088eb371-1799-4949-a119-286cf1cd55d1 +0 -0
  322. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.12_2026-10-06-18-00-25_patch_36554bed-49c5-41cb-9fd4-48cc6af74c09 +0 -0
  323. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.13_2026-10-07-12-24-08_patch_a540a364-3a0d-4960-b278-06ba2c7cc258 +0 -0
  324. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.14_2026-10-07-12-52-39_patch_e3a6fc5c-2ee4-414c-a2dd-4910a655a7dd +0 -0
  325. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.15_2026-10-09-04-15-56_patch_bd7a9b06-867b-4fea-9678-973a05e3022d +0 -0
  326. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.16_2026-10-09-16-11-56_patch_a1135435-7dea-4f00-8c98-203ba3974382 +0 -0
  327. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.17_2026-10-09-17-44-55_patch_faeacad8-541a-40f2-ab9c-abcd66fcd00e +0 -0
  328. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.18_2026-10-10-07-29-38_major_02601a1e-9bdb-45bf-ad67-a07b7dcd0002 +0 -0
  329. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.1_2026-09-29-11-59-38_patch_bbf4753c-d641-4c2f-ac7c-02be6bd8e7c2 +0 -0
  330. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.2_2026-09-29-12-44-07_patch_19fdaa94-60dc-464b-93b8-c17607ebc7b6 +0 -0
  331. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.3_2026-09-29-14-16-00_patch_3cb60272-95cf-4311-8897-721e1b5c2c88 +0 -0
  332. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.4_2026-09-29-16-24-53_patch_9fe8ad2b-e3ec-4558-a5fc-9c44c5c266dc +0 -0
  333. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.5_2026-09-29-17-13-16_patch_e48d2dd2-f41a-402e-a441-756b23c01dcb +0 -0
  334. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.6_2026-09-29-17-22-11_patch_3b1c79e9-9002-4e96-ba78-10668c33be6a +0 -0
  335. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.7_2026-09-30-07-50-58_patch_e8b1f046-d819-499c-9cd5-3e1a20fc9acf +0 -0
  336. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.8_2026-10-01-13-41-44_patch_7d63af18-e0af-4127-ab58-aede2407490f +0 -0
  337. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/19.0.9_2026-10-01-15-57-35_patch_143863cb-8f63-4ef7-bd78-c1114fc93a2d +0 -0
  338. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.0_2026-10-10-09-36-17_patch_d2618f39-cdc9-4d3a-ba40-1a0ad6265f3b +0 -0
  339. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.1_2026-10-11-10-24-33_patch_e29a8713-eecb-4eb1-9641-789d3cfab21a +0 -0
  340. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.2_2026-10-12-07-22-24_patch_f4053ad1-8fcd-4591-a68d-bf1e23485ba7 +0 -0
  341. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.3_2026-10-14-14-29-16_patch_070af1c4-f9d9-4f97-8112-058de90d3ea8 +0 -0
  342. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.4_2026-10-14-16-20-24_patch_c6672844-8227-4e0a-9fb5-36af7e7141dc +0 -0
  343. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.5_2026-10-15-08-53-28_patch_10154146-8afd-4632-b250-9b4b9f5bf67c +0 -0
  344. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.6_2026-10-15-14-17-40_patch_df3a5d3c-f0e0-46cb-aeaf-15b51c8a0f13 +0 -0
  345. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/20.0.7_2026-10-16-07-09-40_major_3e5dfba3-2810-47b4-85a9-938bfff72a04 +0 -0
  346. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.0_2026-10-16-10-44-29_patch_1058e453-613f-492b-a3c7-f3ca2abe8c2d +0 -0
  347. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.10_2026-10-30-14-29-34_major_4fd535f6-6e41-4f34-b29c-543e1a9bac51 +0 -0
  348. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.1_2026-10-16-16-06-10_patch_e20b4ad2-b87f-478e-b4f4-323c8bcc5ea9 +0 -0
  349. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.2_2026-10-19-13-54-31_patch_bf091df4-00bb-43c8-9117-51047944e305 +0 -0
  350. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.3_2026-10-19-14-58-29_patch_9b985381-1b1d-4531-b242-b02cea2484c5 +0 -0
  351. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.4_2026-10-20-17-08-51_patch_38d02583-cb5c-4adc-b5d7-614b483acf19 +0 -0
  352. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.5_2026-10-21-09-28-47_patch_fabd5cfe-2d04-4215-abf1-58fba226acb7 +0 -0
  353. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.6_2026-10-22-16-07-37_patch_d2bb27d7-6304-4c99-abbc-46d3dd7e363b +0 -0
  354. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.7_2026-10-27-11-41-55_patch_6b50567f-209d-42c9-a2cd-d251a2bc8fbf +0 -0
  355. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.8_2026-10-29-13-48-18_patch_bdab3ee6-fba8-4625-9243-c4cbe839ba32 +0 -0
  356. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/21.0.9_2026-10-29-17-51-00_patch_803a4c70-2e2b-4024-8598-c7d91c9db0d2 +0 -0
  357. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/22.0.0_2026-10-30-15-25-42_patch_1f39caf4-aadc-4d26-9124-a854d945b32a +0 -0
  358. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/22.0.1_2026-10-30-17-30-37_patch_4a6e6cfb-d86e-4f1e-84c5-02d4c071f75b +0 -0
  359. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/22.0.2_2026-10-31-11-13-43_patch_54d644d8-cebd-4b6a-ba8f-685e2ffee481 +0 -0
  360. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/22.0.3_2026-10-31-16-57-27_patch_e818d7fa-a4ba-4041-abdd-c6363fcc0a30 +0 -0
  361. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/__init__.py +0 -0
  362. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli/version/read_version.py +0 -0
  363. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/dependency_links.txt +0 -0
  364. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/entry_points.txt +0 -0
  365. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/not-zip-safe +0 -0
  366. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/requires.txt +0 -0
  367. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/ellf_cli.egg-info/top_level.txt +0 -0
  368. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/pyproject.toml +0 -0
  369. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/setup.cfg +0 -0
  370. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/setup.py +0 -0
  371. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_agents.py +0 -0
  372. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_agents_info_stats.py +0 -0
  373. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_appdirs.py +0 -0
  374. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_auth.py +0 -0
  375. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_clusters_info_stats.py +0 -0
  376. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_config.py +0 -0
  377. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_datasets_export.py +0 -0
  378. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_errors.py +0 -0
  379. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_files_cp.py +0 -0
  380. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_files_cp_helpers.py +0 -0
  381. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_helm.py +0 -0
  382. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_import_export.py +0 -0
  383. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_info.py +0 -0
  384. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_config_io.py +0 -0
  385. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_configure.py +0 -0
  386. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_deploy_node_labels.py +0 -0
  387. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_deploy_preflight.py +0 -0
  388. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_destroy.py +0 -0
  389. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_get_terraform.py +0 -0
  390. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_hibernate.py +0 -0
  391. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_pause.py +0 -0
  392. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_provision.py +0 -0
  393. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_start_validation.py +0 -0
  394. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_state_bucket.py +0 -0
  395. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_infra_terraform_init.py +0 -0
  396. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_invalid_secrets.py +0 -0
  397. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_job_list_project_filter.py +0 -0
  398. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_jobs_info_hides_creator.py +0 -0
  399. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_jobs_list_unmatched.py +0 -0
  400. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_key_pair.py +0 -0
  401. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_login.py +0 -0
  402. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_logout.py +0 -0
  403. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_main.py +0 -0
  404. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_mcp_proxy.py +0 -0
  405. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_org_select.py +0 -0
  406. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_plans.py +0 -0
  407. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_projects.py +0 -0
  408. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_projects_delete_confirm.py +0 -0
  409. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_publish_build_poll.py +0 -0
  410. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_publish_data.py +0 -0
  411. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_publish_import_root.py +0 -0
  412. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_publish_requirements.py +0 -0
  413. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_publish_versions.py +0 -0
  414. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_pypi_auth.py +0 -0
  415. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_query.py +0 -0
  416. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_recipe_file.py +0 -0
  417. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_recipe_help.py +0 -0
  418. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_recipe_required_args.py +0 -0
  419. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_recipes.py +0 -0
  420. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_recipes_init.py +0 -0
  421. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_state.py +0 -0
  422. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_support.py +0 -0
  423. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_todos.py +0 -0
  424. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_ty.py +0 -0
  425. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_ui.py +0 -0
  426. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_ui_extras.py +0 -0
  427. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_usage_counts.py +0 -0
  428. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_users_assign.py +0 -0
  429. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_users_info_stats.py +0 -0
  430. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_users_list.py +0 -0
  431. {ellf_cli-22.0.4 → ellf_cli-22.0.6}/tests/test_util.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ellf-cli
3
- Version: 22.0.4
3
+ Version: 22.0.6
4
4
  Summary: Ellf Command Line Interface
5
5
  Home-page: https://prodi.gy
6
6
  Author: ExplosionAI GmbH
@@ -32,7 +32,7 @@ List the actions in a project. Uses your default project unless --project is giv
32
32
  | Argument | Type | Description | Default |
33
33
  | --- | --- | --- | --- |
34
34
  | `--project` | `str` | Name, slug, or ID of action's project or the last project if not set | `None` |
35
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'stats', 'created_by_user', 'state'] | `['id', 'name', 'state']` |
35
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'stats', 'created_by_user', 'created_by_deleted', 'state'] | `['id', 'name', 'state']` |
36
36
  | `--json` | `bool` | Output the result as JSON | `False` |
37
37
 
38
38
  #### `ellf actions info`
@@ -44,7 +44,7 @@ Print information about an action on the cluster
44
44
  | `name_or_id` | `Union[str, UUID]` | Name or ID of the action | |
45
45
  | `--project` | `str` | Name, slug, or ID of action's project or the last project if not set | `None` |
46
46
  | `--cluster` | `str` | Name, slug, or ID of the cluster to search for action name (or the last cluster if not set) | `None` |
47
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'stats', 'created_by_user', 'recipe_name', 'recipe_title', 'evaluation', 'project_name', 'error', 'executions', 'last_execution_id', 'url_logs', 'url', 'related_tasks'] | `None` |
47
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'stats', 'created_by_user', 'created_by_deleted', 'recipe_name', 'recipe_title', 'evaluation', 'project_name', 'error', 'executions', 'last_execution_id', 'url_logs', 'url', 'related_tasks'] | `None` |
48
48
  | `--json` | `bool` | Output the result as JSON | `False` |
49
49
 
50
50
  #### `ellf actions logs`
@@ -215,7 +215,7 @@ List the agents in a project. Uses your default project unless --project is give
215
215
  | Argument | Type | Description | Default |
216
216
  | --- | --- | --- | --- |
217
217
  | `--project` | `str` | Name, slug, or ID of agent's project or the last project if not set | `None` |
218
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'icon', 'created_by_user', 'live_sessions', 'state'] | `['id', 'name', 'state']` |
218
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'icon', 'created_by_user', 'created_by_deleted', 'live_sessions', 'state'] | `['id', 'name', 'state']` |
219
219
  | `--json` | `bool` | Output the result as JSON | `False` |
220
220
 
221
221
  #### `ellf agents info`
@@ -227,7 +227,7 @@ Print information about an agent on the cluster
227
227
  | `name_or_id` | `Union[str, UUID]` | Name or ID of the agent | |
228
228
  | `--project` | `str` | Name, slug, or ID of agent's project or the last project if not set | `None` |
229
229
  | `--cluster` | `str` | Name, slug, or ID of the cluster to search for agent name (or the last cluster if not set) | `None` |
230
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'icon', 'created_by_user', 'live_sessions', 'recipe_name', 'recipe_title', 'project_name', 'error', 'last_execution_id', 'related_tasks'] | `None` |
230
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'icon', 'created_by_user', 'created_by_deleted', 'live_sessions', 'recipe_name', 'recipe_title', 'project_name', 'error', 'last_execution_id', 'related_tasks'] | `None` |
231
231
  | `--json` | `bool` | Output the result as JSON | `False` |
232
232
 
233
233
  #### `ellf agents logs`
@@ -659,12 +659,12 @@ Deploy and manage cluster infrastructure (Kubernetes, TLS, Terraform)
659
659
 
660
660
  #### `ellf infra register`
661
661
 
662
- Register a new cluster with PAM and write credentials to cluster-creds.json. Pass --domain to use your own DNS, or omit it to be allocated a managed subdomain (with an A record) under an Explosion-controlled zone. An org on the free Solo plan has no managed subdomain: omitting --domain registers it at http://localhost.
662
+ Register a new cluster with PAM. Pass --domain to use your own DNS, or omit it to be allocated a managed subdomain (with an A record) under an Explosion-controlled zone. An org on the free Solo plan has no managed subdomain: omitting --domain registers it at http://localhost.
663
663
 
664
664
  | Argument | Type | Description | Default |
665
665
  | --- | --- | --- | --- |
666
666
  | `--name` | `str` | Human-readable name for the cluster | |
667
- | `--domain` | `str` | Public address the cluster is reached on, host or host:port (e.g. 'cluster.example.com' for a hosted cluster on port 443, or 'http://localhost' for a cluster on this machine, which needs no certificate and is what the free Solo plan uses by default; Safari can't reach it there, so for Safari use 'https://localhost[:port]', and to reach it from other devices 'https://<its IP address on your network>'; Ellf issues those a certificate, see 'ellf infra tls'). Stored verbatim as the cluster address; the chart derives the bare hostname for K8s ingress / cert SAN where a port isn't allowed. Omit to get a managed subdomain under an Explosion-controlled zone. | `None` |
667
+ | `--domain` | `str` | Public address the cluster is reached on, host or host:port (e.g. 'cluster.example.com' for a hosted cluster on port 443, or 'http://localhost' for a cluster on this machine, which needs no certificate and is what the free Solo plan uses by default; Safari can't reach it there, so for Safari use 'https://localhost[:port]', and to reach it from other devices 'https://<its IP address on your network>'; Ellf issues those a certificate, see 'ellf infra tls'). Stored as the cluster address without its scheme, which is https unless you give http://; the chart derives the bare hostname for K8s ingress / cert SAN where a port isn't allowed. Omit to get a managed subdomain under an Explosion-controlled zone. | `None` |
668
668
  | `--subdomain` | `str` | Requested label for a managed subdomain (e.g. 'acme' for acme.<zone>). Only valid without --domain; defaults to a slug derived from your org/cluster name. | `None` |
669
669
  | `--public-ip` | `str` | Cluster ingress IP to point the managed subdomain at: a public IPv4 address. Omit to reserve the name now and re-run with --public-ip once the load balancer IP is known. A cluster on a private network uses --domain with your own DNS instead. | `None` |
670
670
  | `--cloud-provider` | `str` | Cloud provider: gcp, k3s, aws, azure | |
@@ -843,13 +843,13 @@ Recreate a cluster hibernated with 'ellf infra hibernate'. Starts the database,
843
843
 
844
844
  #### `ellf infra init-values`
845
845
 
846
- Generate a values.yaml for Helm deployment from credentials and provider defaults.
846
+ Generate a values.yaml for Helm deployment of a registered cluster. The file holds no secrets, so it's safe to keep with the rest of your configuration: 'infra deploy' hands the cluster its registry and licence keys from PAM, and keeps its database password in the cluster.
847
847
 
848
848
  | Argument | Type | Description | Default |
849
849
  | --- | --- | --- | --- |
850
- | `--creds` | `Path` | Path to cluster-creds.json from 'infra register' | |
851
850
  | `--cloud-provider` | `str` | Cloud provider: gcp, k3s, aws, azure | |
852
- | `--domain` | `str` | Public address the cluster is reached on, host or host:port (e.g. 'cluster.example.com'). Use 'http://localhost' for a cluster on this machine, which needs no certificate and works in every browser but Safari. 'https://localhost[:port]', or https at an IP address on a private network (for other devices to reach), is served with a certificate Ellf issues the cluster, which each device trusts once (see 'ellf infra tls'). Match what was passed to 'infra register' — it flows into ELLF_BROKER_HOST so the cluster emits matching OIDC / token URLs. | |
851
+ | `--cluster` | `str` | Name or ID of the registered cluster (default: the one 'infra register' registered last) | `None` |
852
+ | `--domain` | `str` | Public address the cluster is reached on, host or host:port (default: the address it was registered at). Use 'http://localhost' for a cluster on this machine, which needs no certificate and works in every browser but Safari. 'https://localhost[:port]', or https at an IP address on a private network (for other devices to reach), is served with a certificate Ellf issues the cluster, which each device trusts once (see 'ellf infra tls'). It flows into ELLF_BROKER_HOST so the cluster emits matching OIDC / token URLs. | `None` |
853
853
  | `--out` | `Path` | Output path for generated values.yaml | `'values.yaml'` |
854
854
  | `--acme-email` | `str` | Email for Let's Encrypt certificates | `None` |
855
855
  | `--tls-secret-name` | `str` | Serve the cluster with a certificate you provide: the name of a kubernetes.io/tls Secret in the cluster's namespace, made however you like (your own cert-manager issuer, a company CA, by hand). For a cluster on a private network or at an IP address, which Let's Encrypt can't certify. | `None` |
@@ -1255,7 +1255,7 @@ List the services in a project. Uses your default project unless --project is gi
1255
1255
  | Argument | Type | Description | Default |
1256
1256
  | --- | --- | --- | --- |
1257
1257
  | `--project` | `str` | Name, slug, or ID of service's project or the last project if not set | `None` |
1258
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'created_by_user', 'state'] | `['id', 'name', 'state']` |
1258
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'created_by_user', 'created_by_deleted', 'state'] | `['id', 'name', 'state']` |
1259
1259
  | `--json` | `bool` | Output the result as JSON | `False` |
1260
1260
 
1261
1261
  #### `ellf services info`
@@ -1267,7 +1267,7 @@ Print information about a service on the cluster.
1267
1267
  | `name_or_id` | `Union[str, UUID]` | Name or ID of the service | |
1268
1268
  | `--project` | `str` | Name, slug, or ID of service's project or the last project if not set | `None` |
1269
1269
  | `--cluster` | `str` | Name, slug, or ID of the cluster to search for service name (or the last cluster if not set) | `None` |
1270
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'created_by_user', 'recipe_name', 'recipe_title', 'project_name', 'error', 'last_execution_id', 'url', 'url_ui', 'url_logs'] | `None` |
1270
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'cluster_id', 'name', 'project_id', 'job_type', 'plan', 'cli_command', 'last_execution_started', 'created_by_user', 'created_by_deleted', 'recipe_name', 'recipe_title', 'project_name', 'error', 'last_execution_id', 'url', 'url_ui', 'url_logs'] | `None` |
1271
1271
  | `--json` | `bool` | Output the result as JSON | `False` |
1272
1272
 
1273
1273
  #### `ellf services logs`
@@ -1418,7 +1418,7 @@ List the tasks in a project. Uses your default project unless --project is given
1418
1418
  | Argument | Type | Description | Default |
1419
1419
  | --- | --- | --- | --- |
1420
1420
  | `--project` | `str` | Name, slug, or ID of task's project or the last project if not set | `None` |
1421
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'project_id', 'cluster_id', 'name', 'recipe_name', 'recipe_title', 'project_name', 'error', 'plan', 'job_type', 'cli_command', 'last_execution_started', 'created_by_user', 'state'] | `['id', 'name', 'state']` |
1421
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'project_id', 'cluster_id', 'name', 'recipe_name', 'recipe_title', 'project_name', 'error', 'plan', 'job_type', 'cli_command', 'last_execution_started', 'created_by_user', 'created_by_deleted', 'state'] | `['id', 'name', 'state']` |
1422
1422
  | `--json` | `bool` | Output the result as JSON | `False` |
1423
1423
 
1424
1424
  #### `ellf tasks info`
@@ -1430,7 +1430,7 @@ Print information about a task on the cluster
1430
1430
  | `name_or_id` | `Union[str, UUID]` | Name or ID of the task | |
1431
1431
  | `--project` | `str` | Name, slug, or ID of task's project or the last project if not set | `None` |
1432
1432
  | `--cluster` | `str` | Name, slug, or ID of the cluster to search for task name (or the last cluster if not set) | `None` |
1433
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'project_id', 'cluster_id', 'name', 'recipe_name', 'recipe_title', 'project_name', 'error', 'plan', 'job_type', 'cli_command', 'last_execution_started', 'created_by_user', 'last_execution_id', 'related_actions', 'url_logs', 'url'] | `None` |
1433
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'project_id', 'cluster_id', 'name', 'recipe_name', 'recipe_title', 'project_name', 'error', 'plan', 'job_type', 'cli_command', 'last_execution_started', 'created_by_user', 'created_by_deleted', 'last_execution_id', 'related_actions', 'url_logs', 'url'] | `None` |
1434
1434
  | `--json` | `bool` | Output the result as JSON | `False` |
1435
1435
 
1436
1436
  #### `ellf tasks logs`
@@ -1546,7 +1546,7 @@ Remove a user from the organization. By default the user is deactivated: they lo
1546
1546
  | Argument | Type | Description | Default |
1547
1547
  | --- | --- | --- | --- |
1548
1548
  | `email_name_or_id` | `Union[str, UUID]` | Email, name, or ID of the user | |
1549
- | `--permanent` | `bool` | Permanently delete the user's record instead of deactivating them. This removes their sessions and roles and can't be undone | `False` |
1549
+ | `--permanent` | `bool` | Permanently delete the user's record instead of deactivating them. Their annotations, sessions and plans are kept but attributed to a deleted user. This can't be undone | `False` |
1550
1550
  | `--json` | `bool` | Output the result as JSON | `False` |
1551
1551
 
1552
1552
  #### `ellf users reactivate`
@@ -1576,7 +1576,7 @@ List pending invitations
1576
1576
 
1577
1577
  | Argument | Type | Description | Default |
1578
1578
  | --- | --- | --- | --- |
1579
- | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'org_id', 'email', 'avatar_color', 'avatar_url', 'claimed', 'vars', 'created_by_id', 'role'] | `['id', 'email', 'role', 'claimed']` |
1579
+ | `--select` | `list[str]` | Comma-separated fields to select and show in output. Available: ['id', 'created', 'updated', 'org_id', 'email', 'avatar_color', 'avatar_url', 'claimed', 'vars', 'created_by_id', 'created_by_deleted', 'role'] | `['id', 'email', 'role', 'claimed']` |
1580
1580
  | `--all` | `bool` | Also include invitations that have already been claimed | `False` |
1581
1581
  | `--json` | `bool` | Output the result as JSON | `False` |
1582
1582
 
@@ -1,11 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import dataclasses
3
4
  import json
4
5
  import sys
5
6
  from pathlib import Path
6
- from typing import Any
7
+ from typing import Any, Callable, TypeVar
7
8
 
8
- from radicli import Radicli, get_list_converter
9
+ from radicli import Arg, Command, Radicli, get_list_converter
10
+ from radicli.util import DEFAULT_PLACEHOLDER, ArgparseArg
9
11
  from wasabi import msg
10
12
 
11
13
  from ellf_broker_sdk.errors import BrokerError
@@ -18,6 +20,8 @@ from .messages import Messages
18
20
 
19
21
  HELP = """Ellf Command Line Interface."""
20
22
 
23
+ _F = TypeVar("_F", bound=Callable[..., Any])
24
+
21
25
 
22
26
  def _emit_error(title: str, detail: str | None = None) -> int:
23
27
  if not isatty(sys.stderr):
@@ -95,7 +99,40 @@ ERRORS = {
95
99
  }
96
100
 
97
101
 
98
- cli = Radicli(
102
+ class _Radicli(Radicli):
103
+ """Radicli that says which options are required in their help.
104
+
105
+ radicli checks required options itself rather than through argparse,
106
+ which would trip over subcommands, so argparse's usage line shows every
107
+ option in brackets, as if optional. Marked when the command registers,
108
+ so the static ellf.json the CLI runs from carries it too.
109
+ """
110
+
111
+ def _command(
112
+ self,
113
+ name: str,
114
+ args: dict[str, Arg],
115
+ registry: dict[str, Command],
116
+ **kwargs: Any,
117
+ ) -> Callable[[_F], _F]:
118
+ register = super()._command(name, args, registry, **kwargs)
119
+
120
+ def cli_wrapper(cli_func: _F) -> _F:
121
+ register(cli_func)
122
+ command = registry[name]
123
+ command.args = [_mark_required(arg) for arg in command.args]
124
+ return cli_func
125
+
126
+ return cli_wrapper
127
+
128
+
129
+ def _mark_required(arg: ArgparseArg) -> ArgparseArg:
130
+ if not arg.arg.option or arg.default is not DEFAULT_PLACEHOLDER:
131
+ return arg
132
+ return dataclasses.replace(arg, help=f"{arg.help or ''} (required)".lstrip())
133
+
134
+
135
+ cli = _Radicli(
99
136
  prog=about.__prog__,
100
137
  help=HELP,
101
138
  version=about.__version__,
@@ -1,9 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
- import tempfile
5
- from contextlib import contextmanager
6
- from typing import Annotated, Iterator, Literal
3
+ from typing import Annotated, Literal
7
4
 
8
5
  from pydantic import AliasChoices, BaseModel, Field, model_validator
9
6
 
@@ -249,14 +246,5 @@ class ClusterConfigOverrides(BaseModel):
249
246
  node_pools: list[NodePool] | None = None
250
247
  default_worker_type: str | None = None
251
248
 
252
- @contextmanager
253
- def write_to_temp(self) -> Iterator[str]:
254
- """Write override values to a temp JSON file, yielding its path."""
255
- data = self.model_dump(by_alias=True, exclude_none=True)
256
- with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=True) as tmp:
257
- tmp.write(json.dumps(data, indent=2))
258
- tmp.flush()
259
- yield tmp.name
260
-
261
249
 
262
250
  _check_overrides_match(ClusterConfig, ClusterConfigOverrides)
@@ -1,6 +1,7 @@
1
1
  import base64
2
2
  import builtins
3
3
  import json
4
+ import ssl
4
5
  import subprocess
5
6
  import time
6
7
  import uuid
@@ -49,6 +50,24 @@ DEFAULT_NAMESPACE = "ellf"
49
50
  DEFAULT_RELEASE = "ellf"
50
51
 
51
52
 
53
+ def is_untrusted_certificate(exc: BaseException) -> bool:
54
+ """Whether a connection failed because this device doesn't trust the
55
+ cluster's certificate, rather than because nothing answered.
56
+
57
+ That's how a cluster served with a certificate Ellf issues it (on
58
+ localhost or a private network) looks until 'ellf infra tls --trust'.
59
+ httpx reports it as a ConnectError, with the SSL error in its chain.
60
+ """
61
+ seen: set[int] = set()
62
+ current: Optional[BaseException] = exc
63
+ while current is not None and id(current) not in seen:
64
+ if isinstance(current, ssl.SSLCertVerificationError):
65
+ return True
66
+ seen.add(id(current))
67
+ current = current.__cause__ or current.__context__
68
+ return "CERTIFICATE_VERIFY_FAILED" in str(exc)
69
+
70
+
52
71
  def check_cluster_status(
53
72
  cluster: ellf_pam_sdk_models.ClusterSummary,
54
73
  ) -> ClusterStatusCheck:
@@ -68,7 +87,9 @@ def check_cluster_status(
68
87
  return ClusterStatusCheck.ISSUES
69
88
  except InvalidURL:
70
89
  return ClusterStatusCheck.INVALID_ADDRESS
71
- except (ConnectTimeout, ConnectError):
90
+ except (ConnectTimeout, ConnectError) as e:
91
+ if is_untrusted_certificate(e):
92
+ return ClusterStatusCheck.UNTRUSTED_CERTIFICATE
72
93
  # This could mean the cluster is down, but could also mean we have no network access
73
94
  return ClusterStatusCheck.NOT_FOUND
74
95
  except RequestError as e:
@@ -312,13 +333,12 @@ def _check_result(
312
333
  label: str, ok: bool, detail: str = "", *, quiet: bool = False
313
334
  ) -> tuple[str, bool, str]:
314
335
  """Print a check result line (unless quiet) and return (label, ok, detail)."""
315
- symbol = "\u2714" if ok else "\u2718"
316
336
  suffix = f" ({detail})" if detail else ""
317
337
  if not quiet:
318
338
  if ok:
319
- msg.good(f"{symbol} {label}{suffix}")
339
+ msg.good(f"{label}{suffix}")
320
340
  else:
321
- msg.fail(f"{symbol} {label}{suffix}")
341
+ msg.fail(f"{label}{suffix}")
322
342
  return (label, ok, detail)
323
343
 
324
344
 
@@ -387,12 +407,17 @@ def check(
387
407
  quiet=as_json,
388
408
  )
389
409
  )
390
- except (httpx.ConnectError, httpx.ConnectTimeout):
410
+ except (httpx.ConnectError, httpx.ConnectTimeout) as exc:
391
411
  results.append(
392
412
  _check_result(
393
413
  f"Cluster API responding on {broker_url}",
394
414
  False,
395
- detail="connection failed",
415
+ detail=(
416
+ "this device doesn't trust the cluster's certificate: "
417
+ "run 'ellf infra tls --trust'"
418
+ if is_untrusted_certificate(exc)
419
+ else "connection failed"
420
+ ),
396
421
  quiet=as_json,
397
422
  )
398
423
  )
@@ -2,13 +2,14 @@
2
2
 
3
3
  import base64
4
4
  import json
5
+ import os
5
6
  import subprocess
6
7
  import tempfile
8
+ from contextlib import contextmanager
7
9
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Annotated
10
+ from typing import TYPE_CHECKING, ContextManager, Iterator, Optional
9
11
  from uuid import UUID
10
12
 
11
- from pydantic import AliasChoices, BaseModel, Field, StringConstraints
12
13
  from wasabi import msg
13
14
 
14
15
  from ellf_pam_sdk import Client
@@ -17,32 +18,6 @@ from ellf_pam_sdk.models import ClusterCredentials, ClusterDetail
17
18
  if TYPE_CHECKING:
18
19
  from ...cluster_config import ClusterConfig
19
20
 
20
- # Matches pam/ellf_pam/config.py's NonEmptyStr convention.
21
- NonEmptyStr = Annotated[str, StringConstraints(min_length=1)]
22
-
23
-
24
- class ClusterCredsFile(BaseModel):
25
- """Schema for cluster-creds.json, written by `infra register` and read by
26
- `infra init-values`.
27
-
28
- cluster_id/upstream_registry are required — nothing downstream can work
29
- without them. The rest are legitimately blank on a fresh cluster PAM
30
- hasn't released anything to yet (callers warn, not fail, on those).
31
- """
32
-
33
- cluster_id: NonEmptyStr
34
- # The upstream Ellf registry the cluster pulls release images from.
35
- # Renamed from the ambiguous 'container_registry' (which read like the
36
- # cluster's own registry); creds files written before the rename are
37
- # still read via the alias.
38
- upstream_registry: NonEmptyStr = Field(
39
- validation_alias=AliasChoices("upstream_registry", "container_registry")
40
- )
41
- container_sa_key: str = ""
42
- prodigy_license_key: str = ""
43
- target_broker_version: str = ""
44
- target_cpl_version: str = ""
45
-
46
21
 
47
22
  # Tolerations for the system node-pool taint the terraform modules apply:
48
23
  # ellf/role=system on GKE and EKS, and AKS's own CriticalAddonsOnly on AKS,
@@ -419,25 +394,57 @@ def ensure_cert_manager() -> None:
419
394
  Path(tmp_path).unlink(missing_ok=True)
420
395
 
421
396
 
422
- def helm_registry_login(registry: str, sa_key_b64: str) -> None:
423
- """Authenticate the local Helm client to an OCI registry.
397
+ # A registry config helm reads no credentials from but still treats as
398
+ # configured. Given a config with no credentials at all, helm falls back to the
399
+ # OS credential store (the macOS keychain, Docker's credsStore), reading
400
+ # whatever is stored there for the host and saving any login into it.
401
+ _NO_CREDENTIALS_HOST = "ellf.invalid"
402
+
403
+
404
+ @contextmanager
405
+ def helm_registry_config(
406
+ registry: Optional[str] = None, sa_key_b64: Optional[str] = None
407
+ ) -> Iterator[Path]:
408
+ """A throwaway helm registry config, deleted on exit.
424
409
 
425
- The image pull secret only covers the kubelet; Helm's chart pull runs on
426
- the workstation and needs its own login. Creds persist in
427
- ~/.config/helm/registry/config.json, and the login is idempotent.
410
+ Pass it to helm with --registry-config. Without *registry* and
411
+ *sa_key_b64* it holds no credentials, for a chart anyone can pull, and
412
+ keeps helm away from the OS credential store. With them it holds the
413
+ registry key for the registry's host: the cluster's own credential, which
414
+ otherwise would stay in the installer's keychain, and replace whatever
415
+ they had stored for that host, long after the deploy.
428
416
  """
429
- host = registry.split("/", 1)[0]
430
- sa_key_json = base64.b64decode(sa_key_b64, validate=True).decode("utf-8")
431
- result = subprocess.run(
432
- ["helm", "registry", "login", host, "-u", "_json_key", "--password-stdin"],
433
- input=sa_key_json,
434
- text=True,
435
- capture_output=True,
436
- )
437
- if result.returncode != 0:
438
- msg.fail(f"helm registry login failed for {host}: {result.stderr.strip()}")
417
+ auths: dict[str, dict[str, str]] = {_NO_CREDENTIALS_HOST: {}}
418
+ if registry and sa_key_b64:
419
+ host = registry.split("/", 1)[0]
420
+ sa_key_json = base64.b64decode(sa_key_b64, validate=True).decode("utf-8")
421
+ token = base64.b64encode(f"_json_key:{sa_key_json}".encode()).decode()
422
+ auths[host] = {"auth": token}
423
+ with tempfile.TemporaryDirectory(prefix="ellf-helm-") as tmp:
424
+ path = Path(tmp) / "registry.json"
425
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
426
+ with os.fdopen(fd, "w") as f:
427
+ json.dump({"auths": auths}, f)
428
+ yield path
429
+
430
+
431
+ def chart_source(
432
+ creds: ClusterCredentials, registry: Optional[str], sa_key_b64: Optional[str]
433
+ ) -> "tuple[str, ContextManager[Path]]":
434
+ """The chart to install and the helm registry config to pull it with.
435
+
436
+ PAM names a chart anyone can pull, which needs no credentials. A PAM
437
+ that predates the public chart repository names none: the chart is then
438
+ only in the upstream registry, behind the registry key.
439
+ """
440
+ if creds.image.chart:
441
+ return creds.image.chart, helm_registry_config()
442
+ if not registry:
443
+ msg.fail(
444
+ "registries.upstream (or legacy image.registry) is empty in values.yaml"
445
+ )
439
446
  raise SystemExit(1)
440
- msg.info(f"Authenticated Helm to {host}")
447
+ return f"oci://{registry}/ellf", helm_registry_config(registry, sa_key_b64)
441
448
 
442
449
 
443
450
  def get_cluster_auth(
@@ -1,7 +1,7 @@
1
1
  import base64
2
2
  import json
3
+ import secrets
3
4
  import subprocess
4
- import tempfile
5
5
  import time
6
6
  from pathlib import Path
7
7
  from typing import Optional
@@ -28,7 +28,7 @@ from ...key_pair import generate_key_pair
28
28
  from ...url import URL
29
29
  from .._state import get_auth_state
30
30
  from ._config_io import FILL_IN
31
- from ._helpers import create_image_pull_secret, ensure_traefik, helm_registry_login
31
+ from ._helpers import chart_source, create_image_pull_secret, ensure_traefik
32
32
  from .tls import MANAGED_TLS_SECRET_NAME
33
33
 
34
34
  DEFAULT_NAMESPACE = "ellf"
@@ -102,12 +102,22 @@ def deploy(
102
102
  )
103
103
  overrides.image.broker_version = creds.image.broker_version
104
104
  overrides.image.cpl_version = creds.image.cpl_version
105
- # The registry key is PAM's too: each org has its own, which PAM may
106
- # replace (a leaked key is deleted and the org given a fresh one). The
107
- # copy init-values saved in values.yaml goes stale when that happens,
108
- # so always deploy the key PAM hands out now.
105
+ # The registry key and licence key are PAM's too, and are handed to the
106
+ # cluster straight from PAM on every deploy rather than kept in
107
+ # values.yaml: each org has its own registry key, which PAM may replace
108
+ # (a leaked key is deleted and the org given a fresh one), and keeping
109
+ # them in a file leaves them on the installer's disk.
110
+ stored = _secrets_in_values(values_dict)
111
+ if stored:
112
+ msg.warn(
113
+ f"{values_file} holds secrets ({', '.join(stored)}). Deploy no "
114
+ "longer needs them there: the registry and licence keys come from "
115
+ "PAM and the database password from the cluster. Delete them "
116
+ "from the file."
117
+ )
109
118
  if overrides.secrets is not None:
110
119
  overrides.secrets.container_sa_key = creds.secrets.container_sa_key
120
+ overrides.secrets.prodigy_license_key = creds.secrets.prodigy_license_key
111
121
  # 1. Create namespace
112
122
  msg.info(f"Ensuring namespace {namespace}...")
113
123
  subprocess.run(
@@ -159,17 +169,24 @@ def deploy(
159
169
  infra_secret_name = (
160
170
  overrides.secrets.infra_secret_name if overrides.secrets else None
161
171
  ) or ""
172
+ postgresql = overrides.postgresql
173
+ if postgresql and postgresql.enabled:
174
+ # The bundled database's password lives in the cluster, not in
175
+ # values.yaml: reuse the one it was installed with, or make one up
176
+ # on the first install. A new one on upgrade would lock the
177
+ # cluster out of its existing database.
178
+ if postgresql.auth is None:
179
+ postgresql.auth = HelmChartOverrides.Postgresql.Auth()
180
+ if not postgresql.auth.password:
181
+ postgresql.auth.password = _installed_database_password(
182
+ infra_secret_name, namespace
183
+ ) or secrets.token_urlsafe(24)
184
+ database_password = postgresql.auth.password
185
+ else:
186
+ database_password = (
187
+ overrides.secrets.database_password if overrides.secrets else None
188
+ ) or ""
162
189
  if infra_secret_name:
163
- # Resolve the database password from postgresql subchart or explicit config.
164
- postgresql = overrides.postgresql
165
- if postgresql and postgresql.enabled:
166
- database_password = (
167
- postgresql.auth.password if postgresql.auth else None
168
- ) or ""
169
- else:
170
- database_password = (
171
- overrides.secrets.database_password if overrides.secrets else None
172
- ) or ""
173
190
  public_key_pem = _ensure_cluster_keypair_standalone(
174
191
  infra_secret_name, namespace, database_password=database_password
175
192
  )
@@ -199,17 +216,16 @@ def deploy(
199
216
  _require_tls_secret(operator_tls_secret, namespace)
200
217
  # 7. Helm upgrade --install
201
218
  if chart is None:
202
- # Use OCI chart from the registry
203
- if not registry:
204
- msg.fail(
205
- "registries.upstream (or legacy image.registry) is empty in values.yaml"
206
- )
207
- raise SystemExit(1)
208
- if container_sa_key:
209
- helm_registry_login(registry, container_sa_key)
210
- chart_ref = f"oci://{registry}/ellf"
219
+ chart_ref, registry_config = chart_source(creds, registry, container_sa_key)
211
220
  msg.info(f"Installing from {chart_ref}...")
212
- upgrade_from_ref(chart_ref, overrides, namespace=namespace, wait=wait)
221
+ with registry_config as registry_config_path:
222
+ upgrade_from_ref(
223
+ chart_ref,
224
+ overrides,
225
+ namespace=namespace,
226
+ wait=wait,
227
+ registry_config=registry_config_path,
228
+ )
213
229
  else:
214
230
  msg.info(f"Installing from local chart {chart}...")
215
231
  upgrade(chart, overrides, namespace=namespace, wait=wait)
@@ -439,32 +455,85 @@ def _ensure_cluster_keypair_standalone(
439
455
  def _patch_secret_field(secret_name: str, namespace: str, key: str, value: str) -> None:
440
456
  """Ensure a single field exists in an existing K8s secret.
441
457
 
442
- The patch body goes through ``--patch-file`` (a short-lived tempfile) so
443
- the value never appears on the kubectl command line, where ``ps`` would
444
- expose it.
458
+ The updated secret goes to kubectl on stdin, so the value appears neither
459
+ on the command line, where ``ps`` would expose it, nor in a file.
445
460
  """
446
- patch = json.dumps({"stringData": {key: value}})
447
- with tempfile.NamedTemporaryFile(
448
- mode="w", suffix=".json", delete=True
449
- ) as patch_file:
450
- patch_file.write(patch)
451
- patch_file.flush()
452
- subprocess.run(
453
- [
454
- "kubectl",
455
- "patch",
456
- "secret",
457
- secret_name,
458
- f"--namespace={namespace}",
459
- "--type",
460
- "merge",
461
- "--patch-file",
462
- patch_file.name,
463
- ],
464
- check=True,
465
- text=True,
466
- capture_output=True,
461
+ current = subprocess.run(
462
+ [
463
+ "kubectl",
464
+ "get",
465
+ "secret",
466
+ secret_name,
467
+ f"--namespace={namespace}",
468
+ "-o",
469
+ "json",
470
+ ],
471
+ check=True,
472
+ text=True,
473
+ capture_output=True,
474
+ )
475
+ secret = json.loads(current.stdout)
476
+ secret.setdefault("data", {})[key] = base64.b64encode(value.encode()).decode()
477
+ subprocess.run(
478
+ ["kubectl", "replace", "-f", "-"],
479
+ input=json.dumps(secret),
480
+ check=True,
481
+ text=True,
482
+ capture_output=True,
483
+ )
484
+
485
+
486
+ def _read_secret_field(secret_name: str, namespace: str, key: str) -> str:
487
+ """A field of a K8s secret, decoded; empty when the secret or field is missing."""
488
+ jsonpath_key = key.replace(".", r"\.")
489
+ result = subprocess.run(
490
+ [
491
+ "kubectl",
492
+ "get",
493
+ "secret",
494
+ secret_name,
495
+ f"--namespace={namespace}",
496
+ "-o",
497
+ f"jsonpath={{.data.{jsonpath_key}}}",
498
+ ],
499
+ text=True,
500
+ capture_output=True,
501
+ )
502
+ if result.returncode != 0 or not result.stdout.strip():
503
+ return ""
504
+ return base64.b64decode(result.stdout.strip()).decode("utf-8")
505
+
506
+
507
+ def _installed_database_password(infra_secret_name: str, namespace: str) -> str:
508
+ """The bundled database's password, from an earlier install of the cluster.
509
+
510
+ Deploy keeps it in the infra secret. Clusters installed before that have
511
+ it only in the database chart's own secret. Empty on a first install.
512
+ """
513
+ if infra_secret_name:
514
+ password = _read_secret_field(
515
+ infra_secret_name, namespace, "ELLF_DATABASE_PASSWORD"
467
516
  )
517
+ if password:
518
+ return password
519
+ return _read_secret_field(f"{DEFAULT_RELEASE}-postgresql", namespace, "password")
520
+
521
+
522
+ def _secrets_in_values(values: dict) -> list[str]:
523
+ """Dotted keys of the secrets a values.yaml still holds.
524
+
525
+ 'infra init-values' used to write them there; deploy now takes them from
526
+ PAM and the cluster instead.
527
+ """
528
+ found = []
529
+ secrets_block = values.get("secrets") or {}
530
+ for key in ("containerSaKey", "prodigyLicenseKey"):
531
+ if secrets_block.get(key):
532
+ found.append(f"secrets.{key}")
533
+ postgresql_auth = (values.get("postgresql") or {}).get("auth") or {}
534
+ if postgresql_auth.get("password"):
535
+ found.append("postgresql.auth.password")
536
+ return found
468
537
 
469
538
 
470
539
  WORKER_TYPES_CONFIGMAP = "ellf-worker-types"