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,276 @@
|
|
|
1
|
+
"""Presenter for template render output."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
import tempfile
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.panel import Panel
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from cli.infrastructure.editor import EditorError, get_editor
|
|
14
|
+
from cli.infrastructure.formatting.fields import format_uuid
|
|
15
|
+
from cli.infrastructure.macro_parser import extract_jinja_syntax
|
|
16
|
+
from cli.infrastructure.output import OutputService
|
|
17
|
+
from alloy_runtime_types.dtos.templates import RenderTemplateResponse
|
|
18
|
+
|
|
19
|
+
# Import pyperclip at module level for easier mocking in tests
|
|
20
|
+
pyperclip: Any | None = None
|
|
21
|
+
try:
|
|
22
|
+
import pyperclip as _pyperclip
|
|
23
|
+
except ImportError:
|
|
24
|
+
pass
|
|
25
|
+
else:
|
|
26
|
+
pyperclip = _pyperclip
|
|
27
|
+
|
|
28
|
+
PYPERCLIP_AVAILABLE = pyperclip is not None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def present_render_result(
|
|
32
|
+
response: RenderTemplateResponse,
|
|
33
|
+
template_name: str,
|
|
34
|
+
output_mode: str = "console",
|
|
35
|
+
output_file: str | None = None,
|
|
36
|
+
print_escaped: bool = False,
|
|
37
|
+
) -> bool:
|
|
38
|
+
"""Present the rendered template result.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
response: Render response from server
|
|
42
|
+
template_name: Name of the rendered template
|
|
43
|
+
output_mode: Output destination - 'console', 'clipboard', 'file', or 'editor'
|
|
44
|
+
output_file: File path for 'file' output mode
|
|
45
|
+
print_escaped: If True, print Jinja syntax found in rendered output
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
True if output was successful, False if output failed
|
|
49
|
+
"""
|
|
50
|
+
output = OutputService.get()
|
|
51
|
+
|
|
52
|
+
if output_mode == "clipboard":
|
|
53
|
+
result = _copy_to_clipboard(response.rendered_text, template_name, output)
|
|
54
|
+
elif output_mode == "file":
|
|
55
|
+
result = _save_to_file(response, template_name, output_file, output)
|
|
56
|
+
elif output_mode == "editor":
|
|
57
|
+
result = _open_in_editor(response.rendered_text, template_name, output)
|
|
58
|
+
else:
|
|
59
|
+
result = _display_to_console(response, template_name, output)
|
|
60
|
+
|
|
61
|
+
# Print escaped Jinja syntax after output if requested
|
|
62
|
+
if print_escaped:
|
|
63
|
+
_print_escaped_jinja(response.rendered_text, output)
|
|
64
|
+
|
|
65
|
+
return result
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _print_escaped_jinja(rendered_text: str, output: OutputService) -> None:
|
|
69
|
+
"""Print Jinja syntax found in rendered output.
|
|
70
|
+
|
|
71
|
+
Extracts and prints {{ }}, {% %}, and {# #} blocks that remain
|
|
72
|
+
in the rendered output (typically from {% raw %} blocks).
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
rendered_text: The rendered template content
|
|
76
|
+
output: Output service for printing
|
|
77
|
+
"""
|
|
78
|
+
matches = extract_jinja_syntax(rendered_text)
|
|
79
|
+
|
|
80
|
+
if not matches:
|
|
81
|
+
output.info("No escaped Jinja syntax found in rendered output")
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
# Print to stderr so it doesn't interfere with piped output
|
|
85
|
+
stderr_console = Console(file=sys.stderr, force_terminal=True)
|
|
86
|
+
stderr_console.print(
|
|
87
|
+
f"\n[bold cyan]Escaped Jinja Syntax[/bold cyan] ({len(matches)} found):"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
for match in matches:
|
|
91
|
+
# Print the full content of each match
|
|
92
|
+
stderr_console.print(match.content)
|
|
93
|
+
|
|
94
|
+
stderr_console.print() # Blank line after
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _display_to_console(
|
|
98
|
+
response: RenderTemplateResponse,
|
|
99
|
+
template_name: str,
|
|
100
|
+
_output: OutputService,
|
|
101
|
+
) -> bool:
|
|
102
|
+
"""Display rendered template to console.
|
|
103
|
+
|
|
104
|
+
Metadata and status messages are printed to stderr for piping support.
|
|
105
|
+
The actual rendered content is printed to stdout without formatting.
|
|
106
|
+
"""
|
|
107
|
+
# Create a console for stderr output (for metadata/status)
|
|
108
|
+
stderr_console = Console(file=sys.stderr, force_terminal=True)
|
|
109
|
+
|
|
110
|
+
# Print success message to stderr (directly, not through output service)
|
|
111
|
+
stderr_console.print(
|
|
112
|
+
f"[green]✓[/green] Template '{template_name}' rendered successfully"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Metadata table - print to stderr
|
|
116
|
+
meta_table = Table(show_header=False, box=None, padding=(0, 1))
|
|
117
|
+
meta_table.add_column("Field", style="dim")
|
|
118
|
+
meta_table.add_column("Value")
|
|
119
|
+
|
|
120
|
+
meta_table.add_row("Character Count", f"{response.character_count:,}")
|
|
121
|
+
meta_table.add_row(
|
|
122
|
+
"Version ID", format_uuid(response.template_version_id, short=True)
|
|
123
|
+
)
|
|
124
|
+
meta_table.add_row("Content Hash", response.content_hash[:16] + "...")
|
|
125
|
+
meta_table.add_row("Render Log ID", format_uuid(response.render_log_id, short=True))
|
|
126
|
+
|
|
127
|
+
meta_panel = Panel(meta_table, title="Render Metadata", border_style="blue")
|
|
128
|
+
stderr_console.print(meta_panel)
|
|
129
|
+
|
|
130
|
+
# Print the actual rendered content to stdout (for piping)
|
|
131
|
+
# No formatting, no panel - just the raw content
|
|
132
|
+
print(response.rendered_text, file=sys.stdout)
|
|
133
|
+
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _save_to_file(
|
|
138
|
+
response: RenderTemplateResponse,
|
|
139
|
+
template_name: str,
|
|
140
|
+
output_file: str | None,
|
|
141
|
+
output: OutputService,
|
|
142
|
+
) -> bool:
|
|
143
|
+
"""Save rendered template to a file.
|
|
144
|
+
|
|
145
|
+
Returns True on success, False on failure.
|
|
146
|
+
"""
|
|
147
|
+
if not output_file:
|
|
148
|
+
output.warning("No output file specified")
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
file_path = Path(output_file).expanduser().resolve()
|
|
153
|
+
|
|
154
|
+
# Ensure parent directory exists
|
|
155
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
156
|
+
|
|
157
|
+
# Write the content to the file
|
|
158
|
+
file_path.write_text(response.rendered_text, encoding="utf-8")
|
|
159
|
+
|
|
160
|
+
output.success(
|
|
161
|
+
f"Template '{template_name}' rendered and saved to {file_path} "
|
|
162
|
+
f"({response.character_count:,} characters)"
|
|
163
|
+
)
|
|
164
|
+
return True
|
|
165
|
+
except PermissionError:
|
|
166
|
+
output.warning(f"Permission denied: Cannot write to '{output_file}'")
|
|
167
|
+
return False
|
|
168
|
+
except OSError as e:
|
|
169
|
+
output.warning(f"Failed to save file: {e}")
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _copy_to_clipboard(
|
|
174
|
+
rendered_text: str,
|
|
175
|
+
template_name: str,
|
|
176
|
+
output: OutputService,
|
|
177
|
+
) -> bool:
|
|
178
|
+
"""Copy rendered template to clipboard.
|
|
179
|
+
|
|
180
|
+
All output goes to stderr since clipboard mode doesn't output the content to stdout.
|
|
181
|
+
|
|
182
|
+
Returns True on success, False on failure.
|
|
183
|
+
"""
|
|
184
|
+
if not PYPERCLIP_AVAILABLE or pyperclip is None:
|
|
185
|
+
output.warning("pyperclip not installed. Install with: pip install pyperclip")
|
|
186
|
+
output.info("Falling back to console output...")
|
|
187
|
+
# Fallback: print to stdout for piping
|
|
188
|
+
print(rendered_text, file=sys.stdout)
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
pyperclip.copy(rendered_text)
|
|
193
|
+
output.success(
|
|
194
|
+
f"Template '{template_name}' rendered and copied to clipboard "
|
|
195
|
+
f"({len(rendered_text):,} characters)"
|
|
196
|
+
)
|
|
197
|
+
return True
|
|
198
|
+
except Exception as e:
|
|
199
|
+
output.warning(f"Failed to copy to clipboard: {e}")
|
|
200
|
+
output.info("Falling back to console output...")
|
|
201
|
+
# Fallback: print to stdout for piping
|
|
202
|
+
print(rendered_text, file=sys.stdout)
|
|
203
|
+
return False
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _open_in_editor(
|
|
207
|
+
rendered_text: str,
|
|
208
|
+
template_name: str,
|
|
209
|
+
output: OutputService,
|
|
210
|
+
) -> bool:
|
|
211
|
+
"""Open rendered template in the user's $EDITOR.
|
|
212
|
+
|
|
213
|
+
Creates a temporary file, opens it in the editor, and waits for the editor
|
|
214
|
+
to close. The temporary file is cleaned up afterward.
|
|
215
|
+
|
|
216
|
+
Returns True on success, False on failure.
|
|
217
|
+
"""
|
|
218
|
+
try:
|
|
219
|
+
editor = get_editor()
|
|
220
|
+
except EditorError:
|
|
221
|
+
output.warning(
|
|
222
|
+
"No editor found. Set $EDITOR environment variable or install nano/vim."
|
|
223
|
+
)
|
|
224
|
+
output.info("Falling back to console output...")
|
|
225
|
+
print(rendered_text, file=sys.stdout)
|
|
226
|
+
return False
|
|
227
|
+
|
|
228
|
+
# Create temp file with .txt extension
|
|
229
|
+
try:
|
|
230
|
+
with tempfile.NamedTemporaryFile(
|
|
231
|
+
mode="w",
|
|
232
|
+
suffix=".txt",
|
|
233
|
+
delete=False,
|
|
234
|
+
encoding="utf-8",
|
|
235
|
+
) as f:
|
|
236
|
+
f.write(rendered_text)
|
|
237
|
+
temp_path = Path(f.name)
|
|
238
|
+
except OSError as e:
|
|
239
|
+
output.warning(f"Failed to create temporary file: {e}")
|
|
240
|
+
output.info("Falling back to console output...")
|
|
241
|
+
print(rendered_text, file=sys.stdout)
|
|
242
|
+
return False
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
# Open editor and wait for it to close
|
|
246
|
+
editor_parts = editor.split()
|
|
247
|
+
cmd = editor_parts + [str(temp_path)]
|
|
248
|
+
|
|
249
|
+
result = subprocess.call(cmd)
|
|
250
|
+
|
|
251
|
+
if result != 0:
|
|
252
|
+
output.warning(f"Editor exited with non-zero status: {result}")
|
|
253
|
+
return False
|
|
254
|
+
|
|
255
|
+
output.success(
|
|
256
|
+
f"Template '{template_name}' rendered and opened in editor "
|
|
257
|
+
f"({len(rendered_text):,} characters)"
|
|
258
|
+
)
|
|
259
|
+
return True
|
|
260
|
+
|
|
261
|
+
except FileNotFoundError:
|
|
262
|
+
output.warning(f"Editor '{editor}' not found")
|
|
263
|
+
output.info("Falling back to console output...")
|
|
264
|
+
print(rendered_text, file=sys.stdout)
|
|
265
|
+
return False
|
|
266
|
+
except OSError as e:
|
|
267
|
+
output.warning(f"Failed to open editor: {e}")
|
|
268
|
+
output.info("Falling back to console output...")
|
|
269
|
+
print(rendered_text, file=sys.stdout)
|
|
270
|
+
return False
|
|
271
|
+
finally:
|
|
272
|
+
# Clean up temp file
|
|
273
|
+
try:
|
|
274
|
+
temp_path.unlink()
|
|
275
|
+
except OSError:
|
|
276
|
+
pass # Best effort cleanup
|
|
File without changes
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Template update command implementation."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from cli.commands.flag_utils import (
|
|
9
|
+
parse_tags,
|
|
10
|
+
require_exclusive,
|
|
11
|
+
require_update_flags,
|
|
12
|
+
validate_template_content_type,
|
|
13
|
+
validate_visibility,
|
|
14
|
+
)
|
|
15
|
+
from cli.commands.templates.update.presenter import present_template_update_success
|
|
16
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
17
|
+
from cli.infrastructure.file_content import FileContentError, resolve_content
|
|
18
|
+
from alloy_runtime_types.dtos.templates import UpdateTemplateRequest
|
|
19
|
+
from alloy_runtime_types.enums.template_enums import (
|
|
20
|
+
TemplateContentType,
|
|
21
|
+
TemplateVisibility,
|
|
22
|
+
)
|
|
23
|
+
from alloy_runtime_sdk.exceptions.errors import NotFoundError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def templates_update_command(
|
|
27
|
+
template: str = typer.Argument(..., help="Template name or UUID"),
|
|
28
|
+
name: Optional[str] = typer.Option(
|
|
29
|
+
None,
|
|
30
|
+
"-n",
|
|
31
|
+
"--name",
|
|
32
|
+
help="New name",
|
|
33
|
+
),
|
|
34
|
+
description: Optional[str] = typer.Option(
|
|
35
|
+
None,
|
|
36
|
+
"-d",
|
|
37
|
+
"--description",
|
|
38
|
+
help="New description",
|
|
39
|
+
),
|
|
40
|
+
content_type: Optional[str] = typer.Option(
|
|
41
|
+
None,
|
|
42
|
+
"--type",
|
|
43
|
+
help="New type: system_instruction, user_message, fragment",
|
|
44
|
+
),
|
|
45
|
+
visibility: Optional[str] = typer.Option(
|
|
46
|
+
None,
|
|
47
|
+
"-V",
|
|
48
|
+
"--visibility",
|
|
49
|
+
help="New visibility: private, organization, public",
|
|
50
|
+
),
|
|
51
|
+
content: Optional[str] = typer.Option(
|
|
52
|
+
None,
|
|
53
|
+
"-c",
|
|
54
|
+
"--content",
|
|
55
|
+
help="New content (or @file)",
|
|
56
|
+
),
|
|
57
|
+
content_file: Optional[Path] = typer.Option(
|
|
58
|
+
None,
|
|
59
|
+
"-f",
|
|
60
|
+
"--file",
|
|
61
|
+
help="Read new content from file",
|
|
62
|
+
exists=True,
|
|
63
|
+
readable=True,
|
|
64
|
+
),
|
|
65
|
+
tags: Optional[str] = typer.Option(
|
|
66
|
+
None,
|
|
67
|
+
"-t",
|
|
68
|
+
"--tags",
|
|
69
|
+
help="Replace tags (comma-separated)",
|
|
70
|
+
),
|
|
71
|
+
clear_description: bool = typer.Option(
|
|
72
|
+
False,
|
|
73
|
+
"--clear-description",
|
|
74
|
+
help="Clear description",
|
|
75
|
+
),
|
|
76
|
+
clear_tags: bool = typer.Option(
|
|
77
|
+
False,
|
|
78
|
+
"--clear-tags",
|
|
79
|
+
help="Remove all tags",
|
|
80
|
+
),
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Update an existing template.
|
|
83
|
+
|
|
84
|
+
Only specified fields are updated. Content updates only allowed for single-version templates.
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
ai templates update my-template -n new-name
|
|
88
|
+
ai tpl update my-template -d "New description"
|
|
89
|
+
ai tpl update my-template --clear-description
|
|
90
|
+
ai tpl update my-template -f template.jinja2
|
|
91
|
+
ai tpl update my-template -V public -t "new.tag"
|
|
92
|
+
"""
|
|
93
|
+
# Validate exclusive flags
|
|
94
|
+
require_exclusive(("--file", content_file), ("--content", content))
|
|
95
|
+
require_exclusive(
|
|
96
|
+
("--description", description), ("--clear-description", clear_description)
|
|
97
|
+
)
|
|
98
|
+
require_exclusive(("--tags", tags), ("--clear-tags", clear_tags))
|
|
99
|
+
|
|
100
|
+
# Check at least one update flag provided
|
|
101
|
+
require_update_flags(
|
|
102
|
+
("--name", name),
|
|
103
|
+
("--description", description),
|
|
104
|
+
("--type", content_type),
|
|
105
|
+
("--visibility", visibility),
|
|
106
|
+
("--content", content),
|
|
107
|
+
("--file", content_file),
|
|
108
|
+
("--tags", tags),
|
|
109
|
+
("--clear-description", clear_description),
|
|
110
|
+
("--clear-tags", clear_tags),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
_execute_update(
|
|
114
|
+
template_identifier=template,
|
|
115
|
+
name=name,
|
|
116
|
+
description=description,
|
|
117
|
+
content_type=content_type,
|
|
118
|
+
visibility=visibility,
|
|
119
|
+
content=content,
|
|
120
|
+
content_file=content_file,
|
|
121
|
+
tags=tags,
|
|
122
|
+
clear_description=clear_description,
|
|
123
|
+
clear_tags=clear_tags,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@async_command
|
|
128
|
+
async def _execute_update(
|
|
129
|
+
template_identifier: str,
|
|
130
|
+
name: Optional[str],
|
|
131
|
+
description: Optional[str],
|
|
132
|
+
content_type: Optional[str],
|
|
133
|
+
visibility: Optional[str],
|
|
134
|
+
content: Optional[str],
|
|
135
|
+
content_file: Optional[Path],
|
|
136
|
+
tags: Optional[str],
|
|
137
|
+
clear_description: bool,
|
|
138
|
+
clear_tags: bool,
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Execute the template update operation."""
|
|
141
|
+
# Resolve @file references
|
|
142
|
+
try:
|
|
143
|
+
content = resolve_content(content)
|
|
144
|
+
except FileContentError as e:
|
|
145
|
+
raise typer.BadParameter(str(e))
|
|
146
|
+
|
|
147
|
+
# Get content from file if specified
|
|
148
|
+
template_content: Optional[str] = None
|
|
149
|
+
if content_file is not None:
|
|
150
|
+
template_content = content_file.read_text()
|
|
151
|
+
elif content is not None:
|
|
152
|
+
template_content = content
|
|
153
|
+
|
|
154
|
+
# Validate enums
|
|
155
|
+
content_type_enum: Optional[TemplateContentType] = None
|
|
156
|
+
if content_type is not None:
|
|
157
|
+
content_type_enum = validate_template_content_type(content_type)
|
|
158
|
+
|
|
159
|
+
visibility_enum: Optional[TemplateVisibility] = None
|
|
160
|
+
if visibility is not None:
|
|
161
|
+
visibility_enum = validate_visibility(visibility)
|
|
162
|
+
|
|
163
|
+
# Handle tags
|
|
164
|
+
tag_paths: Optional[list[str]] = None
|
|
165
|
+
if clear_tags:
|
|
166
|
+
tag_paths = []
|
|
167
|
+
elif tags is not None:
|
|
168
|
+
tag_paths = parse_tags(tags)
|
|
169
|
+
if not tag_paths:
|
|
170
|
+
raise typer.BadParameter("--tags must contain at least one tag")
|
|
171
|
+
|
|
172
|
+
# Handle description
|
|
173
|
+
final_description: Optional[str] = description
|
|
174
|
+
if clear_description:
|
|
175
|
+
final_description = ""
|
|
176
|
+
|
|
177
|
+
# Build update request
|
|
178
|
+
request = UpdateTemplateRequest(
|
|
179
|
+
name=name,
|
|
180
|
+
description=final_description
|
|
181
|
+
if (description is not None or clear_description)
|
|
182
|
+
else None,
|
|
183
|
+
content_type=content_type_enum,
|
|
184
|
+
visibility=visibility_enum,
|
|
185
|
+
content=template_content,
|
|
186
|
+
tag_paths=tag_paths,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
async with authenticated_client() as (_config, client):
|
|
190
|
+
try:
|
|
191
|
+
await client.get_template(template_identifier)
|
|
192
|
+
except NotFoundError:
|
|
193
|
+
raise typer.BadParameter(
|
|
194
|
+
f"Template '{template_identifier}' not found. Use 'ai templates list' to see available templates."
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
response = await client.update_template(template_identifier, request)
|
|
198
|
+
|
|
199
|
+
present_template_update_success(response)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Presenter for template update output."""
|
|
2
|
+
|
|
3
|
+
from rich.panel import Panel
|
|
4
|
+
from rich.table import Table
|
|
5
|
+
from rich.text import Text
|
|
6
|
+
|
|
7
|
+
from cli.infrastructure.formatting.fields import (
|
|
8
|
+
format_datetime,
|
|
9
|
+
format_optional,
|
|
10
|
+
format_uuid,
|
|
11
|
+
)
|
|
12
|
+
from cli.infrastructure.output import OutputService
|
|
13
|
+
from alloy_runtime_types.dtos.templates import UpdateTemplateResponse
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def present_template_update_success(response: UpdateTemplateResponse) -> None:
|
|
17
|
+
"""Present successful template update.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
response: Template update response from server
|
|
21
|
+
"""
|
|
22
|
+
output = OutputService.get()
|
|
23
|
+
|
|
24
|
+
template = response.template
|
|
25
|
+
version = response.version
|
|
26
|
+
dependencies = response.dependencies
|
|
27
|
+
|
|
28
|
+
output.success("Template updated successfully")
|
|
29
|
+
|
|
30
|
+
# Build a table for template display
|
|
31
|
+
table = Table(show_header=False, box=None, padding=(0, 1))
|
|
32
|
+
table.add_column("Field", style="dim")
|
|
33
|
+
table.add_column("Value")
|
|
34
|
+
|
|
35
|
+
# Template info
|
|
36
|
+
table.add_row("ID", format_uuid(template.id, short=False))
|
|
37
|
+
table.add_row("Name", template.name)
|
|
38
|
+
table.add_row("Content Type", template.content_type_id)
|
|
39
|
+
table.add_row("Visibility", template.visibility_id)
|
|
40
|
+
table.add_row("Description", format_optional(template.description))
|
|
41
|
+
|
|
42
|
+
# Version info
|
|
43
|
+
table.add_row("Version", str(version.version))
|
|
44
|
+
table.add_row("Version ID", format_uuid(version.id, short=True))
|
|
45
|
+
table.add_row("Content Length", f"{len(version.content)} chars")
|
|
46
|
+
|
|
47
|
+
# Tags
|
|
48
|
+
if template.tags:
|
|
49
|
+
tag_str = ", ".join(t.tag_path for t in template.tags)
|
|
50
|
+
table.add_row("Tags", tag_str)
|
|
51
|
+
else:
|
|
52
|
+
table.add_row("Tags", "(none)")
|
|
53
|
+
|
|
54
|
+
# Dependencies
|
|
55
|
+
if dependencies:
|
|
56
|
+
dep_str = ", ".join(d.child_template_name for d in dependencies)
|
|
57
|
+
table.add_row("Dependencies", dep_str)
|
|
58
|
+
else:
|
|
59
|
+
table.add_row("Dependencies", "(none)")
|
|
60
|
+
|
|
61
|
+
# Variables
|
|
62
|
+
if version.required_variables:
|
|
63
|
+
vars_str = ", ".join(version.required_variables)
|
|
64
|
+
table.add_row("Required Variables", vars_str)
|
|
65
|
+
else:
|
|
66
|
+
table.add_row("Required Variables", "(none)")
|
|
67
|
+
|
|
68
|
+
# Ownership
|
|
69
|
+
table.add_row(
|
|
70
|
+
"Organization ID",
|
|
71
|
+
format_optional(template.organization_id, lambda x: format_uuid(x, short=True)),
|
|
72
|
+
)
|
|
73
|
+
table.add_row(
|
|
74
|
+
"User ID",
|
|
75
|
+
format_optional(template.user_id, lambda x: format_uuid(x, short=True)),
|
|
76
|
+
)
|
|
77
|
+
table.add_row("Created At", format_datetime(template.created_at))
|
|
78
|
+
table.add_row("Updated At", format_datetime(template.updated_at))
|
|
79
|
+
|
|
80
|
+
panel = Panel(table, title=f"Template: {template.name}", border_style="green")
|
|
81
|
+
output.console.print(panel)
|
|
82
|
+
|
|
83
|
+
# Show content preview
|
|
84
|
+
if version.content:
|
|
85
|
+
content_preview = version.content
|
|
86
|
+
if len(content_preview) > 500:
|
|
87
|
+
content_preview = content_preview[:500] + "\n... (truncated)"
|
|
88
|
+
|
|
89
|
+
content_panel = Panel(
|
|
90
|
+
Text(content_preview, style="dim"),
|
|
91
|
+
title="Content Preview",
|
|
92
|
+
border_style="blue",
|
|
93
|
+
)
|
|
94
|
+
output.console.print(content_panel)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Template version create command implementation."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from cli.commands.flag_utils import parse_tags, require_one_of
|
|
9
|
+
from cli.commands.templates.version.presenter import present_version_create_success
|
|
10
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
11
|
+
from alloy_runtime_types.dtos.templates import CreateTemplateVersionRequest
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def templates_version_command(
|
|
15
|
+
template: str = typer.Argument(
|
|
16
|
+
...,
|
|
17
|
+
help="Template name or UUID",
|
|
18
|
+
),
|
|
19
|
+
content_file: Optional[Path] = typer.Option(
|
|
20
|
+
None,
|
|
21
|
+
"-f",
|
|
22
|
+
"--file",
|
|
23
|
+
help="Read content from file",
|
|
24
|
+
exists=True,
|
|
25
|
+
readable=True,
|
|
26
|
+
),
|
|
27
|
+
content: Optional[str] = typer.Option(
|
|
28
|
+
None,
|
|
29
|
+
"-c",
|
|
30
|
+
"--content",
|
|
31
|
+
help="Inline content",
|
|
32
|
+
),
|
|
33
|
+
tags: Optional[str] = typer.Option(
|
|
34
|
+
None,
|
|
35
|
+
"-t",
|
|
36
|
+
"--tags",
|
|
37
|
+
help="Replace tags (comma-separated)",
|
|
38
|
+
),
|
|
39
|
+
clear_tags: bool = typer.Option(
|
|
40
|
+
False,
|
|
41
|
+
"--clear-tags",
|
|
42
|
+
help="Remove all tags",
|
|
43
|
+
),
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Create a new version of a template.
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
ai templates version my-template -c "Updated content"
|
|
49
|
+
ai tpl version my-template -f updated.jinja2
|
|
50
|
+
ai tpl version my-template -c "New content" -t "email,v2"
|
|
51
|
+
ai tpl version my-template -c "New content" --clear-tags
|
|
52
|
+
"""
|
|
53
|
+
require_one_of(("--file", content_file), ("--content", content))
|
|
54
|
+
|
|
55
|
+
_execute_version_from_flags(
|
|
56
|
+
template_identifier=template,
|
|
57
|
+
content_file=content_file,
|
|
58
|
+
content=content,
|
|
59
|
+
tags=tags,
|
|
60
|
+
clear_tags=clear_tags,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _execute_version_from_flags(
|
|
65
|
+
template_identifier: str,
|
|
66
|
+
content_file: Optional[Path],
|
|
67
|
+
content: Optional[str],
|
|
68
|
+
tags: Optional[str],
|
|
69
|
+
clear_tags: bool,
|
|
70
|
+
) -> None:
|
|
71
|
+
"""Build and execute version creation from command flags."""
|
|
72
|
+
# Get content from file or inline
|
|
73
|
+
if content_file:
|
|
74
|
+
template_content = content_file.read_text()
|
|
75
|
+
else:
|
|
76
|
+
template_content = content or ""
|
|
77
|
+
|
|
78
|
+
if not template_content.strip():
|
|
79
|
+
raise typer.BadParameter("Template content cannot be empty")
|
|
80
|
+
|
|
81
|
+
# Parse tags
|
|
82
|
+
tag_paths: list[str] | None = None
|
|
83
|
+
if clear_tags:
|
|
84
|
+
tag_paths = []
|
|
85
|
+
elif tags:
|
|
86
|
+
tag_paths = parse_tags(tags)
|
|
87
|
+
|
|
88
|
+
# Build request
|
|
89
|
+
request = CreateTemplateVersionRequest(
|
|
90
|
+
content=template_content,
|
|
91
|
+
tag_paths=tag_paths,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
_resolve_and_create_version(template_identifier, request)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@async_command
|
|
98
|
+
async def _resolve_and_create_version(
|
|
99
|
+
template_identifier: str, request: CreateTemplateVersionRequest
|
|
100
|
+
) -> None:
|
|
101
|
+
"""Resolve template identifier and create version."""
|
|
102
|
+
from alloy_runtime_sdk.exceptions.errors import NotFoundError
|
|
103
|
+
|
|
104
|
+
async with authenticated_client() as (_config, client):
|
|
105
|
+
try:
|
|
106
|
+
template_data = await client.get_template(template_identifier)
|
|
107
|
+
except NotFoundError:
|
|
108
|
+
raise typer.BadParameter(
|
|
109
|
+
f"Template '{template_identifier}' not found. Use 'ai templates list' to see available templates."
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
response = await client.create_template_version(
|
|
113
|
+
template_data.template.id, request
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
present_version_create_success(response)
|