alloy-runtime-cli 0.1.0__py3-none-any.whl
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.
- alloy_runtime_cli-0.1.0.dist-info/METADATA +61 -0
- alloy_runtime_cli-0.1.0.dist-info/RECORD +451 -0
- alloy_runtime_cli-0.1.0.dist-info/WHEEL +5 -0
- alloy_runtime_cli-0.1.0.dist-info/entry_points.txt +2 -0
- alloy_runtime_cli-0.1.0.dist-info/top_level.txt +1 -0
- cli/__init__.py +0 -0
- cli/commands/__init__.py +0 -0
- cli/commands/admin/__init__.py +0 -0
- cli/commands/admin/bootstrap_command.py +118 -0
- cli/commands/admin/credentials/__init__.py +0 -0
- cli/commands/admin/credentials/create/__init__.py +0 -0
- cli/commands/admin/credentials/create/command.py +148 -0
- cli/commands/admin/credentials/create/presenter.py +16 -0
- cli/commands/admin/credentials/grant/__init__.py +0 -0
- cli/commands/admin/credentials/grant/command.py +119 -0
- cli/commands/admin/credentials/grant/fields.py +33 -0
- cli/commands/admin/credentials/grant/presenter.py +23 -0
- cli/commands/agents/__init__.py +0 -0
- cli/commands/agents/create/__init__.py +0 -0
- cli/commands/agents/create/command.py +475 -0
- cli/commands/agents/create/fields.py +64 -0
- cli/commands/agents/create/presenter.py +68 -0
- cli/commands/agents/delete/__init__.py +0 -0
- cli/commands/agents/delete/command.py +47 -0
- cli/commands/agents/delete/presenter.py +16 -0
- cli/commands/agents/get/command.py +37 -0
- cli/commands/agents/get/presenter.py +32 -0
- cli/commands/agents/list/__init__.py +1 -0
- cli/commands/agents/list/command.py +54 -0
- cli/commands/agents/list/presenter.py +82 -0
- cli/commands/agents/update/__init__.py +0 -0
- cli/commands/agents/update/command.py +435 -0
- cli/commands/agents/update/fields.py +40 -0
- cli/commands/agents/update/presenter.py +68 -0
- cli/commands/audio/__init__.py +0 -0
- cli/commands/audio/transcribe/__init__.py +0 -0
- cli/commands/audio/transcribe/command.py +144 -0
- cli/commands/audio/transcribe/presenter.py +15 -0
- cli/commands/auth/__init__.py +0 -0
- cli/commands/auth/login/__init__.py +0 -0
- cli/commands/auth/login/command.py +80 -0
- cli/commands/auth/signup/__init__.py +0 -0
- cli/commands/auth/signup/command.py +115 -0
- cli/commands/billing/__init__.py +1 -0
- cli/commands/billing/costs/__init__.py +1 -0
- cli/commands/billing/costs/by_agent/__init__.py +1 -0
- cli/commands/billing/costs/by_agent/command.py +57 -0
- cli/commands/billing/costs/by_agent/presenter.py +81 -0
- cli/commands/billing/costs/by_model/__init__.py +1 -0
- cli/commands/billing/costs/by_model/command.py +57 -0
- cli/commands/billing/costs/by_model/presenter.py +80 -0
- cli/commands/billing/costs/daily/__init__.py +1 -0
- cli/commands/billing/costs/daily/command.py +55 -0
- cli/commands/billing/costs/daily/presenter.py +75 -0
- cli/commands/billing/costs/summary/__init__.py +1 -0
- cli/commands/billing/costs/summary/command.py +57 -0
- cli/commands/billing/costs/summary/presenter.py +42 -0
- cli/commands/billing/projects/__init__.py +1 -0
- cli/commands/billing/projects/create/__init__.py +1 -0
- cli/commands/billing/projects/create/command.py +60 -0
- cli/commands/billing/projects/create/presenter.py +26 -0
- cli/commands/billing/projects/get/__init__.py +1 -0
- cli/commands/billing/projects/get/command.py +33 -0
- cli/commands/billing/projects/get/presenter.py +32 -0
- cli/commands/billing/projects/list/__init__.py +1 -0
- cli/commands/billing/projects/list/command.py +40 -0
- cli/commands/billing/projects/list/presenter.py +57 -0
- cli/commands/content/__init__.py +1 -0
- cli/commands/content/delete/__init__.py +0 -0
- cli/commands/content/delete/command.py +49 -0
- cli/commands/content/delete/presenter.py +18 -0
- cli/commands/content/edit/__init__.py +1 -0
- cli/commands/content/edit/command.py +155 -0
- cli/commands/content/edit/editor.py +150 -0
- cli/commands/content/edit/presenter.py +146 -0
- cli/commands/content/get/__init__.py +1 -0
- cli/commands/content/get/command.py +39 -0
- cli/commands/content/get/presenter.py +176 -0
- cli/commands/content/list/__init__.py +1 -0
- cli/commands/content/list/command.py +347 -0
- cli/commands/content/list/export_formatters.py +409 -0
- cli/commands/content/list/export_handler.py +165 -0
- cli/commands/content/list/presenter.py +190 -0
- cli/commands/credentials/__init__.py +0 -0
- cli/commands/credentials/create/__init__.py +0 -0
- cli/commands/credentials/create/command.py +165 -0
- cli/commands/credentials/create/fields.py +38 -0
- cli/commands/credentials/create/presenter.py +20 -0
- cli/commands/credentials/update/__init__.py +0 -0
- cli/commands/credentials/update/command.py +53 -0
- cli/commands/credentials/update/fields.py +71 -0
- cli/commands/credentials/update/presenter.py +16 -0
- cli/commands/flag_utils.py +366 -0
- cli/commands/generate/__init__.py +0 -0
- cli/commands/generate/cancel/__init__.py +1 -0
- cli/commands/generate/cancel/command.py +44 -0
- cli/commands/generate/cancel/presenter.py +26 -0
- cli/commands/generate/status/__init__.py +1 -0
- cli/commands/generate/status/command.py +58 -0
- cli/commands/generate/status/presenter.py +78 -0
- cli/commands/generate/text/__init__.py +0 -0
- cli/commands/generate/text/command.py +1325 -0
- cli/commands/generate/text/concurrent_renderer.py +355 -0
- cli/commands/generate/text/presenter.py +287 -0
- cli/commands/generate/text/stream_renderer.py +129 -0
- cli/commands/knowledge/__init__.py +0 -0
- cli/commands/knowledge/collections/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster/command.py +64 -0
- cli/commands/knowledge/collections/cluster/presenter.py +74 -0
- cli/commands/knowledge/collections/cluster_status/__init__.py +0 -0
- cli/commands/knowledge/collections/cluster_status/command.py +46 -0
- cli/commands/knowledge/collections/cluster_status/presenter.py +10 -0
- cli/commands/knowledge/collections/create/__init__.py +0 -0
- cli/commands/knowledge/collections/create/command.py +137 -0
- cli/commands/knowledge/collections/create/presenter.py +38 -0
- cli/commands/knowledge/collections/delete/__init__.py +1 -0
- cli/commands/knowledge/collections/delete/command.py +47 -0
- cli/commands/knowledge/collections/delete/presenter.py +20 -0
- cli/commands/knowledge/collections/get/__init__.py +1 -0
- cli/commands/knowledge/collections/get/command.py +30 -0
- cli/commands/knowledge/collections/get/presenter.py +44 -0
- cli/commands/knowledge/collections/list/__init__.py +1 -0
- cli/commands/knowledge/collections/list/command.py +41 -0
- cli/commands/knowledge/collections/list/presenter.py +68 -0
- cli/commands/knowledge/collections/update/__init__.py +0 -0
- cli/commands/knowledge/collections/update/command.py +97 -0
- cli/commands/knowledge/collections/update/presenter.py +42 -0
- cli/commands/knowledge/documents/__init__.py +0 -0
- cli/commands/knowledge/documents/bulk_metadata/__init__.py +0 -0
- cli/commands/knowledge/documents/bulk_metadata/command.py +119 -0
- cli/commands/knowledge/documents/bulk_metadata/presenter.py +36 -0
- cli/commands/knowledge/documents/delete/__init__.py +0 -0
- cli/commands/knowledge/documents/delete/command.py +47 -0
- cli/commands/knowledge/documents/delete/presenter.py +20 -0
- cli/commands/knowledge/documents/get/__init__.py +0 -0
- cli/commands/knowledge/documents/get/command.py +39 -0
- cli/commands/knowledge/documents/get/presenter.py +78 -0
- cli/commands/knowledge/documents/ingest/__init__.py +0 -0
- cli/commands/knowledge/documents/ingest/command.py +222 -0
- cli/commands/knowledge/documents/ingest/presenter.py +41 -0
- cli/commands/knowledge/documents/list/__init__.py +0 -0
- cli/commands/knowledge/documents/list/command.py +69 -0
- cli/commands/knowledge/documents/list/presenter.py +86 -0
- cli/commands/knowledge/documents/reingest/__init__.py +0 -0
- cli/commands/knowledge/documents/reingest/command.py +102 -0
- cli/commands/knowledge/documents/reingest/presenter.py +70 -0
- cli/commands/knowledge/documents/update/__init__.py +0 -0
- cli/commands/knowledge/documents/update/command.py +85 -0
- cli/commands/knowledge/documents/update/presenter.py +37 -0
- cli/commands/knowledge/recover/__init__.py +0 -0
- cli/commands/knowledge/recover/command.py +46 -0
- cli/commands/knowledge/recover/presenter.py +79 -0
- cli/commands/knowledge/search/__init__.py +0 -0
- cli/commands/knowledge/search/command.py +218 -0
- cli/commands/knowledge/search/presenter.py +111 -0
- cli/commands/knowledge/synthesis/__init__.py +0 -0
- cli/commands/knowledge/synthesis/create/__init__.py +0 -0
- cli/commands/knowledge/synthesis/create/command.py +127 -0
- cli/commands/knowledge/synthesis/create/presenter.py +33 -0
- cli/commands/knowledge/synthesis/delete/__init__.py +0 -0
- cli/commands/knowledge/synthesis/delete/command.py +53 -0
- cli/commands/knowledge/synthesis/delete/presenter.py +31 -0
- cli/commands/knowledge/synthesis/get/__init__.py +0 -0
- cli/commands/knowledge/synthesis/get/command.py +55 -0
- cli/commands/knowledge/synthesis/get/presenter.py +114 -0
- cli/commands/knowledge/synthesis/list/__init__.py +0 -0
- cli/commands/knowledge/synthesis/list/command.py +132 -0
- cli/commands/knowledge/synthesis/list/presenter.py +84 -0
- cli/commands/knowledge/synthesis/refresh/__init__.py +0 -0
- cli/commands/knowledge/synthesis/refresh/command.py +42 -0
- cli/commands/knowledge/synthesis/refresh/presenter.py +33 -0
- cli/commands/knowledge/synthesis/update/__init__.py +0 -0
- cli/commands/knowledge/synthesis/update/command.py +76 -0
- cli/commands/knowledge/synthesis/update/presenter.py +41 -0
- cli/commands/models/__init__.py +0 -0
- cli/commands/models/list/__init__.py +0 -0
- cli/commands/models/list/command.py +84 -0
- cli/commands/models/list/presenter.py +114 -0
- cli/commands/organizations/__init__.py +0 -0
- cli/commands/organizations/create/command.py +32 -0
- cli/commands/organizations/create/presenter.py +9 -0
- cli/commands/pipelines/__init__.py +1 -0
- cli/commands/pipelines/approvals/__init__.py +1 -0
- cli/commands/pipelines/approvals/decide_command.py +77 -0
- cli/commands/pipelines/approvals/get_command.py +44 -0
- cli/commands/pipelines/approvals/presenter.py +56 -0
- cli/commands/pipelines/costs/__init__.py +1 -0
- cli/commands/pipelines/costs/command.py +57 -0
- cli/commands/pipelines/costs/daily_command.py +54 -0
- cli/commands/pipelines/costs/daily_presenter.py +59 -0
- cli/commands/pipelines/costs/presenter.py +37 -0
- cli/commands/pipelines/create/__init__.py +1 -0
- cli/commands/pipelines/create/command.py +103 -0
- cli/commands/pipelines/create/presenter.py +22 -0
- cli/commands/pipelines/env_vars/__init__.py +1 -0
- cli/commands/pipelines/env_vars/command.py +51 -0
- cli/commands/pipelines/env_vars/presenter.py +16 -0
- cli/commands/pipelines/execute/__init__.py +1 -0
- cli/commands/pipelines/execute/command.py +142 -0
- cli/commands/pipelines/execute/presenter.py +47 -0
- cli/commands/pipelines/executions/__init__.py +1 -0
- cli/commands/pipelines/executions/costs/__init__.py +1 -0
- cli/commands/pipelines/executions/costs/command.py +48 -0
- cli/commands/pipelines/executions/costs/presenter.py +29 -0
- cli/commands/pipelines/executions/costs_by_model/__init__.py +1 -0
- cli/commands/pipelines/executions/costs_by_model/command.py +50 -0
- cli/commands/pipelines/executions/costs_by_model/presenter.py +78 -0
- cli/commands/pipelines/executions/costs_by_step/__init__.py +1 -0
- cli/commands/pipelines/executions/costs_by_step/command.py +50 -0
- cli/commands/pipelines/executions/costs_by_step/presenter.py +72 -0
- cli/commands/pipelines/executions/get_command.py +38 -0
- cli/commands/pipelines/executions/list_command.py +123 -0
- cli/commands/pipelines/executions/presenter.py +131 -0
- cli/commands/pipelines/executions/rerun_command.py +41 -0
- cli/commands/pipelines/executions/update/__init__.py +1 -0
- cli/commands/pipelines/executions/update/command.py +110 -0
- cli/commands/pipelines/executions/update/presenter.py +28 -0
- cli/commands/pipelines/get/__init__.py +1 -0
- cli/commands/pipelines/get/command.py +33 -0
- cli/commands/pipelines/get/presenter.py +48 -0
- cli/commands/pipelines/list/__init__.py +1 -0
- cli/commands/pipelines/list/command.py +53 -0
- cli/commands/pipelines/list/presenter.py +66 -0
- cli/commands/pipelines/schedules/__init__.py +1 -0
- cli/commands/pipelines/schedules/create_command.py +119 -0
- cli/commands/pipelines/schedules/create_presenter.py +35 -0
- cli/commands/pipelines/schedules/delete_command.py +52 -0
- cli/commands/pipelines/schedules/env_vars_command.py +59 -0
- cli/commands/pipelines/schedules/env_vars_presenter.py +16 -0
- cli/commands/pipelines/schedules/get_command.py +38 -0
- cli/commands/pipelines/schedules/list_command.py +33 -0
- cli/commands/pipelines/schedules/once_command.py +90 -0
- cli/commands/pipelines/schedules/once_presenter.py +30 -0
- cli/commands/pipelines/schedules/presenter.py +104 -0
- cli/commands/pipelines/schedules/update_command.py +139 -0
- cli/commands/pipelines/schedules/update_presenter.py +29 -0
- cli/commands/render/__init__.py +0 -0
- cli/commands/render/html_to_image/__init__.py +0 -0
- cli/commands/render/html_to_image/command.py +170 -0
- cli/commands/schemas/__init__.py +0 -0
- cli/commands/schemas/create/__init__.py +0 -0
- cli/commands/schemas/create/command.py +122 -0
- cli/commands/schemas/create/presenter.py +53 -0
- cli/commands/schemas/delete/command.py +45 -0
- cli/commands/schemas/delete/presenter.py +9 -0
- cli/commands/schemas/get/__init__.py +0 -0
- cli/commands/schemas/get/command.py +56 -0
- cli/commands/schemas/get/presenter.py +129 -0
- cli/commands/schemas/list/__init__.py +0 -0
- cli/commands/schemas/list/command.py +64 -0
- cli/commands/schemas/list/presenter.py +133 -0
- cli/commands/schemas/update/__init__.py +0 -0
- cli/commands/schemas/update/command.py +369 -0
- cli/commands/schemas/update/presenter.py +53 -0
- cli/commands/sessions/__init__.py +1 -0
- cli/commands/sessions/delete/__init__.py +1 -0
- cli/commands/sessions/delete/command.py +47 -0
- cli/commands/sessions/delete/presenter.py +10 -0
- cli/commands/sessions/get/__init__.py +1 -0
- cli/commands/sessions/get/command.py +42 -0
- cli/commands/sessions/get/presenter.py +59 -0
- cli/commands/sessions/list/__init__.py +1 -0
- cli/commands/sessions/list/command.py +61 -0
- cli/commands/sessions/list/presenter.py +68 -0
- cli/commands/sessions/messages/__init__.py +1 -0
- cli/commands/sessions/messages/command.py +78 -0
- cli/commands/sessions/messages/presenter.py +79 -0
- cli/commands/shared_flags.py +500 -0
- cli/commands/sync/__init__.py +0 -0
- cli/commands/sync/command.py +45 -0
- cli/commands/sync/presenter.py +49 -0
- cli/commands/tags/__init__.py +1 -0
- cli/commands/tags/create/__init__.py +1 -0
- cli/commands/tags/create/command.py +60 -0
- cli/commands/tags/delete/__init__.py +1 -0
- cli/commands/tags/delete/command.py +47 -0
- cli/commands/tags/delete/presenter.py +10 -0
- cli/commands/tags/get/command.py +31 -0
- cli/commands/tags/get/presenter.py +23 -0
- cli/commands/tags/list/__init__.py +1 -0
- cli/commands/tags/list/command.py +52 -0
- cli/commands/tags/list/presenter.py +49 -0
- cli/commands/tags/update/command.py +64 -0
- cli/commands/tags/update/presenter.py +9 -0
- cli/commands/templates/__init__.py +0 -0
- cli/commands/templates/create/__init__.py +0 -0
- cli/commands/templates/create/command.py +152 -0
- cli/commands/templates/create/presenter.py +86 -0
- cli/commands/templates/delete/__init__.py +0 -0
- cli/commands/templates/delete/command.py +47 -0
- cli/commands/templates/delete/presenter.py +16 -0
- cli/commands/templates/get/__init__.py +0 -0
- cli/commands/templates/get/command.py +52 -0
- cli/commands/templates/get/presenter.py +233 -0
- cli/commands/templates/get_by_version/command.py +32 -0
- cli/commands/templates/get_by_version/presenter.py +30 -0
- cli/commands/templates/list/__init__.py +1 -0
- cli/commands/templates/list/command.py +102 -0
- cli/commands/templates/list/presenter.py +93 -0
- cli/commands/templates/render/__init__.py +0 -0
- cli/commands/templates/render/command.py +115 -0
- cli/commands/templates/render/presenter.py +276 -0
- cli/commands/templates/update/__init__.py +0 -0
- cli/commands/templates/update/command.py +199 -0
- cli/commands/templates/update/presenter.py +94 -0
- cli/commands/templates/version/__init__.py +1 -0
- cli/commands/templates/version/command.py +116 -0
- cli/commands/templates/version/presenter.py +100 -0
- cli/commands/tool_configs/__init__.py +0 -0
- cli/commands/tool_configs/create/__init__.py +0 -0
- cli/commands/tool_configs/create/command.py +118 -0
- cli/commands/tool_configs/create/presenter.py +53 -0
- cli/commands/tool_configs/delete/__init__.py +0 -0
- cli/commands/tool_configs/delete/command.py +47 -0
- cli/commands/tool_configs/delete/presenter.py +18 -0
- cli/commands/tool_configs/get/__init__.py +0 -0
- cli/commands/tool_configs/get/command.py +31 -0
- cli/commands/tool_configs/get/presenter.py +62 -0
- cli/commands/tool_configs/list/__init__.py +0 -0
- cli/commands/tool_configs/list/command.py +59 -0
- cli/commands/tool_configs/list/presenter.py +60 -0
- cli/commands/tool_configs/update/__init__.py +0 -0
- cli/commands/tool_configs/update/command.py +128 -0
- cli/commands/tool_configs/update/presenter.py +53 -0
- cli/commands/tools/__init__.py +1 -0
- cli/commands/tools/get/__init__.py +1 -0
- cli/commands/tools/get/command.py +42 -0
- cli/commands/tools/get/presenter.py +45 -0
- cli/commands/tools/list/__init__.py +1 -0
- cli/commands/tools/list/command.py +56 -0
- cli/commands/tools/list/presenter.py +44 -0
- cli/commands/users/__init__.py +0 -0
- cli/commands/users/create/command.py +53 -0
- cli/commands/users/create/presenter.py +9 -0
- cli/commands/whoami/__init__.py +0 -0
- cli/commands/whoami/command.py +42 -0
- cli/infrastructure/__init__.py +0 -0
- cli/infrastructure/auth_storage.py +71 -0
- cli/infrastructure/client_factory.py +36 -0
- cli/infrastructure/command.py +75 -0
- cli/infrastructure/config.py +188 -0
- cli/infrastructure/console.py +27 -0
- cli/infrastructure/editor.py +138 -0
- cli/infrastructure/error_display.py +178 -0
- cli/infrastructure/field_extractor.py +360 -0
- cli/infrastructure/file_content.py +210 -0
- cli/infrastructure/filter_parser.py +256 -0
- cli/infrastructure/formatters/__init__.py +0 -0
- cli/infrastructure/formatters/base.py +99 -0
- cli/infrastructure/formatters/compact_formatter.py +245 -0
- cli/infrastructure/formatters/json_formatter.py +84 -0
- cli/infrastructure/formatters/lines_formatter.py +102 -0
- cli/infrastructure/formatting/__init__.py +0 -0
- cli/infrastructure/formatting/fields.py +193 -0
- cli/infrastructure/forms/__init__.py +0 -0
- cli/infrastructure/forms/agent_picker.py +123 -0
- cli/infrastructure/forms/agent_tool_editor.py +384 -0
- cli/infrastructure/forms/agent_tools_manager.py +212 -0
- cli/infrastructure/forms/base_picker.py +469 -0
- cli/infrastructure/forms/components.py +126 -0
- cli/infrastructure/forms/json_schema_builder.py +149 -0
- cli/infrastructure/forms/model_picker.py +134 -0
- cli/infrastructure/forms/parsers.py +173 -0
- cli/infrastructure/forms/resolution_modal.py +302 -0
- cli/infrastructure/forms/schema_picker.py +137 -0
- cli/infrastructure/forms/tag_management_modal.py +103 -0
- cli/infrastructure/forms/tag_picker.py +207 -0
- cli/infrastructure/forms/template_picker.py +131 -0
- cli/infrastructure/forms/tool_config_picker.py +130 -0
- cli/infrastructure/forms/tool_picker.py +103 -0
- cli/infrastructure/injection/__init__.py +0 -0
- cli/infrastructure/injection/parser.py +302 -0
- cli/infrastructure/injection/resolver.py +399 -0
- cli/infrastructure/kv_parser.py +130 -0
- cli/infrastructure/local_storage.py +227 -0
- cli/infrastructure/macro_parser.py +215 -0
- cli/infrastructure/output.py +192 -0
- cli/infrastructure/provider_setup.py +81 -0
- cli/infrastructure/renderers/__init__.py +0 -0
- cli/infrastructure/renderers/entity_renderer.py +77 -0
- cli/infrastructure/renderers/list_renderer.py +114 -0
- cli/infrastructure/scope_utils.py +47 -0
- cli/infrastructure/spinner.py +101 -0
- cli/infrastructure/tui/__init__.py +0 -0
- cli/infrastructure/tui/clipboard.py +41 -0
- cli/infrastructure/tui/formatters.py +105 -0
- cli/infrastructure/tui/preview.py +14 -0
- cli/infrastructure/tui/selectable.py +198 -0
- cli/infrastructure/validation/__init__.py +0 -0
- cli/infrastructure/validation/tag_validation.py +74 -0
- cli/main.py +759 -0
- cli/tui/__init__.py +0 -0
- cli/tui/app.py +199 -0
- cli/tui/app_store.py +73 -0
- cli/tui/chat/__init__.py +0 -0
- cli/tui/chat/commands/__init__.py +0 -0
- cli/tui/chat/commands/base.py +65 -0
- cli/tui/chat/commands/create_session.py +135 -0
- cli/tui/chat/commands/load_session.py +119 -0
- cli/tui/chat/commands/regenerate.py +120 -0
- cli/tui/chat/commands/reload_session.py +63 -0
- cli/tui/chat/commands/send_message.py +190 -0
- cli/tui/chat/commands/undo.py +66 -0
- cli/tui/chat/editor.py +71 -0
- cli/tui/chat/messages.py +223 -0
- cli/tui/chat/pane.py +141 -0
- cli/tui/chat/renderers/__init__.py +0 -0
- cli/tui/chat/renderers/base.py +72 -0
- cli/tui/chat/renderers/markdown.py +250 -0
- cli/tui/chat/renderers/plain.py +83 -0
- cli/tui/chat/screen.py +1155 -0
- cli/tui/chat/services/__init__.py +0 -0
- cli/tui/chat/services/injection.py +386 -0
- cli/tui/chat/services/name_generator.py +256 -0
- cli/tui/chat/slash_commands.py +424 -0
- cli/tui/chat/store.py +280 -0
- cli/tui/chat/types.py +220 -0
- cli/tui/chat/widgets/__init__.py +0 -0
- cli/tui/chat/widgets/chat_header.py +75 -0
- cli/tui/chat/widgets/chat_input.py +362 -0
- cli/tui/chat/widgets/injection_popup.py +161 -0
- cli/tui/chat/widgets/message_display.py +287 -0
- cli/tui/chat/widgets/session_sidebar.py +214 -0
- cli/tui/chat/widgets/welcome_screen.py +290 -0
- cli/tui/screens/__init__.py +0 -0
- cli/tui/screens/agents.py +344 -0
- cli/tui/screens/base.py +301 -0
- cli/tui/screens/content.py +508 -0
- cli/tui/screens/dashboard.py +89 -0
- cli/tui/screens/models.py +96 -0
- cli/tui/screens/nav_screen.py +186 -0
- cli/tui/screens/schemas.py +522 -0
- cli/tui/screens/templates.py +734 -0
- cli/tui/screens/tool_configs.py +335 -0
- cli/tui/styles/__init__.py +0 -0
- cli/tui/widgets/__init__.py +0 -0
- cli/tui/widgets/agent_create_modal.py +139 -0
- cli/tui/widgets/agent_form_modal.py +659 -0
- cli/tui/widgets/agent_update_modal.py +299 -0
- cli/tui/widgets/base_form_modal.py +77 -0
- cli/tui/widgets/confirm_modal.py +75 -0
- cli/tui/widgets/help_modal.py +145 -0
- cli/tui/widgets/new_session_modal.py +328 -0
- cli/tui/widgets/schema_create_modal.py +271 -0
- cli/tui/widgets/schema_update_modal.py +188 -0
- cli/tui/widgets/status_footer.py +147 -0
- cli/tui/widgets/template_create_modal.py +502 -0
- cli/tui/widgets/template_update_modal.py +308 -0
- cli/tui/widgets/tool_config_create_modal.py +216 -0
- cli/tui/widgets/tool_config_update_modal.py +208 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Tool config update command implementation."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, Optional, cast
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from cli.commands.flag_utils import require_update_flags
|
|
9
|
+
from cli.commands.tool_configs.update.presenter import (
|
|
10
|
+
present_tool_config_update_success,
|
|
11
|
+
)
|
|
12
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
13
|
+
from cli.infrastructure.file_content import FileContentError, resolve_content
|
|
14
|
+
from alloy_runtime_types.dtos.tool_configs import UpdateToolConfigRequest
|
|
15
|
+
from alloy_runtime_sdk.exceptions.errors import NotFoundError
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def tool_configs_update_command(
|
|
19
|
+
identifier: str = typer.Argument(
|
|
20
|
+
...,
|
|
21
|
+
help="Tool config UUID or slug",
|
|
22
|
+
),
|
|
23
|
+
name: Optional[str] = typer.Option(
|
|
24
|
+
None,
|
|
25
|
+
"-n",
|
|
26
|
+
"--name",
|
|
27
|
+
help="New name (will regenerate slug)",
|
|
28
|
+
),
|
|
29
|
+
config: Optional[str] = typer.Option(
|
|
30
|
+
None,
|
|
31
|
+
"-c",
|
|
32
|
+
"--config",
|
|
33
|
+
help="New configuration as JSON (or @file.json)",
|
|
34
|
+
),
|
|
35
|
+
description: Optional[str] = typer.Option(
|
|
36
|
+
None,
|
|
37
|
+
"-d",
|
|
38
|
+
"--description",
|
|
39
|
+
help="New description",
|
|
40
|
+
),
|
|
41
|
+
clear_description: bool = typer.Option(
|
|
42
|
+
False,
|
|
43
|
+
"--clear-description",
|
|
44
|
+
help="Clear the description",
|
|
45
|
+
),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Update an existing tool config.
|
|
48
|
+
|
|
49
|
+
Only specified fields are updated; others are preserved.
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
ai tool-configs update my-config -n "New Name"
|
|
53
|
+
ai tool-configs update my-config -c '{"top_k": 20}'
|
|
54
|
+
ai tool-configs update my-config -d "Updated description"
|
|
55
|
+
ai tc update my-config --clear-description
|
|
56
|
+
"""
|
|
57
|
+
# Check at least one update flag provided
|
|
58
|
+
require_update_flags(
|
|
59
|
+
("--name", name),
|
|
60
|
+
("--config", config),
|
|
61
|
+
("--description", description),
|
|
62
|
+
("--clear-description", clear_description),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
_execute_update(
|
|
66
|
+
identifier=identifier,
|
|
67
|
+
name=name,
|
|
68
|
+
config=config,
|
|
69
|
+
description=description,
|
|
70
|
+
clear_description=clear_description,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@async_command
|
|
75
|
+
async def _execute_update(
|
|
76
|
+
identifier: str,
|
|
77
|
+
name: Optional[str],
|
|
78
|
+
config: Optional[str],
|
|
79
|
+
description: Optional[str],
|
|
80
|
+
clear_description: bool,
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Execute the tool config update operation."""
|
|
83
|
+
# Build update request dict
|
|
84
|
+
request_data: dict[str, Any] = {}
|
|
85
|
+
|
|
86
|
+
if name is not None:
|
|
87
|
+
request_data["name"] = name
|
|
88
|
+
|
|
89
|
+
if config is not None:
|
|
90
|
+
# Resolve @file reference for config
|
|
91
|
+
try:
|
|
92
|
+
config_content = resolve_content(config)
|
|
93
|
+
except FileContentError as e:
|
|
94
|
+
raise typer.BadParameter(str(e))
|
|
95
|
+
|
|
96
|
+
if not config_content:
|
|
97
|
+
raise typer.BadParameter("Config cannot be empty")
|
|
98
|
+
|
|
99
|
+
# Parse config as JSON
|
|
100
|
+
try:
|
|
101
|
+
config_dict_raw = json.loads(config_content)
|
|
102
|
+
except json.JSONDecodeError as e:
|
|
103
|
+
raise typer.BadParameter(f"Invalid JSON in config: {e}")
|
|
104
|
+
|
|
105
|
+
if not isinstance(config_dict_raw, dict):
|
|
106
|
+
raise typer.BadParameter("Config must be a JSON object")
|
|
107
|
+
|
|
108
|
+
request_data["config"] = cast(dict[str, Any], config_dict_raw)
|
|
109
|
+
|
|
110
|
+
if description is not None:
|
|
111
|
+
request_data["description"] = description
|
|
112
|
+
elif clear_description:
|
|
113
|
+
request_data["description"] = ""
|
|
114
|
+
|
|
115
|
+
request = UpdateToolConfigRequest(**request_data)
|
|
116
|
+
|
|
117
|
+
async with authenticated_client() as (_, client):
|
|
118
|
+
try:
|
|
119
|
+
# Try to get the tool config first to verify it exists
|
|
120
|
+
await client.get_tool_config(identifier)
|
|
121
|
+
except NotFoundError:
|
|
122
|
+
raise typer.BadParameter(
|
|
123
|
+
f"Tool config '{identifier}' not found. Use 'ai tool-configs list' to see available configs."
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
response = await client.update_tool_config(identifier, request)
|
|
127
|
+
|
|
128
|
+
present_tool_config_update_success(response)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Presenter for tool config update command output."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from rich.panel import Panel
|
|
6
|
+
from rich.syntax import Syntax
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from cli.infrastructure.formatting.fields import (
|
|
10
|
+
format_optional,
|
|
11
|
+
format_uuid,
|
|
12
|
+
)
|
|
13
|
+
from cli.infrastructure.output import OutputService
|
|
14
|
+
from alloy_runtime_types.dtos.tool_configs import UpdateToolConfigResponse
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def present_tool_config_update_success(response: UpdateToolConfigResponse) -> None:
|
|
18
|
+
"""Present successful tool config update.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
response: Tool config update response from server
|
|
22
|
+
"""
|
|
23
|
+
output = OutputService.get()
|
|
24
|
+
|
|
25
|
+
output.success("Tool config updated successfully")
|
|
26
|
+
|
|
27
|
+
# Build a simple table for entity display
|
|
28
|
+
table = Table(show_header=False, box=None, padding=(0, 1))
|
|
29
|
+
table.add_column("Field", style="dim")
|
|
30
|
+
table.add_column("Value")
|
|
31
|
+
|
|
32
|
+
table.add_row("ID", format_uuid(response.id, short=False))
|
|
33
|
+
table.add_row("Slug", response.slug)
|
|
34
|
+
table.add_row("Name", response.name)
|
|
35
|
+
table.add_row("Tool ID", response.tool_id)
|
|
36
|
+
table.add_row("Description", format_optional(response.description))
|
|
37
|
+
|
|
38
|
+
# Format ownership
|
|
39
|
+
if response.user_id:
|
|
40
|
+
table.add_row("Scope", "User")
|
|
41
|
+
elif response.organization_id:
|
|
42
|
+
table.add_row("Scope", "Organization")
|
|
43
|
+
else:
|
|
44
|
+
table.add_row("Scope", "Global")
|
|
45
|
+
|
|
46
|
+
panel = Panel(table, title=f"Tool Config: {response.name}", border_style="green")
|
|
47
|
+
output.console.print(panel)
|
|
48
|
+
|
|
49
|
+
# Display config as syntax-highlighted JSON
|
|
50
|
+
config_json = json.dumps(response.config, indent=2)
|
|
51
|
+
syntax = Syntax(config_json, "json", theme="monokai", word_wrap=True)
|
|
52
|
+
config_panel = Panel(syntax, title="Configuration", border_style="blue")
|
|
53
|
+
output.console.print(config_panel)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Tools get command implementation."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from cli.commands.tools.get.presenter import present_tool_details
|
|
6
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def tools_get_command(
|
|
10
|
+
tool_id: str = typer.Argument(
|
|
11
|
+
...,
|
|
12
|
+
help="Tool identifier (e.g., 'rag_search', 'web_search')",
|
|
13
|
+
),
|
|
14
|
+
) -> None:
|
|
15
|
+
"""Get details of a single tool.
|
|
16
|
+
|
|
17
|
+
Retrieves the full tool definition including the parameter_schema
|
|
18
|
+
which defines what configuration options the tool accepts.
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
ai tools get rag_search
|
|
22
|
+
ai tools get web_search
|
|
23
|
+
"""
|
|
24
|
+
_execute_get(tool_id=tool_id)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@async_command
|
|
28
|
+
async def _execute_get(tool_id: str) -> None:
|
|
29
|
+
"""Execute get tool operation.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
tool_id: Tool identifier string
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
NotFoundError: If tool not found
|
|
36
|
+
AuthenticationError: If API key is invalid
|
|
37
|
+
ServerError: If server returns 5xx error
|
|
38
|
+
"""
|
|
39
|
+
async with authenticated_client() as (_config, client):
|
|
40
|
+
response = await client.get_tool(tool_id)
|
|
41
|
+
|
|
42
|
+
present_tool_details(response)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Presenter for tools get command output."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from alloy_runtime_types.dtos.tools import ToolResponse
|
|
8
|
+
|
|
9
|
+
from cli.infrastructure.output import OutputService
|
|
10
|
+
from cli.infrastructure.renderers.entity_renderer import FieldConfig
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _format_parameter_schema(schema: dict[str, Any] | None) -> str:
|
|
14
|
+
"""Format parameter_schema as pretty-printed JSON.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
schema: Parameter schema dict or None
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Formatted JSON string, or '-' if no schema
|
|
21
|
+
"""
|
|
22
|
+
if not schema:
|
|
23
|
+
return "None (no configurable parameters)"
|
|
24
|
+
return json.dumps(schema, indent=2, ensure_ascii=False)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def present_tool_details(response: ToolResponse) -> None:
|
|
28
|
+
"""Present tool details including parameter schema.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
response: ToolResponse from server
|
|
32
|
+
"""
|
|
33
|
+
output = OutputService.get()
|
|
34
|
+
|
|
35
|
+
fields = [
|
|
36
|
+
FieldConfig("id", "ID"),
|
|
37
|
+
FieldConfig("description", "Description"),
|
|
38
|
+
FieldConfig(
|
|
39
|
+
"parameter_schema",
|
|
40
|
+
"Parameter Schema",
|
|
41
|
+
_format_parameter_schema,
|
|
42
|
+
),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
output.entity(response, f"Tool: {response.id}", fields)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Empty per project convention - import directly from submodules
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Tools list command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from cli.commands.tools.list.presenter import present_tools_list
|
|
8
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def tools_list_command(
|
|
12
|
+
search: Optional[str] = typer.Option(
|
|
13
|
+
None,
|
|
14
|
+
"-s",
|
|
15
|
+
"--search",
|
|
16
|
+
help="Fuzzy search terms",
|
|
17
|
+
),
|
|
18
|
+
limit: int = typer.Option(
|
|
19
|
+
50,
|
|
20
|
+
"-l",
|
|
21
|
+
"--limit",
|
|
22
|
+
min=1,
|
|
23
|
+
max=100,
|
|
24
|
+
help="Max results",
|
|
25
|
+
),
|
|
26
|
+
offset: int = typer.Option(
|
|
27
|
+
0,
|
|
28
|
+
"--offset",
|
|
29
|
+
min=0,
|
|
30
|
+
help="Skip N results",
|
|
31
|
+
),
|
|
32
|
+
) -> None:
|
|
33
|
+
"""List available tools in the registry.
|
|
34
|
+
|
|
35
|
+
Shows all tools that can be configured on agents, including
|
|
36
|
+
their identifiers and descriptions.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
ai tools list
|
|
40
|
+
ai tools list -s "search"
|
|
41
|
+
ai tools list -l 10 --offset 20
|
|
42
|
+
"""
|
|
43
|
+
_execute_list(search=search, limit=limit, offset=offset)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@async_command
|
|
47
|
+
async def _execute_list(search: Optional[str], limit: int, offset: int) -> None:
|
|
48
|
+
"""Execute list tools operation."""
|
|
49
|
+
async with authenticated_client() as (_config, client):
|
|
50
|
+
response = await client.list_tools(
|
|
51
|
+
search=search,
|
|
52
|
+
limit=limit,
|
|
53
|
+
offset=offset,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
present_tools_list(response)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Presenter for tools list command output."""
|
|
2
|
+
|
|
3
|
+
from alloy_runtime_types.dtos.tools import ListToolsResponse
|
|
4
|
+
|
|
5
|
+
from cli.infrastructure.output import OutputService
|
|
6
|
+
from cli.infrastructure.renderers.list_renderer import ColumnConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def present_tools_list(response: ListToolsResponse) -> None:
|
|
10
|
+
"""Present list of tools with Rich table formatting."""
|
|
11
|
+
output = OutputService.get()
|
|
12
|
+
|
|
13
|
+
if not response.tools:
|
|
14
|
+
output.info("No tools found")
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
columns = [
|
|
18
|
+
ColumnConfig(
|
|
19
|
+
source_field="id",
|
|
20
|
+
header_label="ID",
|
|
21
|
+
compact_line=1,
|
|
22
|
+
compact_style="cyan",
|
|
23
|
+
),
|
|
24
|
+
ColumnConfig(
|
|
25
|
+
source_field="description",
|
|
26
|
+
header_label="Description",
|
|
27
|
+
formatter=lambda x: x[:80] + "..." if x and len(x) > 80 else (x or "-"),
|
|
28
|
+
compact_line=2,
|
|
29
|
+
compact_style="dim",
|
|
30
|
+
),
|
|
31
|
+
ColumnConfig(
|
|
32
|
+
source_field="parameter_schema",
|
|
33
|
+
header_label="Has Parameters",
|
|
34
|
+
formatter=lambda x: "Yes" if x else "No",
|
|
35
|
+
compact_line=1,
|
|
36
|
+
compact_style="green",
|
|
37
|
+
),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
output.table(
|
|
41
|
+
items=response.tools, # type: ignore[arg-type]
|
|
42
|
+
title=f"Tools ({response.total})",
|
|
43
|
+
columns=columns,
|
|
44
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Users create command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from cli.commands.users.create.presenter import present_create_result
|
|
8
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
9
|
+
from alloy_runtime_types.dtos.users import CreateUserRequest
|
|
10
|
+
from alloy_runtime_types.enums.member_role import MemberRole
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def users_create_command(
|
|
14
|
+
email: str = typer.Option(
|
|
15
|
+
...,
|
|
16
|
+
"-e",
|
|
17
|
+
"--email",
|
|
18
|
+
help="User email address",
|
|
19
|
+
),
|
|
20
|
+
name: str = typer.Option(
|
|
21
|
+
...,
|
|
22
|
+
"-n",
|
|
23
|
+
"--name",
|
|
24
|
+
help="User display name",
|
|
25
|
+
),
|
|
26
|
+
role: Optional[str] = typer.Option(
|
|
27
|
+
None,
|
|
28
|
+
"-r",
|
|
29
|
+
"--role",
|
|
30
|
+
help="User role (member, admin, owner). Defaults to member",
|
|
31
|
+
),
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Create a new user.
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
ai users create --email user@example.com --name "John Doe"
|
|
37
|
+
ai users create -e admin@example.com -n "Admin User" -r admin
|
|
38
|
+
"""
|
|
39
|
+
role_enum = MemberRole(role.lower()) if role else MemberRole.MEMBER
|
|
40
|
+
_execute_create(email=email, name=name, role=role_enum)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@async_command
|
|
44
|
+
async def _execute_create(
|
|
45
|
+
email: str,
|
|
46
|
+
name: str,
|
|
47
|
+
role: MemberRole,
|
|
48
|
+
) -> None:
|
|
49
|
+
request = CreateUserRequest(email=email, name=name, role_id=role)
|
|
50
|
+
async with authenticated_client() as (_config, client):
|
|
51
|
+
response = await client.create_user(request)
|
|
52
|
+
|
|
53
|
+
present_create_result(response)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Presenter for users create command output."""
|
|
2
|
+
|
|
3
|
+
from cli.infrastructure.output import OutputService
|
|
4
|
+
from alloy_runtime_types.dtos.users import CreateUserResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def present_create_result(response: CreateUserResponse) -> None:
|
|
8
|
+
output = OutputService.get()
|
|
9
|
+
output.success(f"Created user: {response.email}")
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Whoami command implementation."""
|
|
2
|
+
|
|
3
|
+
from cli.infrastructure.command import async_command
|
|
4
|
+
from cli.infrastructure.config import load_config
|
|
5
|
+
from cli.infrastructure.console import get_console
|
|
6
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def whoami_command() -> None:
|
|
10
|
+
"""Show current authenticated user information.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
|
|
14
|
+
ai whoami
|
|
15
|
+
"""
|
|
16
|
+
_execute_whoami()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@async_command
|
|
20
|
+
async def _execute_whoami() -> None:
|
|
21
|
+
"""Execute the whoami operation."""
|
|
22
|
+
console = get_console()
|
|
23
|
+
config = load_config()
|
|
24
|
+
|
|
25
|
+
async with ApiClient(base_url=config.api_url, api_key=config.api_key) as client:
|
|
26
|
+
me = await client.get_me()
|
|
27
|
+
|
|
28
|
+
# Print user info
|
|
29
|
+
console.print(f"[cyan]Email:[/cyan] {me.email}")
|
|
30
|
+
console.print(f"[cyan]Name:[/cyan] {me.name}")
|
|
31
|
+
console.print(f"[cyan]User ID:[/cyan] {me.user_id}")
|
|
32
|
+
|
|
33
|
+
if me.organization_id:
|
|
34
|
+
console.print(
|
|
35
|
+
f"[cyan]Organization:[/cyan] {me.organization_name or me.organization_id}"
|
|
36
|
+
)
|
|
37
|
+
console.print(f"[cyan]Organization ID:[/cyan] {me.organization_id}")
|
|
38
|
+
else:
|
|
39
|
+
console.print("[dim]No organization[/dim]")
|
|
40
|
+
|
|
41
|
+
if me.is_system_admin:
|
|
42
|
+
console.print("[yellow]System Administrator[/yellow]")
|
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""CLI authentication storage for API keys and credentials.
|
|
2
|
+
|
|
3
|
+
Stores API key and URL in ~/.alloy-runtime/config file for persistent authentication.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
CONFIG_DIR = Path.home() / ".alloy-runtime"
|
|
11
|
+
CONFIG_FILE = CONFIG_DIR / "config"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def save_credentials(api_url: str, api_key: str) -> None:
|
|
15
|
+
"""Save API credentials to config file.
|
|
16
|
+
|
|
17
|
+
Creates ~/.alloy-runtime/config with API URL and key.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
api_url: API server base URL (e.g., http://localhost:8000)
|
|
21
|
+
api_key: API authentication key
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
save_credentials("http://localhost:8000", "sk_live_abc123...")
|
|
25
|
+
"""
|
|
26
|
+
CONFIG_DIR.mkdir(exist_ok=True, mode=0o700) # Secure directory permissions
|
|
27
|
+
|
|
28
|
+
with open(CONFIG_FILE, "w") as f:
|
|
29
|
+
f.write(f"ALLOY_RUNTIME_API_URL={api_url}\n")
|
|
30
|
+
f.write(f"ALLOY_RUNTIME_API_KEY={api_key}\n")
|
|
31
|
+
|
|
32
|
+
# Set secure file permissions (owner read/write only)
|
|
33
|
+
os.chmod(CONFIG_FILE, 0o600)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def load_credentials() -> tuple[str, str] | None:
|
|
37
|
+
"""Load API credentials from config file.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Tuple of (api_url, api_key) if config exists, None otherwise
|
|
41
|
+
|
|
42
|
+
Example:
|
|
43
|
+
creds = load_credentials()
|
|
44
|
+
if creds:
|
|
45
|
+
api_url, api_key = creds
|
|
46
|
+
"""
|
|
47
|
+
if not CONFIG_FILE.exists():
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
config: dict[str, str] = {}
|
|
51
|
+
with open(CONFIG_FILE, encoding="utf-8") as f:
|
|
52
|
+
for line in f:
|
|
53
|
+
line = line.strip()
|
|
54
|
+
if not line or "=" not in line:
|
|
55
|
+
continue
|
|
56
|
+
key, value = line.split("=", 1)
|
|
57
|
+
config[key] = value
|
|
58
|
+
|
|
59
|
+
if "ALLOY_RUNTIME_API_URL" in config and "ALLOY_RUNTIME_API_KEY" in config:
|
|
60
|
+
return config["ALLOY_RUNTIME_API_URL"], config["ALLOY_RUNTIME_API_KEY"]
|
|
61
|
+
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def clear_credentials() -> None:
|
|
66
|
+
"""Remove stored credentials (logout).
|
|
67
|
+
|
|
68
|
+
Deletes the config file if it exists.
|
|
69
|
+
"""
|
|
70
|
+
if CONFIG_FILE.exists():
|
|
71
|
+
CONFIG_FILE.unlink()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Factory for creating configured ApiClient instances."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import AsyncIterator
|
|
4
|
+
from contextlib import asynccontextmanager
|
|
5
|
+
|
|
6
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
7
|
+
|
|
8
|
+
from cli.infrastructure.config import CLIConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@asynccontextmanager
|
|
12
|
+
async def create_client(config: CLIConfig) -> AsyncIterator[ApiClient]:
|
|
13
|
+
"""Create a configured ApiClient instance.
|
|
14
|
+
|
|
15
|
+
This factory encapsulates the ApiClient creation and configuration,
|
|
16
|
+
ensuring proper async context management and resource cleanup.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
config: Validated CLI configuration
|
|
20
|
+
|
|
21
|
+
Yields:
|
|
22
|
+
Configured ApiClient ready for API calls
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
```python
|
|
26
|
+
config = load_config()
|
|
27
|
+
async with create_client(config) as client:
|
|
28
|
+
response = await client.update_system_credential(...)
|
|
29
|
+
```
|
|
30
|
+
"""
|
|
31
|
+
async with ApiClient(
|
|
32
|
+
base_url=config.api_url,
|
|
33
|
+
api_key=config.api_key,
|
|
34
|
+
timeout=config.timeout,
|
|
35
|
+
) as client:
|
|
36
|
+
yield client
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Command infrastructure for consistent error handling and setup."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from collections.abc import AsyncGenerator, Coroutine
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
from functools import wraps
|
|
7
|
+
from typing import Any, Callable, ParamSpec
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
from cli.infrastructure.client_factory import create_client
|
|
12
|
+
from cli.infrastructure.config import CLIConfig, load_config
|
|
13
|
+
from cli.infrastructure.error_display import display_error
|
|
14
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
15
|
+
|
|
16
|
+
P = ParamSpec("P")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def async_command(func: Callable[P, Coroutine[Any, Any, None]]) -> Callable[P, None]:
|
|
20
|
+
"""Decorator for async CLI commands with standard error handling.
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
@async_command
|
|
24
|
+
async def my_command(arg: str) -> None:
|
|
25
|
+
async with authenticated_client() as (config, client):
|
|
26
|
+
response = await client.some_method(arg)
|
|
27
|
+
|
|
28
|
+
The decorator handles:
|
|
29
|
+
- asyncio.run() wrapper
|
|
30
|
+
- Exception catching and display_error()
|
|
31
|
+
- typer.Exit(code=1) on failure
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
func: Async command function to wrap
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Wrapped sync function suitable for Typer command
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@wraps(func)
|
|
41
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> None:
|
|
42
|
+
try:
|
|
43
|
+
asyncio.run(func(*args, **kwargs))
|
|
44
|
+
except (BlockingIOError, BrokenPipeError):
|
|
45
|
+
# Pipe closed or blocked - exit silently
|
|
46
|
+
# This happens when piping to programs like vim that don't immediately consume stdin
|
|
47
|
+
raise typer.Exit(code=0)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
display_error(e)
|
|
50
|
+
raise typer.Exit(code=1)
|
|
51
|
+
|
|
52
|
+
return wrapper
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@asynccontextmanager
|
|
56
|
+
async def authenticated_client() -> AsyncGenerator[tuple[CLIConfig, ApiClient], None]:
|
|
57
|
+
"""Context manager for authenticated API operations.
|
|
58
|
+
|
|
59
|
+
Usage:
|
|
60
|
+
async with authenticated_client() as (config, client):
|
|
61
|
+
response = await client.some_method()
|
|
62
|
+
|
|
63
|
+
Handles:
|
|
64
|
+
- Configuration loading (raises ConfigurationError if missing)
|
|
65
|
+
- Client lifecycle management
|
|
66
|
+
|
|
67
|
+
Yields:
|
|
68
|
+
Tuple of (CLIConfig, ApiClient) for the operation
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
ConfigurationError: If required configuration is missing
|
|
72
|
+
"""
|
|
73
|
+
config = load_config()
|
|
74
|
+
async with create_client(config) as client:
|
|
75
|
+
yield config, client
|