ellf-cli 6.0.2__tar.gz → 6.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ellf_cli-6.0.2/ellf_cli.egg-info → ellf_cli-6.0.3}/PKG-INFO +1 -1
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/about.json +1 -1
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/auth.py +20 -6
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/general.py +11 -8
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf.json +1 -1
- {ellf_cli-6.0.2 → ellf_cli-6.0.3/ellf_cli.egg-info}/PKG-INFO +1 -1
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_login.py +83 -1
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/LICENSE +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/MANIFEST.in +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/README.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/__main__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/about.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/appdirs.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/cli.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/cloud/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/cloud/gcp.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/cluster_config.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/_cluster_select.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/_org_select.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/_recipe_file.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/_recipe_subcommand.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/_state.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/actions.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/agents.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/assets.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/auth.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/clusters.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/config.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/datasets.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/cp.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/ls.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/rm.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/rsync.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/files/stats.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/import_export.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/_helpers.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/deploy.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/init_values.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/provision.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/register.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/setup.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/start.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/terraform.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/infra/tls.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/jobs.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/packages.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/paths.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/plans.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/projects.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/publish_code.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/publish_data.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/recipes.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/secrets.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/support.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/tasks.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/commands/todos.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/config.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/.claude-plugin/plugin.json +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/.gitignore +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skill_variants.json +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/annotation_audit.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/references/builtin_ellf_annotation_recipes.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/annotation_audit.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_ellf_annotation_recipes.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.coding/references/builtin_prodigy_recipes.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ask/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-handoff/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/annotation_metrics.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/references/training_monitoring.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/annotation_metrics.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/references/training_monitoring.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.coding/scripts/check_training.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ops.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ops.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ops.coding/references/data_infra_cli.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ops.coding/scripts/run_job.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-patterns/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-patterns/references/pattern_strategies.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_action_recipe.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_agent_recipe.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_blocks_ui.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_correct.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_custom_ui.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_manual.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_pages_ui.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_routing.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_task_recipe.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/assets/templates/template_teach.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/builtin_recipes.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/ellf_recipe_sdk.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/lint_recipe.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/prodigy_recipe_api.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/template_index.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/consulting_patterns.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/explosion_strategy.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.assistant/references/prodigy_llm_bot.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/consulting_patterns.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/explosion_strategy.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.coding/references/prodigy_llm_bot.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-support.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-support.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-todo/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/diagnostics.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/evaluation_guide.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/model_selection.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/training_paradigms.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.assistant/references/workflow.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/SKILL.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_advanced.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_architectures.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/config_training.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/diagnostics.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/evaluation_guide.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/experiment_patterns.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/model_selection.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_paradigms.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/training_troubleshooting.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/references/workflow.md +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-train.coding/scripts/ellf_logger.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/errors.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/helm.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/key_pair.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/main.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/messages.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/query.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/cookiecutter.json +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/.gitignore +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/README.md.tmpl +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements-dev.in +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/requirements.in +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/setup.py.tmpl +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/about.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/recipes_cookiecutter/{{cookiecutter.package_dir}}/{{cookiecutter.package_name}}/recipes/example_task.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/testing/__init__.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ty.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ui.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/url.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/util.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/SOURCES.txt +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/dependency_links.txt +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/entry_points.txt +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/not-zip-safe +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/requires.txt +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli.egg-info/top_level.txt +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/pyproject.toml +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/setup.cfg +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/setup.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_appdirs.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_auth.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_config.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_errors.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_files_cp.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_files_cp_helpers.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_info.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_invalid_secrets.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_key_pair.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_logout.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_main.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_org_select.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_plans.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_projects.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_query.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_recipe_file.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_recipes.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_state.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_support.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_ty.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_ui.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_ui_extras.py +0 -0
- {ellf_cli-6.0.2 → ellf_cli-6.0.3}/tests/test_util.py +0 -0
|
@@ -210,10 +210,11 @@ class AuthStateImpl:
|
|
|
210
210
|
# PAM lookup-by-address every time the user runs an ellf command.
|
|
211
211
|
# `auth.cluster_id` falls back to the address lookup only if this is None.
|
|
212
212
|
self._cluster_id = settings.cluster_id
|
|
213
|
-
# Seed org_id from saved
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
213
|
+
# Seed org_id from saved-defaults as a fallback only. The ``org_id``
|
|
214
|
+
# property reads from the api_token's ``oid`` claim — which is what
|
|
215
|
+
# PAM authorizes against — and overwrites this value on first access.
|
|
216
|
+
# The seed is just here to satisfy callers that read ``_org_id``
|
|
217
|
+
# before any token is fetched.
|
|
217
218
|
self._org_id = settings.org_id
|
|
218
219
|
self._secrets_path = ctx.secrets_path
|
|
219
220
|
self._saved_settings_path = ctx.saved_settings_path
|
|
@@ -269,9 +270,22 @@ class AuthStateImpl:
|
|
|
269
270
|
|
|
270
271
|
@property
|
|
271
272
|
def org_id(self) -> UUID:
|
|
273
|
+
# PAM authorizes against the api_token's ``oid`` claim, so the JWT
|
|
274
|
+
# is the source of truth. The saved-defaults pointer (seeded into
|
|
275
|
+
# ``_org_id`` in __init__) can drift — e.g. when secrets.json is
|
|
276
|
+
# restored from backup, when a switch updates the pointer without
|
|
277
|
+
# re-minting the token, or when an ELLF_API_TOKEN env var injects
|
|
278
|
+
# a token from a different org. Reading from the JWT keeps every
|
|
279
|
+
# caller (server-side request bodies, display strings) aligned
|
|
280
|
+
# with what PAM will actually authorize against.
|
|
281
|
+
oid = self.get_api_token().header.get("oid")
|
|
282
|
+
if oid is not None:
|
|
283
|
+
self._org_id = UUID(oid)
|
|
284
|
+
return self._org_id
|
|
272
285
|
if self._org_id is None:
|
|
273
|
-
#
|
|
274
|
-
#
|
|
286
|
+
# Token missing the oid claim (older PAM tokens, or an
|
|
287
|
+
# externally-supplied ELLF_API_TOKEN). Fall back to listing —
|
|
288
|
+
# the login should only have the user's own org accessible.
|
|
275
289
|
orgs = list(self.client.org.all())
|
|
276
290
|
if not orgs:
|
|
277
291
|
raise EllfError(message="Could not fetch orgs")
|
|
@@ -152,17 +152,20 @@ def _select_and_persist_org(
|
|
|
152
152
|
) -> UUID:
|
|
153
153
|
"""Pick an org via pam and write it into SavedSettings.
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
The api_token's JWT carries an ``oid`` claim that PAM authorizes
|
|
156
|
+
against server-side; the saved-defaults ``org_id`` is only a local
|
|
157
|
+
display pointer. The two can drift apart (e.g. saved-defaults reset
|
|
158
|
+
independently, or a prior switch that updated the pointer without
|
|
159
|
+
re-minting). We compare ``chosen`` to the JWT claim — not the saved
|
|
160
|
+
pointer — so a ``login --org X`` that finds the pointer already at X
|
|
161
|
+
but the token issued for Y still calls ``/v1/token/switch-org`` and
|
|
162
|
+
converges both sides on X.
|
|
161
163
|
"""
|
|
162
164
|
chosen = select_org(auth.client, name_or_id)
|
|
163
165
|
settings = get_saved_settings()
|
|
164
|
-
|
|
165
|
-
if
|
|
166
|
+
token_oid = auth.get_api_token().header.get("oid")
|
|
167
|
+
token_org_id = UUID(token_oid) if token_oid else None
|
|
168
|
+
if token_org_id != chosen.org_id:
|
|
166
169
|
auth.set_active_org(chosen.org_id)
|
|
167
170
|
settings.update("org_id", chosen.org_id)
|
|
168
171
|
settings.save(get_root_cfg().saved_settings_path)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
5
|
+
from uuid import uuid4
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
def _plugin_runtime_files(base_dir: Path) -> dict[Path, bytes]:
|
|
@@ -154,6 +156,86 @@ def test_install_claude_skills_with_packaged_plugin(tmp_path, monkeypatch):
|
|
|
154
156
|
assert (dest / "ellf-patterns").is_dir()
|
|
155
157
|
|
|
156
158
|
|
|
159
|
+
def _fake_membership(org_id, org_name="acme"):
|
|
160
|
+
return SimpleNamespace(
|
|
161
|
+
org_id=org_id,
|
|
162
|
+
org_name=org_name,
|
|
163
|
+
user_id=uuid4(),
|
|
164
|
+
is_org_admin=True,
|
|
165
|
+
is_org_developer=True,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def _build_select_org_test(tmp_path, monkeypatch, *, jwt_oid, saved_org, chosen_org):
|
|
170
|
+
"""Common scaffolding for _select_and_persist_org tests.
|
|
171
|
+
|
|
172
|
+
Patches the three module-level lookups the function depends on
|
|
173
|
+
(``select_org``, ``get_saved_settings``, ``get_root_cfg``) and returns
|
|
174
|
+
a mock ``auth`` whose ``get_api_token().header['oid']`` is ``jwt_oid``.
|
|
175
|
+
"""
|
|
176
|
+
from ellf_cli.commands import general
|
|
177
|
+
from ellf_cli.config import SavedSettings
|
|
178
|
+
|
|
179
|
+
settings = SavedSettings.blank()
|
|
180
|
+
settings.org_id = saved_org
|
|
181
|
+
settings_path = tmp_path / "saved-defaults.json"
|
|
182
|
+
monkeypatch.setattr(general, "get_saved_settings", lambda: settings)
|
|
183
|
+
monkeypatch.setattr(
|
|
184
|
+
general,
|
|
185
|
+
"get_root_cfg",
|
|
186
|
+
lambda: SimpleNamespace(saved_settings_path=settings_path),
|
|
187
|
+
)
|
|
188
|
+
monkeypatch.setattr(
|
|
189
|
+
general,
|
|
190
|
+
"select_org",
|
|
191
|
+
MagicMock(return_value=_fake_membership(chosen_org)),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
auth = MagicMock()
|
|
195
|
+
auth.get_api_token.return_value = SimpleNamespace(header={"oid": str(jwt_oid)})
|
|
196
|
+
return general, auth, settings, settings_path
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_select_and_persist_org_reissues_when_jwt_disagrees(tmp_path, monkeypatch):
|
|
200
|
+
"""Regression: even if saved-defaults already names the chosen org, a
|
|
201
|
+
mismatched JWT must trigger ``/v1/token/switch-org`` so the local
|
|
202
|
+
pointer and the server-side authorization converge.
|
|
203
|
+
"""
|
|
204
|
+
chosen_org = uuid4()
|
|
205
|
+
jwt_org = uuid4() # token was issued for a different org
|
|
206
|
+
general, auth, settings, settings_path = _build_select_org_test(
|
|
207
|
+
tmp_path,
|
|
208
|
+
monkeypatch,
|
|
209
|
+
jwt_oid=jwt_org,
|
|
210
|
+
saved_org=chosen_org, # stale pointer already at chosen
|
|
211
|
+
chosen_org=chosen_org,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
result = general._select_and_persist_org(auth, chosen_org)
|
|
215
|
+
|
|
216
|
+
assert result == chosen_org
|
|
217
|
+
auth.set_active_org.assert_called_once_with(chosen_org)
|
|
218
|
+
assert settings.org_id == chosen_org
|
|
219
|
+
assert json.loads(settings_path.read_text())["org_id"] == str(chosen_org)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def test_select_and_persist_org_skips_reissue_when_jwt_matches(tmp_path, monkeypatch):
|
|
223
|
+
"""No token round-trip when the JWT already authorizes the chosen org."""
|
|
224
|
+
chosen_org = uuid4()
|
|
225
|
+
general, auth, _, _ = _build_select_org_test(
|
|
226
|
+
tmp_path,
|
|
227
|
+
monkeypatch,
|
|
228
|
+
jwt_oid=chosen_org,
|
|
229
|
+
saved_org=uuid4(), # saved-defaults out of sync the other way
|
|
230
|
+
chosen_org=chosen_org,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
result = general._select_and_persist_org(auth, chosen_org)
|
|
234
|
+
|
|
235
|
+
assert result == chosen_org
|
|
236
|
+
auth.set_active_org.assert_not_called()
|
|
237
|
+
|
|
238
|
+
|
|
157
239
|
def test_install_claude_skills_leaves_existing_settings_untouched(
|
|
158
240
|
tmp_path, monkeypatch
|
|
159
241
|
):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-annotate.assistant/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-monitor.assistant/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-ops.coding/scripts/run_job.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-prodigy/references/lint_recipe.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-project.assistant/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ellf_cli-6.0.2 → ellf_cli-6.0.3}/ellf_cli/ellf_skills/skills/ellf-support.assistant/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|