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,192 @@
|
|
|
1
|
+
"""Unified output service for CLI presentation.
|
|
2
|
+
|
|
3
|
+
This module provides format-aware output that can switch between
|
|
4
|
+
Rich terminal output and JSON for scripting/piping.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from cli.infrastructure.console import get_console
|
|
12
|
+
from cli.infrastructure.formatters.base import Formatter
|
|
13
|
+
from cli.infrastructure.formatters.compact_formatter import CompactFormatter
|
|
14
|
+
from cli.infrastructure.formatters.json_formatter import JsonFormatter
|
|
15
|
+
from cli.infrastructure.formatters.lines_formatter import LinesFormatter
|
|
16
|
+
from cli.infrastructure.renderers.entity_renderer import FieldConfig
|
|
17
|
+
from cli.infrastructure.renderers.list_renderer import ColumnConfig
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class OutputFormat(Enum):
|
|
21
|
+
"""Supported output formats."""
|
|
22
|
+
|
|
23
|
+
COMPACT = "compact" # Default: 2-line blocks, copy-friendly, no borders
|
|
24
|
+
JSON = "json" # Machine-readable JSON
|
|
25
|
+
LINES = "lines" # Key-value lines format
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class OutputService:
|
|
29
|
+
"""Format-aware output service.
|
|
30
|
+
|
|
31
|
+
Usage:
|
|
32
|
+
output = OutputService.get() # Uses global format setting
|
|
33
|
+
output.success("Operation completed")
|
|
34
|
+
output.entity(response, "User Details", USER_FIELDS)
|
|
35
|
+
output.table(items, "Users", USER_COLUMNS)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
_instance: "OutputService | None" = None
|
|
39
|
+
_format: OutputFormat = OutputFormat.COMPACT
|
|
40
|
+
|
|
41
|
+
def __init__(self, format: OutputFormat = OutputFormat.COMPACT):
|
|
42
|
+
"""Initialize output service with specified format.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
format: Output format (compact, json, or lines)
|
|
46
|
+
"""
|
|
47
|
+
self.format = format
|
|
48
|
+
self._console = get_console()
|
|
49
|
+
self._formatter = self._create_formatter(format)
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def configure(cls, format: OutputFormat) -> None:
|
|
53
|
+
"""Configure global output format. Call once at app startup.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
format: Output format to use globally
|
|
57
|
+
"""
|
|
58
|
+
cls._format = format
|
|
59
|
+
cls._instance = None # Reset singleton
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def get(cls) -> "OutputService":
|
|
63
|
+
"""Get the configured output service instance.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Singleton OutputService instance
|
|
67
|
+
"""
|
|
68
|
+
if cls._instance is None:
|
|
69
|
+
cls._instance = cls(cls._format)
|
|
70
|
+
return cls._instance
|
|
71
|
+
|
|
72
|
+
def _create_formatter(self, format: OutputFormat) -> Formatter:
|
|
73
|
+
"""Create formatter instance for the specified format.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
format: Output format
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Formatter instance
|
|
80
|
+
"""
|
|
81
|
+
if format == OutputFormat.JSON:
|
|
82
|
+
return JsonFormatter()
|
|
83
|
+
if format == OutputFormat.LINES:
|
|
84
|
+
return LinesFormatter()
|
|
85
|
+
# Default: COMPACT
|
|
86
|
+
return CompactFormatter(self._console)
|
|
87
|
+
|
|
88
|
+
# Message methods
|
|
89
|
+
def success(self, message: str) -> None:
|
|
90
|
+
"""Print a success message.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
message: Success message to display
|
|
94
|
+
"""
|
|
95
|
+
output = self._formatter.format_success(message)
|
|
96
|
+
self._console.print(output)
|
|
97
|
+
|
|
98
|
+
def info(self, message: str) -> None:
|
|
99
|
+
"""Print an informational message.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
message: Info message to display
|
|
103
|
+
"""
|
|
104
|
+
output = self._formatter.format_info(message)
|
|
105
|
+
self._console.print(output)
|
|
106
|
+
|
|
107
|
+
def warning(self, message: str) -> None:
|
|
108
|
+
"""Print a warning message.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
message: Warning message to display
|
|
112
|
+
"""
|
|
113
|
+
output = self._formatter.format_warning(message)
|
|
114
|
+
self._console.print(output)
|
|
115
|
+
|
|
116
|
+
def status(self, message: str) -> None:
|
|
117
|
+
"""Print a status message (dim, no icon).
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
message: Status message to display
|
|
121
|
+
"""
|
|
122
|
+
self._console.print(f"[dim]{message}[/dim]")
|
|
123
|
+
|
|
124
|
+
# Entity rendering
|
|
125
|
+
def entity(
|
|
126
|
+
self, entity: BaseModel, title: str | None, fields: list[FieldConfig]
|
|
127
|
+
) -> None:
|
|
128
|
+
"""Render a single entity (Pydantic model).
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
entity: Pydantic model instance to render
|
|
132
|
+
title: Display title for the entity
|
|
133
|
+
fields: Field configurations defining what to show
|
|
134
|
+
"""
|
|
135
|
+
from cli.infrastructure.renderers.entity_renderer import EntityRenderer
|
|
136
|
+
|
|
137
|
+
renderer = EntityRenderer(self._formatter)
|
|
138
|
+
renderer.render(entity, title, fields)
|
|
139
|
+
|
|
140
|
+
# List rendering
|
|
141
|
+
def table(
|
|
142
|
+
self, items: list[BaseModel], title: str | None, columns: list[ColumnConfig]
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Render a list of entities as a table.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
items: List of Pydantic model instances
|
|
148
|
+
title: Optional table title
|
|
149
|
+
columns: Column configurations
|
|
150
|
+
"""
|
|
151
|
+
from cli.infrastructure.renderers.list_renderer import ListRenderer
|
|
152
|
+
|
|
153
|
+
renderer = ListRenderer(self._formatter)
|
|
154
|
+
renderer.render(items, columns, title)
|
|
155
|
+
|
|
156
|
+
# Raw console access for complex cases
|
|
157
|
+
@property
|
|
158
|
+
def console(self):
|
|
159
|
+
"""Get the underlying console for complex rendering needs.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Rich Console instance
|
|
163
|
+
"""
|
|
164
|
+
return self._console
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Convenience functions for direct usage (uses global singleton)
|
|
168
|
+
def print_success(message: str) -> None:
|
|
169
|
+
"""Print a success message with checkmark.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
message: Success message to display
|
|
173
|
+
"""
|
|
174
|
+
OutputService.get().success(message)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def print_info(message: str) -> None:
|
|
178
|
+
"""Print an informational message.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
message: Info message to display
|
|
182
|
+
"""
|
|
183
|
+
OutputService.get().info(message)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def print_warning(message: str) -> None:
|
|
187
|
+
"""Print a warning message.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
message: Warning message to display
|
|
191
|
+
"""
|
|
192
|
+
OutputService.get().warning(message)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Provider credentials setup service.
|
|
2
|
+
|
|
3
|
+
Shared logic for prompting users to configure AI provider API keys.
|
|
4
|
+
Used by both login and signup flows.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from cli.infrastructure.console import Confirm, Prompt, get_console
|
|
8
|
+
from alloy_runtime_sdk.api_client.client import ApiClient
|
|
9
|
+
from alloy_runtime_types.dtos.organization_credentials import (
|
|
10
|
+
CreateOrganizationCredentialRequest,
|
|
11
|
+
)
|
|
12
|
+
from alloy_runtime_types.enums.provider import Provider
|
|
13
|
+
|
|
14
|
+
# Provider definitions: (display_name, Provider enum, env_hint, example_prefix)
|
|
15
|
+
PROVIDERS = [
|
|
16
|
+
("X.Ai", Provider.XAI, "XAI_API_KEY", "..."),
|
|
17
|
+
("Google", Provider.GOOGLE, "GOOGLE_API_KEY", "..."),
|
|
18
|
+
("Anthropic", Provider.ANTHROPIC, "ANTHROPIC_API_KEY", "sk-ant-..."),
|
|
19
|
+
("OpenAI", Provider.OPENAI, "OPENAI_API_KEY", "sk-..."),
|
|
20
|
+
("OpenRouter", Provider.OPENROUTER, "OPENROUTER_API_KEY", "sk-or-..."),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def prompt_provider_credentials(api_url: str, api_key: str) -> int:
|
|
25
|
+
"""Prompt user to configure provider API keys.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
api_url: API server base URL
|
|
29
|
+
api_key: User's API key for authenticated requests
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Number of providers successfully configured
|
|
33
|
+
"""
|
|
34
|
+
console = get_console()
|
|
35
|
+
|
|
36
|
+
console.print("\n[bold cyan]AI Provider Credentials Setup[/bold cyan]")
|
|
37
|
+
console.print(
|
|
38
|
+
"[dim]Configure API keys for AI providers to start using the platform.[/dim]\n"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
configured_count = 0
|
|
42
|
+
|
|
43
|
+
async with ApiClient(base_url=api_url, api_key=api_key) as client:
|
|
44
|
+
for display_name, provider_enum, _env_hint, example_prefix in PROVIDERS:
|
|
45
|
+
if Confirm.ask(
|
|
46
|
+
f"Configure [cyan]{display_name}[/cyan] API key?", default=False
|
|
47
|
+
):
|
|
48
|
+
api_key_value = Prompt.ask(
|
|
49
|
+
f"[cyan]{display_name} API Key[/cyan] (e.g., {example_prefix})",
|
|
50
|
+
password=True,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if api_key_value and api_key_value.strip():
|
|
54
|
+
try:
|
|
55
|
+
request = CreateOrganizationCredentialRequest(
|
|
56
|
+
credential_type_id="org_provider",
|
|
57
|
+
name=f"{display_name} API Key",
|
|
58
|
+
plaintext_value=api_key_value.strip(),
|
|
59
|
+
provider_key=provider_enum,
|
|
60
|
+
description=f"{display_name} API key configured during signup",
|
|
61
|
+
)
|
|
62
|
+
await client.create_organization_credential(request)
|
|
63
|
+
console.print(
|
|
64
|
+
f"[green]✓[/green] {display_name} credential saved!"
|
|
65
|
+
)
|
|
66
|
+
configured_count += 1
|
|
67
|
+
except Exception as e:
|
|
68
|
+
console.print(
|
|
69
|
+
f"[red]✗[/red] Failed to save {display_name} credential: {e}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if configured_count > 0:
|
|
73
|
+
console.print(f"\n[green]Configured {configured_count} provider(s)![/green]")
|
|
74
|
+
console.print("[green]You're ready to use Alloy Runtime![/green]")
|
|
75
|
+
else:
|
|
76
|
+
console.print("\n[yellow]No providers configured.[/yellow]")
|
|
77
|
+
console.print(
|
|
78
|
+
"[dim]You can add them later with the credentials commands.[/dim]"
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return configured_count
|
|
File without changes
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Entity renderer for displaying single entity details.
|
|
2
|
+
|
|
3
|
+
Renders single Pydantic model instances using configured field formatters.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Any, Callable
|
|
8
|
+
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
from cli.infrastructure.console import get_console
|
|
12
|
+
from cli.infrastructure.formatters.base import Formatter
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class FieldConfig:
|
|
17
|
+
"""Configuration for a single field to render.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
source_field: Attribute name on the Pydantic model
|
|
21
|
+
display_label: Human-readable label for display
|
|
22
|
+
formatter: Optional function to format the field value
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
source_field: str
|
|
26
|
+
display_label: str
|
|
27
|
+
formatter: Callable[[Any], str] | None = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EntityRenderer:
|
|
31
|
+
"""Renders single entity details using a formatter.
|
|
32
|
+
|
|
33
|
+
Extracts data from Pydantic models according to field configurations
|
|
34
|
+
and renders using the provided formatter.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, formatter: Formatter):
|
|
38
|
+
"""Initialize renderer with a formatter.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
formatter: Formatter instance (CompactFormatter, JsonFormatter, etc.)
|
|
42
|
+
"""
|
|
43
|
+
self.formatter = formatter
|
|
44
|
+
|
|
45
|
+
def render(
|
|
46
|
+
self, entity: BaseModel, title: str | None, fields: list[FieldConfig]
|
|
47
|
+
) -> None:
|
|
48
|
+
"""Render entity details to console.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
entity: Pydantic model instance to render
|
|
52
|
+
title: Display title for the entity (optional)
|
|
53
|
+
fields: List of field configurations defining what to show
|
|
54
|
+
"""
|
|
55
|
+
# Extract data from entity using field configs
|
|
56
|
+
data: dict[str, Any] = {}
|
|
57
|
+
for field_config in fields:
|
|
58
|
+
# Safely extract field value using getattr
|
|
59
|
+
value = getattr(entity, field_config.source_field, None)
|
|
60
|
+
|
|
61
|
+
# Apply formatter if provided
|
|
62
|
+
if field_config.formatter:
|
|
63
|
+
value = field_config.formatter(value)
|
|
64
|
+
elif value is not None:
|
|
65
|
+
value = str(value)
|
|
66
|
+
# If value is None and no formatter, leave as None
|
|
67
|
+
# (formatter will handle it with "(not set)" placeholder)
|
|
68
|
+
|
|
69
|
+
data[field_config.display_label] = value
|
|
70
|
+
|
|
71
|
+
# Format using the configured formatter
|
|
72
|
+
output = self.formatter.format_entity(data, title)
|
|
73
|
+
|
|
74
|
+
# Print using shared console
|
|
75
|
+
# Output can be a Rich renderable (Table, Panel, etc.) or a string
|
|
76
|
+
console = get_console()
|
|
77
|
+
console.print(output)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""List renderer for displaying collections with pagination.
|
|
2
|
+
|
|
3
|
+
Renders lists of Pydantic model instances using configured column formatters.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from cli.infrastructure.console import get_console
|
|
13
|
+
from cli.infrastructure.formatters.base import ColumnMeta, Formatter
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ColumnConfig:
|
|
18
|
+
"""Configuration for a table column.
|
|
19
|
+
|
|
20
|
+
Attributes:
|
|
21
|
+
source_field: Attribute name on the Pydantic model
|
|
22
|
+
header_label: Column header text
|
|
23
|
+
formatter: Optional function to format the column value
|
|
24
|
+
width: Optional fixed column width
|
|
25
|
+
align: Text alignment - "left", "center", or "right"
|
|
26
|
+
compact_line: For compact format - 1 = primary line (metadata),
|
|
27
|
+
2 = detail line (content/description). Default is 1.
|
|
28
|
+
compact_style: Rich style for compact format (e.g., "cyan bold", "dim")
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
source_field: str
|
|
32
|
+
header_label: str
|
|
33
|
+
formatter: Callable[[Any], str] | None = None
|
|
34
|
+
width: int | None = None
|
|
35
|
+
align: str = "left"
|
|
36
|
+
compact_line: int = 1
|
|
37
|
+
compact_style: str | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ListRenderer:
|
|
41
|
+
"""Renders lists/collections with pagination support.
|
|
42
|
+
|
|
43
|
+
Extracts data from lists of Pydantic models according to column configurations
|
|
44
|
+
and renders using the provided formatter.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, formatter: Formatter):
|
|
48
|
+
"""Initialize renderer with a formatter.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
formatter: Formatter instance (CompactFormatter, JsonFormatter, etc.)
|
|
52
|
+
"""
|
|
53
|
+
self.formatter = formatter
|
|
54
|
+
|
|
55
|
+
def render(
|
|
56
|
+
self,
|
|
57
|
+
items: Sequence[BaseModel],
|
|
58
|
+
columns: list[ColumnConfig],
|
|
59
|
+
title: str | None = None,
|
|
60
|
+
cursor: str | None = None,
|
|
61
|
+
total_count: int | None = None,
|
|
62
|
+
) -> None:
|
|
63
|
+
"""Render paginated list to console.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
items: Sequence of Pydantic model instances to render
|
|
67
|
+
columns: Column configurations defining what to show
|
|
68
|
+
title: Optional table title
|
|
69
|
+
cursor: Pagination cursor for next page
|
|
70
|
+
total_count: Total items across all pages
|
|
71
|
+
"""
|
|
72
|
+
# Extract data from items using column configs
|
|
73
|
+
rows: list[dict[str, Any]] = []
|
|
74
|
+
for item in items:
|
|
75
|
+
row: dict[str, Any] = {}
|
|
76
|
+
for col in columns:
|
|
77
|
+
# Safely extract column value using getattr
|
|
78
|
+
value = getattr(item, col.source_field, None)
|
|
79
|
+
|
|
80
|
+
# Apply formatter if provided
|
|
81
|
+
if col.formatter:
|
|
82
|
+
value = col.formatter(value)
|
|
83
|
+
elif value is not None:
|
|
84
|
+
value = str(value)
|
|
85
|
+
# If value is None and no formatter, leave as None
|
|
86
|
+
# (formatter will handle it with "(not set)" placeholder)
|
|
87
|
+
|
|
88
|
+
row[col.header_label] = value
|
|
89
|
+
rows.append(row)
|
|
90
|
+
|
|
91
|
+
# Build column metadata for formatters that need layout info
|
|
92
|
+
column_meta = [
|
|
93
|
+
ColumnMeta(
|
|
94
|
+
label=col.header_label,
|
|
95
|
+
compact_line=col.compact_line,
|
|
96
|
+
compact_style=col.compact_style,
|
|
97
|
+
width=col.width,
|
|
98
|
+
)
|
|
99
|
+
for col in columns
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
# Format the list using the configured formatter
|
|
103
|
+
output = self.formatter.format_list(rows, title, column_meta)
|
|
104
|
+
|
|
105
|
+
# Print using shared console
|
|
106
|
+
# Output can be a Rich renderable (Table) or a string
|
|
107
|
+
console = get_console()
|
|
108
|
+
console.print(output)
|
|
109
|
+
|
|
110
|
+
# Show pagination info if available
|
|
111
|
+
if cursor:
|
|
112
|
+
console.print(f"[dim]Next page cursor: {cursor}[/dim]")
|
|
113
|
+
if total_count:
|
|
114
|
+
console.print(f"[dim]Showing {len(items)} of {total_count} total[/dim]")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Common formatting utilities for CLI display."""
|
|
2
|
+
|
|
3
|
+
from alloy_runtime_types.enums.ownership_scope import OwnershipScope
|
|
4
|
+
from textual.widgets import RadioSet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def format_scope_label(
|
|
8
|
+
organization_id: str | None,
|
|
9
|
+
user_id: str | None,
|
|
10
|
+
) -> str:
|
|
11
|
+
"""Format ownership scope as human-readable label.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
organization_id: Organization UUID if org-owned
|
|
15
|
+
user_id: User UUID if user-owned
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
Scope string: "User", "Org", or "Global"
|
|
19
|
+
"""
|
|
20
|
+
if user_id:
|
|
21
|
+
return "User"
|
|
22
|
+
elif organization_id:
|
|
23
|
+
return "Org"
|
|
24
|
+
return "Global"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_scope_from_radioset(
|
|
28
|
+
radioset: RadioSet,
|
|
29
|
+
user_id: str = "scope-user",
|
|
30
|
+
org_id: str = "scope-org",
|
|
31
|
+
) -> OwnershipScope:
|
|
32
|
+
"""Extract OwnershipScope from a RadioSet widget.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
radioset: The RadioSet containing scope radio buttons
|
|
36
|
+
user_id: ID of the user scope radio button
|
|
37
|
+
org_id: ID of the org scope radio button
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
OwnershipScope enum value
|
|
41
|
+
"""
|
|
42
|
+
pressed = radioset.pressed_button
|
|
43
|
+
if pressed is None or pressed.id == user_id:
|
|
44
|
+
return OwnershipScope.USER
|
|
45
|
+
elif pressed.id == org_id:
|
|
46
|
+
return OwnershipScope.ORGANIZATION
|
|
47
|
+
return OwnershipScope.GLOBAL
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Reusable loading spinner component for async operations.
|
|
2
|
+
|
|
3
|
+
Provides a context manager for displaying a spinner while waiting for
|
|
4
|
+
server responses or other async operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import AsyncIterator
|
|
8
|
+
from contextlib import asynccontextmanager
|
|
9
|
+
from types import TracebackType
|
|
10
|
+
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.status import Status
|
|
13
|
+
|
|
14
|
+
from cli.infrastructure.console import get_console
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Spinner:
|
|
18
|
+
"""A loading spinner for async operations.
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
async with Spinner("Processing...") as spinner:
|
|
22
|
+
result = await some_async_operation()
|
|
23
|
+
spinner.update("Almost done...")
|
|
24
|
+
|
|
25
|
+
# Or with the module-level context manager:
|
|
26
|
+
async with spinner("Loading data..."):
|
|
27
|
+
data = await fetch_data()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
message: str = "Processing...",
|
|
33
|
+
spinner_style: str = "dots",
|
|
34
|
+
console: Console | None = None,
|
|
35
|
+
):
|
|
36
|
+
"""Initialize the spinner.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
message: Initial status message to display
|
|
40
|
+
spinner_style: Rich spinner style (dots, line, dots2, etc.)
|
|
41
|
+
console: Optional console instance (uses global if not provided)
|
|
42
|
+
"""
|
|
43
|
+
self.message = message
|
|
44
|
+
self.spinner_style = spinner_style
|
|
45
|
+
self._console = console or get_console()
|
|
46
|
+
self._status: Status | None = None
|
|
47
|
+
|
|
48
|
+
async def __aenter__(self) -> "Spinner":
|
|
49
|
+
"""Start the spinner."""
|
|
50
|
+
self._status = self._console.status(
|
|
51
|
+
f"[dim]{self.message}[/]",
|
|
52
|
+
spinner=self.spinner_style,
|
|
53
|
+
spinner_style="cyan",
|
|
54
|
+
)
|
|
55
|
+
self._status.start()
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
async def __aexit__(
|
|
59
|
+
self,
|
|
60
|
+
_exc_type: type[BaseException] | None,
|
|
61
|
+
_exc_val: BaseException | None,
|
|
62
|
+
_exc_tb: TracebackType | None,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""Stop the spinner."""
|
|
65
|
+
if self._status:
|
|
66
|
+
self._status.stop()
|
|
67
|
+
self._status = None
|
|
68
|
+
|
|
69
|
+
def update(self, message: str) -> None:
|
|
70
|
+
"""Update the spinner message.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
message: New status message to display
|
|
74
|
+
"""
|
|
75
|
+
if self._status:
|
|
76
|
+
self._status.update(f"[dim]{message}[/]")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@asynccontextmanager
|
|
80
|
+
async def spinner(
|
|
81
|
+
message: str = "Processing...",
|
|
82
|
+
spinner_style: str = "dots",
|
|
83
|
+
) -> AsyncIterator[Spinner]:
|
|
84
|
+
"""Context manager for displaying a loading spinner.
|
|
85
|
+
|
|
86
|
+
Usage:
|
|
87
|
+
async with spinner("Fetching data...") as s:
|
|
88
|
+
data = await fetch_data()
|
|
89
|
+
s.update("Processing response...")
|
|
90
|
+
result = process(data)
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
message: Initial status message to display
|
|
94
|
+
spinner_style: Rich spinner style
|
|
95
|
+
|
|
96
|
+
Yields:
|
|
97
|
+
Spinner instance for updating the message
|
|
98
|
+
"""
|
|
99
|
+
s = Spinner(message=message, spinner_style=spinner_style)
|
|
100
|
+
async with s:
|
|
101
|
+
yield s
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Clipboard utilities for TUI applications."""
|
|
2
|
+
|
|
3
|
+
import pyperclip
|
|
4
|
+
from typing import Literal, Protocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
SeverityLevel = Literal["information", "warning", "error"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SupportsNotify(Protocol):
|
|
11
|
+
"""Minimal app protocol for clipboard notifications."""
|
|
12
|
+
|
|
13
|
+
def notify(
|
|
14
|
+
self,
|
|
15
|
+
message: str,
|
|
16
|
+
*,
|
|
17
|
+
title: str = "",
|
|
18
|
+
severity: SeverityLevel = "information",
|
|
19
|
+
timeout: float | None = None,
|
|
20
|
+
markup: bool = True,
|
|
21
|
+
) -> None: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def copy_to_clipboard(app: SupportsNotify, text: str, label: str = "ID") -> bool:
|
|
25
|
+
"""Copy text to clipboard with user notification.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
app: The Textual app instance (for notifications)
|
|
29
|
+
text: The text to copy
|
|
30
|
+
label: Label for the notification message (e.g., "ID", "Version ID")
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
True if copy succeeded, False otherwise
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
pyperclip.copy(text)
|
|
37
|
+
app.notify(f"Copied {label}: {text}", severity="information")
|
|
38
|
+
return True
|
|
39
|
+
except Exception as e:
|
|
40
|
+
app.notify(f"Copy failed: {e}", severity="error")
|
|
41
|
+
return False
|