hud-python 0.5.35__tar.gz → 0.5.37__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.
- {hud_python-0.5.35 → hud_python-0.5.37}/PKG-INFO +1 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/__init__.py +2 -0
- hud_python-0.5.37/hud/cli/login.py +293 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_build.py +2 -2
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_sync.py +0 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/api.py +2 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/settings.py +6 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/__init__.py +6 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/__init__.py +2 -0
- hud_python-0.5.37/hud/tools/coding/gemini_edit.py +340 -0
- hud_python-0.5.37/hud/tools/coding/gemini_write.py +92 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_gemini_tools.py +78 -15
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/__init__.py +2 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/base.py +20 -4
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/gemini.py +140 -44
- hud_python-0.5.37/hud/tools/filesystem/gemini_read_many.py +207 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/tests/test_glob.py +13 -4
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/tests/test_grep.py +47 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/tests/test_list.py +1 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/tests/test_read.py +46 -8
- hud_python-0.5.37/hud/tools/filesystem/tests/test_read_many.py +121 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/test_version.py +1 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/version.py +1 -1
- {hud_python-0.5.35 → hud_python-0.5.37}/pyproject.toml +1 -1
- hud_python-0.5.35/hud/tools/coding/gemini_edit.py +0 -252
- {hud_python-0.5.35 → hud_python-0.5.37}/.gitignore +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/LICENSE +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/README.md +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/examples/README.md +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/__main__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/claude.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/gateway.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/gemini_cua.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/grounded_openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/misc/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/misc/integration_test_agent.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/misc/response_agent.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/openai_chat.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/operator.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/resolver.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/conftest.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_base_runtime.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_claude.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_grounded_openai_agent.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_integration_test_agent.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_operator.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_resolver.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/tests/test_run_eval.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/agents/types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/__main__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/analyze.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/build.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/cancel.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/harbor.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/tests/conftest.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/convert/tests/test_harbor.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/debug.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/deploy.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/dev.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/eval.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/dev.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/tasks.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/templates.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/flows/tests/test_dev.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/link.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/models.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/push.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/rl.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/scenario.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/sync.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_analysis_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_analyze.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_analyze_metadata.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_analyze_module.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_build_failure.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_build_module.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_cli_init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_cli_main.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_cli_more_wrappers.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_cli_root.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_convert.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_debug.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_debug_directory_mode.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_deploy.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_dev.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_eval.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_eval_bedrock.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_lockfile_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_main_module.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_mcp_server.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_push.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_push_happy.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_push_wrapper.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_rl.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_scenario.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/tests/test_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/analysis.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/args.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/build_display.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/build_logs.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/collect.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/config.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/docker.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/env_check.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/environment.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/git.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/interactive.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/lockfile.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/logging.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/metadata.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/name_check.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/project_config.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/server.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/source_hash.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tasks.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/taskset.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_collect.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_config.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_docker.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_docker_hints.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_env_check.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_environment.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_git.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_interactive_module.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_logging_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_metadata.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_source_hash.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/tests/test_tasks.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/validation.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/version_check.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/cli/utils/viewer.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/loader.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/runner.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/tests/test_loader.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/tests/test_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/datasets/utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connection.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/local.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/mcp_config.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/connectors/remote.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/environment.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/adk.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/anthropic.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/langchain.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/llamaindex.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/integrations/openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/mock.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/router.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/scenarios.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_connection.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_connectors.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_environment.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_integrations.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_local_connectors.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_scenarios.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_session_id.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/tests/test_tools.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/utils/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/utils/formats.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/utils/schema.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/environment/utils/tool_wrappers.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/display.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/instrument.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/manager.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/parallel.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/task.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/test_context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/test_eval.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/test_manager.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/test_parallel.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/tests/test_task.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/eval/utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/chat.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/graders.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/permissions.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/skills.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/native/tests/test_graders.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/patches/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/patches/mcp_patches.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/patches/warnings.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/py.typed +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/helper/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/low_level.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/router.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/server.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_add_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_mcp_server_handlers.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_mcp_server_integration.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_mcp_server_more.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_prefix_naming.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_run_wrapper.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_server_extra.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/server/tests/test_sigterm_runner.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/chat.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/chat_service.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/reply_metadata.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/tests/test_chat.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/services/tests/test_chat_service.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/exceptions.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/hints.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/requests.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/tests/test_exceptions.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/tests/test_hints.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/shared/tests/test_requests.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/exporter.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/instrument.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/tests/test_eval_telemetry.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/tests/test_exporter.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/telemetry/tests/test_instrument.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/agent.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/apply_patch.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/bash.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/edit.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/gemini_shell.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/session.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/shell.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_apply_patch.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_bash.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_bash_extended.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_bash_integration.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_edit.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/tests/test_shell.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/coding/utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/anthropic.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/glm.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/hud.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/openai.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/qwen.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/settings.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/tests/test_compression.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/tests/test_computer.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/tests/test_computer_actions.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/computer/tests/test_glm_computer.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/elicitation.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/pyautogui.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/tests/test_base_executor.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/tests/test_pyautogui_executor.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/executors/xdo.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/glob.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/grep.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/list.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/read.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/filesystem/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/config.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/grounded_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/grounder.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/grounding/tests/test_grounded_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/code_execution.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/google_search.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/tool_search.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/url_context.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/web_fetch.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/hosted/web_search.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/jupyter.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/claude.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/session.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/tests/test_claude.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/tests/test_gemini.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/memory/tests/test_session.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/native_types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/playwright.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/response.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/submit.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_agent_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_base.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_elicitation.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_jupyter_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_native_tool_e2e.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_native_types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_playwright_tool.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_response.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_submit.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_tools.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_tools_init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/tests/test_utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/tools/utils.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/types.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/env.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/hud_console.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/mcp.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/pretty_errors.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/serialization.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/strict_schema.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/__init__.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/test_init.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/test_pretty_errors.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/test_serialization.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tests/test_tool_shorthand.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/tool_shorthand.py +0 -0
- {hud_python-0.5.35 → hud_python-0.5.37}/hud/utils/types.py +0 -0
|
@@ -38,6 +38,7 @@ from .dev import dev_command # noqa: E402
|
|
|
38
38
|
from .eval import eval_command # noqa: E402
|
|
39
39
|
from .init import init_command # noqa: E402
|
|
40
40
|
from .link import link_command # noqa: E402
|
|
41
|
+
from .login import login_command # noqa: E402
|
|
41
42
|
from .models import models_command # noqa: E402
|
|
42
43
|
from .push import push_command # noqa: E402
|
|
43
44
|
from .rl import rl_run_command, rl_status_command # noqa: E402
|
|
@@ -52,6 +53,7 @@ app.command(name="dev", context_settings=_EXTRA_ARGS)(dev_command)
|
|
|
52
53
|
app.command(name="build", context_settings=_EXTRA_ARGS)(build_command)
|
|
53
54
|
app.command(name="deploy")(deploy_command)
|
|
54
55
|
app.command(name="link", hidden=True)(link_command)
|
|
56
|
+
app.command(name="login")(login_command)
|
|
55
57
|
app.command(name="eval")(eval_command)
|
|
56
58
|
app.command(name="push", hidden=True)(push_command)
|
|
57
59
|
app.command(name="init")(init_command)
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"""``hud login`` — Browser-based login for the HUD CLI.
|
|
2
|
+
|
|
3
|
+
Implements the OAuth 2.0 Device Authorization Grant (RFC 8628) against the
|
|
4
|
+
HUD platform so users can authenticate without copy-pasting an API key:
|
|
5
|
+
|
|
6
|
+
Use ``--quiet`` / ``-q`` to print the URL instead of opening a browser
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import contextlib
|
|
12
|
+
import socket
|
|
13
|
+
import time
|
|
14
|
+
import webbrowser
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import httpx
|
|
18
|
+
import typer
|
|
19
|
+
from rich.panel import Panel
|
|
20
|
+
from rich.text import Text
|
|
21
|
+
|
|
22
|
+
from hud.settings import settings
|
|
23
|
+
from hud.utils.hud_console import HUDConsole
|
|
24
|
+
|
|
25
|
+
from .utils.config import get_user_env_path, set_env_values
|
|
26
|
+
|
|
27
|
+
DEVICE_CODE_PATH = "/auth/device/code"
|
|
28
|
+
DEVICE_TOKEN_PATH = "/auth/device/token" # noqa: S105 — URL path, not a secret
|
|
29
|
+
|
|
30
|
+
# Fallback poll interval if the server doesn't send one.
|
|
31
|
+
DEFAULT_POLL_INTERVAL = 5
|
|
32
|
+
# Max wall-clock time to wait for the user to confirm.
|
|
33
|
+
DEFAULT_EXPIRES_IN = 600
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _client_name() -> str:
|
|
37
|
+
try:
|
|
38
|
+
return socket.gethostname() or "unknown host"
|
|
39
|
+
except Exception:
|
|
40
|
+
return "unknown host"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _client_version() -> str:
|
|
44
|
+
try:
|
|
45
|
+
from hud import __version__
|
|
46
|
+
|
|
47
|
+
return str(__version__)
|
|
48
|
+
except Exception:
|
|
49
|
+
return "unknown"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _api_base_url() -> str:
|
|
53
|
+
return settings.hud_api_url.rstrip("/")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _fallback_web_url() -> str:
|
|
57
|
+
return settings.hud_web_url.rstrip("/")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _extract_error_code(response: httpx.Response) -> str | None:
|
|
61
|
+
"""Pull RFC 8628 error codes out of a non-200 response.
|
|
62
|
+
|
|
63
|
+
The backend wraps errors as ``{"detail": {"error": "authorization_pending"}}``
|
|
64
|
+
via FastAPI's ``HTTPException``. Be defensive in case the shape changes.
|
|
65
|
+
"""
|
|
66
|
+
try:
|
|
67
|
+
body: Any = response.json()
|
|
68
|
+
except Exception:
|
|
69
|
+
return None
|
|
70
|
+
if isinstance(body, dict):
|
|
71
|
+
detail = body.get("detail")
|
|
72
|
+
if isinstance(detail, dict) and isinstance(detail.get("error"), str):
|
|
73
|
+
return detail["error"]
|
|
74
|
+
if isinstance(body.get("error"), str):
|
|
75
|
+
return body["error"]
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _request_device_code(client: httpx.Client, hud_console: HUDConsole) -> dict[str, Any]:
|
|
80
|
+
"""Call ``POST /auth/device/code`` and return the parsed response body."""
|
|
81
|
+
try:
|
|
82
|
+
response = client.post(
|
|
83
|
+
f"{_api_base_url()}{DEVICE_CODE_PATH}",
|
|
84
|
+
json={
|
|
85
|
+
"client_name": _client_name(),
|
|
86
|
+
"client_version": _client_version(),
|
|
87
|
+
},
|
|
88
|
+
timeout=30.0,
|
|
89
|
+
)
|
|
90
|
+
except httpx.RequestError as exc:
|
|
91
|
+
hud_console.error(f"Failed to reach HUD API: {exc}")
|
|
92
|
+
hud_console.info(f"HUD_API_URL={_api_base_url()}")
|
|
93
|
+
raise typer.Exit(1) from exc
|
|
94
|
+
|
|
95
|
+
if response.status_code != 200:
|
|
96
|
+
hud_console.error(f"HUD API returned {response.status_code} when starting login.")
|
|
97
|
+
with contextlib.suppress(Exception):
|
|
98
|
+
hud_console.info(response.text[:500])
|
|
99
|
+
raise typer.Exit(1)
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
return response.json()
|
|
103
|
+
except Exception as exc:
|
|
104
|
+
hud_console.error("HUD API returned an invalid response.")
|
|
105
|
+
raise typer.Exit(1) from exc
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _display_login_prompt(
|
|
109
|
+
hud_console: HUDConsole,
|
|
110
|
+
*,
|
|
111
|
+
user_code: str,
|
|
112
|
+
verification_uri: str,
|
|
113
|
+
verification_uri_complete: str,
|
|
114
|
+
quiet: bool,
|
|
115
|
+
) -> None:
|
|
116
|
+
"""Show the big 'open this URL / enter this code' card."""
|
|
117
|
+
body = Text()
|
|
118
|
+
body.append("Verification code: ", style="dim")
|
|
119
|
+
body.append(f"{user_code}\n\n", style="bold cyan")
|
|
120
|
+
if quiet:
|
|
121
|
+
body.append("Open this URL in your browser:\n", style="dim")
|
|
122
|
+
else:
|
|
123
|
+
body.append("Opening this URL in your browser:\n", style="dim")
|
|
124
|
+
body.append(f" {verification_uri_complete}\n\n")
|
|
125
|
+
body.append("Or visit ", style="dim")
|
|
126
|
+
body.append(verification_uri, style="")
|
|
127
|
+
body.append(" and enter the code manually.", style="dim")
|
|
128
|
+
|
|
129
|
+
hud_console.console.print(
|
|
130
|
+
Panel(
|
|
131
|
+
body,
|
|
132
|
+
title="[bold]hud login[/bold]",
|
|
133
|
+
border_style="cyan",
|
|
134
|
+
padding=(1, 2),
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _poll_for_token(
|
|
140
|
+
client: httpx.Client,
|
|
141
|
+
hud_console: HUDConsole,
|
|
142
|
+
*,
|
|
143
|
+
device_code: str,
|
|
144
|
+
interval: int,
|
|
145
|
+
expires_in: int,
|
|
146
|
+
) -> dict[str, Any]:
|
|
147
|
+
"""Poll ``/auth/device/token`` until success, timeout, or fatal error."""
|
|
148
|
+
deadline = time.monotonic() + max(expires_in, 30)
|
|
149
|
+
current_interval = max(interval, 1)
|
|
150
|
+
|
|
151
|
+
with hud_console.console.status(
|
|
152
|
+
"[cyan]Waiting for confirmation in your browser...[/cyan]",
|
|
153
|
+
spinner="dots",
|
|
154
|
+
):
|
|
155
|
+
while time.monotonic() < deadline:
|
|
156
|
+
# Sleep first so we don't hammer the server on the initial tick
|
|
157
|
+
# before the user has had a chance to click "Connect CLI".
|
|
158
|
+
time.sleep(current_interval)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
response = client.post(
|
|
162
|
+
f"{_api_base_url()}{DEVICE_TOKEN_PATH}",
|
|
163
|
+
json={"device_code": device_code},
|
|
164
|
+
timeout=30.0,
|
|
165
|
+
)
|
|
166
|
+
except httpx.RequestError:
|
|
167
|
+
# Transient network error — keep polling.
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
if response.status_code == 200:
|
|
171
|
+
try:
|
|
172
|
+
return response.json()
|
|
173
|
+
except Exception as exc: # pragma: no cover — server misbehaving
|
|
174
|
+
hud_console.error("HUD API returned an invalid token response.")
|
|
175
|
+
raise typer.Exit(1) from exc
|
|
176
|
+
|
|
177
|
+
error = _extract_error_code(response)
|
|
178
|
+
if error == "authorization_pending":
|
|
179
|
+
continue
|
|
180
|
+
if error == "slow_down":
|
|
181
|
+
current_interval += 5
|
|
182
|
+
continue
|
|
183
|
+
if error == "expired_token":
|
|
184
|
+
hud_console.error(
|
|
185
|
+
"Login code expired before you confirmed. Run 'hud login' to try again."
|
|
186
|
+
)
|
|
187
|
+
raise typer.Exit(1)
|
|
188
|
+
if error == "access_denied":
|
|
189
|
+
hud_console.error("Login was denied in the browser.")
|
|
190
|
+
raise typer.Exit(1)
|
|
191
|
+
|
|
192
|
+
# Unknown 4xx/5xx — treat as transient unless it's an obvious fatal.
|
|
193
|
+
if 500 <= response.status_code < 600:
|
|
194
|
+
continue
|
|
195
|
+
|
|
196
|
+
hud_console.error(f"Unexpected response from HUD API ({response.status_code}).")
|
|
197
|
+
with contextlib.suppress(Exception):
|
|
198
|
+
hud_console.info(response.text[:500])
|
|
199
|
+
raise typer.Exit(1)
|
|
200
|
+
|
|
201
|
+
hud_console.error("Login timed out. Run 'hud login' to try again.")
|
|
202
|
+
raise typer.Exit(1)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _persist_api_key(hud_console: HUDConsole, api_key: str) -> None:
|
|
206
|
+
"""Write ``HUD_API_KEY`` into ``~/.hud/.env``."""
|
|
207
|
+
try:
|
|
208
|
+
path = set_env_values({"HUD_API_KEY": api_key})
|
|
209
|
+
except Exception as exc:
|
|
210
|
+
hud_console.error(f"Failed to write {get_user_env_path()}: {exc}")
|
|
211
|
+
hud_console.info("You can set the key manually with:")
|
|
212
|
+
hud_console.info(f" hud set HUD_API_KEY={api_key}")
|
|
213
|
+
raise typer.Exit(1) from exc
|
|
214
|
+
|
|
215
|
+
hud_console.success("Saved API key to user config")
|
|
216
|
+
hud_console.info(f"Location: {path}")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def login_command(
|
|
220
|
+
quiet: bool = typer.Option(
|
|
221
|
+
False,
|
|
222
|
+
"--quiet",
|
|
223
|
+
"-q",
|
|
224
|
+
help="Don't try to open a browser; print the verification URL instead.",
|
|
225
|
+
),
|
|
226
|
+
) -> None:
|
|
227
|
+
"""Authenticate with the HUD platform.
|
|
228
|
+
|
|
229
|
+
[not dim]Opens a browser to hud.ai, confirms your identity, and stores a
|
|
230
|
+
freshly-minted API key in ~/.hud/.env.
|
|
231
|
+
|
|
232
|
+
Examples:
|
|
233
|
+
hud login
|
|
234
|
+
hud login --quiet[/not dim]
|
|
235
|
+
"""
|
|
236
|
+
hud_console = HUDConsole()
|
|
237
|
+
|
|
238
|
+
# -- Device authorization grant -----------------------------------------
|
|
239
|
+
try:
|
|
240
|
+
with httpx.Client() as client:
|
|
241
|
+
device = _request_device_code(client, hud_console)
|
|
242
|
+
|
|
243
|
+
device_code = device["device_code"]
|
|
244
|
+
user_code = device["user_code"]
|
|
245
|
+
verification_uri = device.get("verification_uri") or f"{_fallback_web_url()}/device"
|
|
246
|
+
verification_uri_complete = (
|
|
247
|
+
device.get("verification_uri_complete")
|
|
248
|
+
or f"{_fallback_web_url()}/device?code={user_code}"
|
|
249
|
+
)
|
|
250
|
+
interval = int(device.get("interval") or DEFAULT_POLL_INTERVAL)
|
|
251
|
+
expires_in = int(device.get("expires_in") or DEFAULT_EXPIRES_IN)
|
|
252
|
+
|
|
253
|
+
_display_login_prompt(
|
|
254
|
+
hud_console,
|
|
255
|
+
user_code=user_code,
|
|
256
|
+
verification_uri=verification_uri,
|
|
257
|
+
verification_uri_complete=verification_uri_complete,
|
|
258
|
+
quiet=quiet,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if not quiet:
|
|
262
|
+
with contextlib.suppress(Exception):
|
|
263
|
+
webbrowser.open(verification_uri_complete, new=2)
|
|
264
|
+
|
|
265
|
+
token = _poll_for_token(
|
|
266
|
+
client,
|
|
267
|
+
hud_console,
|
|
268
|
+
device_code=device_code,
|
|
269
|
+
interval=interval,
|
|
270
|
+
expires_in=expires_in,
|
|
271
|
+
)
|
|
272
|
+
except KeyboardInterrupt:
|
|
273
|
+
hud_console.info("\nLogin cancelled.")
|
|
274
|
+
raise typer.Exit(130) from None
|
|
275
|
+
|
|
276
|
+
# -- Persist and report -------------------------------------------------
|
|
277
|
+
key = token.get("api_key")
|
|
278
|
+
if not isinstance(key, str) or not key:
|
|
279
|
+
hud_console.error("HUD API returned a login response without an API key.")
|
|
280
|
+
raise typer.Exit(1)
|
|
281
|
+
|
|
282
|
+
_persist_api_key(hud_console, key)
|
|
283
|
+
|
|
284
|
+
user_info = token.get("user") or {}
|
|
285
|
+
team_info = token.get("team") or {}
|
|
286
|
+
user_email = user_info.get("email") if isinstance(user_info, dict) else None
|
|
287
|
+
team_name = team_info.get("name") if isinstance(team_info, dict) else None
|
|
288
|
+
|
|
289
|
+
if user_email:
|
|
290
|
+
hud_console.info(f"Logged in as {user_email}")
|
|
291
|
+
if team_name:
|
|
292
|
+
hud_console.info(f"Team: {team_name}")
|
|
293
|
+
hud_console.info("You're all set, try 'hud eval --help'.")
|
|
@@ -61,12 +61,12 @@ class TestIncrementVersion:
|
|
|
61
61
|
def test_increment_minor(self):
|
|
62
62
|
"""Test incrementing minor version."""
|
|
63
63
|
assert increment_version("1.2.3", "minor") == "1.3.0"
|
|
64
|
-
assert increment_version("0.5.
|
|
64
|
+
assert increment_version("0.5.37", "minor") == "0.6.0"
|
|
65
65
|
|
|
66
66
|
def test_increment_major(self):
|
|
67
67
|
"""Test incrementing major version."""
|
|
68
68
|
assert increment_version("1.2.3", "major") == "2.0.0"
|
|
69
|
-
assert increment_version("0.5.
|
|
69
|
+
assert increment_version("0.5.37", "major") == "1.0.0"
|
|
70
70
|
|
|
71
71
|
def test_increment_with_v_prefix(self):
|
|
72
72
|
"""Test incrementing version with v prefix."""
|
|
@@ -777,7 +777,6 @@ class TestColumnInference:
|
|
|
777
777
|
defs = _build_column_definitions(specs)
|
|
778
778
|
assert defs is not None
|
|
779
779
|
assert defs["difficulty"]["type"] == "text"
|
|
780
|
-
assert defs["score"]["type"] == "number"
|
|
781
780
|
|
|
782
781
|
def test_build_column_definitions_empty(self) -> None:
|
|
783
782
|
from hud.cli.sync import _build_column_definitions
|
|
@@ -15,7 +15,8 @@ def require_api_key(action: str = "perform this action") -> str:
|
|
|
15
15
|
hud_console = HUDConsole()
|
|
16
16
|
hud_console.error("No HUD API key found")
|
|
17
17
|
hud_console.info(f"A HUD API key is required to {action}.")
|
|
18
|
-
hud_console.info("
|
|
18
|
+
hud_console.info("Run: hud login")
|
|
19
|
+
hud_console.info("Or get your key at: https://hud.ai/settings")
|
|
19
20
|
hud_console.info("Set it via: hud set HUD_API_KEY=your-key-here")
|
|
20
21
|
raise typer.Exit(1)
|
|
21
22
|
return settings.api_key
|
|
@@ -76,6 +76,12 @@ class Settings(BaseSettings):
|
|
|
76
76
|
validation_alias="HUD_API_URL",
|
|
77
77
|
)
|
|
78
78
|
|
|
79
|
+
hud_web_url: str = Field(
|
|
80
|
+
default="https://hud.ai",
|
|
81
|
+
description="Base URL of the HUD web app (used as a fallback for CLI login)",
|
|
82
|
+
validation_alias="HUD_WEB_URL",
|
|
83
|
+
)
|
|
84
|
+
|
|
79
85
|
hud_gateway_url: str = Field(
|
|
80
86
|
default="https://inference.hud.ai",
|
|
81
87
|
description="Base URL for the HUD inference gateway",
|
|
@@ -43,6 +43,7 @@ if TYPE_CHECKING:
|
|
|
43
43
|
EditTool,
|
|
44
44
|
GeminiEditTool,
|
|
45
45
|
GeminiShellTool,
|
|
46
|
+
GeminiWriteTool,
|
|
46
47
|
ShellTool,
|
|
47
48
|
)
|
|
48
49
|
from .computer import (
|
|
@@ -54,6 +55,7 @@ if TYPE_CHECKING:
|
|
|
54
55
|
QwenComputerTool,
|
|
55
56
|
)
|
|
56
57
|
from .filesystem import (
|
|
58
|
+
GeminiReadManyTool,
|
|
57
59
|
GlobTool,
|
|
58
60
|
GrepTool,
|
|
59
61
|
ListTool,
|
|
@@ -74,7 +76,9 @@ __all__ = [
|
|
|
74
76
|
"GeminiComputerTool",
|
|
75
77
|
"GeminiEditTool",
|
|
76
78
|
"GeminiMemoryTool",
|
|
79
|
+
"GeminiReadManyTool",
|
|
77
80
|
"GeminiShellTool",
|
|
81
|
+
"GeminiWriteTool",
|
|
78
82
|
"GlobTool",
|
|
79
83
|
"GoogleSearchTool",
|
|
80
84
|
"GrepTool",
|
|
@@ -121,6 +125,7 @@ def __getattr__(name: str) -> Any:
|
|
|
121
125
|
"ApplyPatchTool",
|
|
122
126
|
"GeminiShellTool",
|
|
123
127
|
"GeminiEditTool",
|
|
128
|
+
"GeminiWriteTool",
|
|
124
129
|
):
|
|
125
130
|
from . import coding
|
|
126
131
|
|
|
@@ -132,6 +137,7 @@ def __getattr__(name: str) -> Any:
|
|
|
132
137
|
"GrepTool",
|
|
133
138
|
"GlobTool",
|
|
134
139
|
"ListTool",
|
|
140
|
+
"GeminiReadManyTool",
|
|
135
141
|
):
|
|
136
142
|
from . import filesystem
|
|
137
143
|
|
|
@@ -23,6 +23,7 @@ from hud.tools.coding.bash import BashTool, ClaudeBashSession, _BashSession
|
|
|
23
23
|
from hud.tools.coding.edit import Command, EditTool
|
|
24
24
|
from hud.tools.coding.gemini_edit import GeminiEditTool
|
|
25
25
|
from hud.tools.coding.gemini_shell import GeminiShellOutput, GeminiShellTool
|
|
26
|
+
from hud.tools.coding.gemini_write import GeminiWriteTool
|
|
26
27
|
from hud.tools.coding.session import BashSession, ShellCallOutcome, ShellCommandOutput
|
|
27
28
|
from hud.tools.coding.shell import ShellResult, ShellTool
|
|
28
29
|
from hud.tools.coding.utils import (
|
|
@@ -49,6 +50,7 @@ __all__ = [
|
|
|
49
50
|
"GeminiEditTool",
|
|
50
51
|
"GeminiShellOutput",
|
|
51
52
|
"GeminiShellTool",
|
|
53
|
+
"GeminiWriteTool",
|
|
52
54
|
"ShellCallOutcome",
|
|
53
55
|
"ShellCommandOutput",
|
|
54
56
|
"ShellResult",
|