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,129 @@
|
|
|
1
|
+
"""Presenter for schema get command output."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
from rich.text import Text
|
|
10
|
+
|
|
11
|
+
from cli.infrastructure.formatting.fields import (
|
|
12
|
+
format_datetime,
|
|
13
|
+
format_optional,
|
|
14
|
+
format_uuid,
|
|
15
|
+
)
|
|
16
|
+
from alloy_runtime_types.dtos.schemas import GetSchemaResponse
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _derive_scope(response: GetSchemaResponse) -> str:
|
|
20
|
+
"""Derive scope string from organization_id and user_id fields.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
response: Schema response from server
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Scope string: user, organization, or global
|
|
27
|
+
"""
|
|
28
|
+
if response.organization_id is not None and response.user_id is None:
|
|
29
|
+
return "organization"
|
|
30
|
+
elif response.user_id is not None:
|
|
31
|
+
return "user"
|
|
32
|
+
else:
|
|
33
|
+
return "global"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _format_definition_for_display(
|
|
37
|
+
schema_format_id: str, schema_definition: str
|
|
38
|
+
) -> str:
|
|
39
|
+
"""Format schema definition for display.
|
|
40
|
+
|
|
41
|
+
JSON schemas are pretty-printed, regex patterns shown as-is.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
schema_format_id: Format type (json_schema, regex)
|
|
45
|
+
schema_definition: The schema definition string
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Formatted definition string
|
|
49
|
+
"""
|
|
50
|
+
if schema_format_id == "json_schema":
|
|
51
|
+
try:
|
|
52
|
+
# Parse and pretty-print JSON
|
|
53
|
+
parsed = json.loads(schema_definition)
|
|
54
|
+
return json.dumps(parsed, indent=2, ensure_ascii=False)
|
|
55
|
+
except (json.JSONDecodeError, TypeError):
|
|
56
|
+
# If parsing fails, return as-is
|
|
57
|
+
return schema_definition
|
|
58
|
+
else:
|
|
59
|
+
# Regex or other formats - return as-is
|
|
60
|
+
return schema_definition
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def present_schema_details(response: GetSchemaResponse) -> None:
|
|
64
|
+
"""Present schema details with Rich formatting.
|
|
65
|
+
|
|
66
|
+
Metadata goes to stderr (visible in terminal but not piped).
|
|
67
|
+
Schema definition goes to stdout (for piping to other commands).
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
response: GetSchemaResponse from server
|
|
71
|
+
"""
|
|
72
|
+
# Create console for stderr output (metadata)
|
|
73
|
+
stderr_console = Console(file=sys.stderr, force_terminal=True)
|
|
74
|
+
|
|
75
|
+
# Print success message to stderr
|
|
76
|
+
stderr_console.print(
|
|
77
|
+
f"[green]✓[/green] Schema retrieved: {response.schema_name} (v{response.version})"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Build metadata table
|
|
81
|
+
metadata_table = Table(show_header=False, box=None, padding=(0, 1))
|
|
82
|
+
metadata_table.add_column("Field", style="dim", width=20)
|
|
83
|
+
metadata_table.add_column("Value")
|
|
84
|
+
|
|
85
|
+
metadata_table.add_row("ID", format_uuid(response.id, short=False))
|
|
86
|
+
metadata_table.add_row("Name", response.schema_name)
|
|
87
|
+
metadata_table.add_row("Format", response.schema_format_id)
|
|
88
|
+
metadata_table.add_row("Version", str(response.version))
|
|
89
|
+
metadata_table.add_row("Description", format_optional(response.description))
|
|
90
|
+
metadata_table.add_row("Scope", _derive_scope(response))
|
|
91
|
+
metadata_table.add_row("Is Latest", "Yes" if response.is_latest else "No")
|
|
92
|
+
metadata_table.add_row(
|
|
93
|
+
"Organization ID",
|
|
94
|
+
format_optional(response.organization_id, lambda x: format_uuid(x, short=True)),
|
|
95
|
+
)
|
|
96
|
+
metadata_table.add_row(
|
|
97
|
+
"User ID",
|
|
98
|
+
format_optional(response.user_id, lambda x: format_uuid(x, short=True)),
|
|
99
|
+
)
|
|
100
|
+
metadata_table.add_row("Created At", format_datetime(response.created_at))
|
|
101
|
+
|
|
102
|
+
# Display metadata panel to stderr
|
|
103
|
+
metadata_panel = Panel(
|
|
104
|
+
metadata_table,
|
|
105
|
+
title=f"Schema: {response.schema_name}",
|
|
106
|
+
border_style="blue",
|
|
107
|
+
)
|
|
108
|
+
stderr_console.print(metadata_panel)
|
|
109
|
+
|
|
110
|
+
# Format and display definition to stdout for piping
|
|
111
|
+
formatted_definition = _format_definition_for_display(
|
|
112
|
+
response.schema_format_id, response.schema_definition
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Also show definition preview in a panel to stderr
|
|
116
|
+
preview_text = (
|
|
117
|
+
formatted_definition
|
|
118
|
+
if len(formatted_definition) <= 500
|
|
119
|
+
else formatted_definition[:500] + "\n... (truncated in preview)"
|
|
120
|
+
)
|
|
121
|
+
definition_panel = Panel(
|
|
122
|
+
Text(preview_text, style="dim"),
|
|
123
|
+
title=f"Schema Definition Preview ({response.schema_format_id})",
|
|
124
|
+
border_style="green",
|
|
125
|
+
)
|
|
126
|
+
stderr_console.print(definition_panel)
|
|
127
|
+
|
|
128
|
+
# Print full definition to stdout for piping
|
|
129
|
+
print(formatted_definition, file=sys.stdout)
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Schemas list command implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from cli.commands.schemas.list.presenter import present_schemas_list
|
|
8
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def schemas_list_command(
|
|
12
|
+
search: Optional[str] = typer.Option(
|
|
13
|
+
None,
|
|
14
|
+
"-s",
|
|
15
|
+
"--search",
|
|
16
|
+
help="Fuzzy search terms",
|
|
17
|
+
),
|
|
18
|
+
schema_format: Optional[str] = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--schema-format",
|
|
21
|
+
help="Filter: json_schema or regex",
|
|
22
|
+
),
|
|
23
|
+
limit: int = typer.Option(
|
|
24
|
+
50,
|
|
25
|
+
"-l",
|
|
26
|
+
"--limit",
|
|
27
|
+
min=1,
|
|
28
|
+
max=100,
|
|
29
|
+
help="Max results",
|
|
30
|
+
),
|
|
31
|
+
offset: int = typer.Option(
|
|
32
|
+
0,
|
|
33
|
+
"--offset",
|
|
34
|
+
min=0,
|
|
35
|
+
help="Skip N results",
|
|
36
|
+
),
|
|
37
|
+
) -> None:
|
|
38
|
+
"""List schemas.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
ai schemas list
|
|
42
|
+
ai schemas list -s "user profile"
|
|
43
|
+
ai schemas list --schema-format json_schema
|
|
44
|
+
ai schemas list -l 20
|
|
45
|
+
"""
|
|
46
|
+
_execute_list(
|
|
47
|
+
search=search, schema_format=schema_format, limit=limit, offset=offset
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@async_command
|
|
52
|
+
async def _execute_list(
|
|
53
|
+
search: Optional[str], schema_format: Optional[str], limit: int, offset: int
|
|
54
|
+
) -> None:
|
|
55
|
+
"""Execute list schemas operation."""
|
|
56
|
+
async with authenticated_client() as (_config, client):
|
|
57
|
+
response = await client.list_schemas(
|
|
58
|
+
search=search,
|
|
59
|
+
schema_format=schema_format,
|
|
60
|
+
limit=limit,
|
|
61
|
+
offset=offset,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
present_schemas_list(response)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Presenter for schemas list command output."""
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
from alloy_runtime_types.dtos.schemas import ListSchemasResponse, SchemaSummary
|
|
5
|
+
|
|
6
|
+
from cli.infrastructure.scope_utils import format_scope_label
|
|
7
|
+
from cli.infrastructure.output import OutputService
|
|
8
|
+
from cli.infrastructure.renderers.list_renderer import ColumnConfig
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SchemaDisplay(BaseModel):
|
|
12
|
+
"""Schema with computed scope field for display."""
|
|
13
|
+
|
|
14
|
+
id: str = Field(..., description="Schema ID")
|
|
15
|
+
schema_name: str = Field(..., description="Schema name")
|
|
16
|
+
version: int = Field(..., description="Version number")
|
|
17
|
+
schema_format_id: str = Field(..., description="Format type")
|
|
18
|
+
description: str | None = Field(None, description="Description")
|
|
19
|
+
scope: str = Field(..., description="Ownership scope")
|
|
20
|
+
created_at: str = Field(..., description="Creation date")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _format_description(description: str | None) -> str:
|
|
24
|
+
"""Format description for display, truncating if too long.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
description: Optional description text
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Formatted description string
|
|
31
|
+
"""
|
|
32
|
+
if not description:
|
|
33
|
+
return "-"
|
|
34
|
+
if len(description) > 120:
|
|
35
|
+
return description[:117] + "..."
|
|
36
|
+
return description
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _transform_schema_for_display(schema: SchemaSummary) -> SchemaDisplay:
|
|
40
|
+
"""Transform schema summary into display model with computed fields.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
schema: Schema summary from API
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
SchemaDisplay with computed scope field
|
|
47
|
+
"""
|
|
48
|
+
return SchemaDisplay(
|
|
49
|
+
id=str(schema.id),
|
|
50
|
+
schema_name=schema.schema_name,
|
|
51
|
+
version=schema.version,
|
|
52
|
+
schema_format_id=schema.schema_format_id,
|
|
53
|
+
description=schema.description,
|
|
54
|
+
scope=format_scope_label(
|
|
55
|
+
str(schema.organization_id) if schema.organization_id else None,
|
|
56
|
+
str(schema.user_id) if schema.user_id else None,
|
|
57
|
+
),
|
|
58
|
+
created_at=schema.created_at.strftime("%Y-%m-%d") if schema.created_at else "-",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def present_schemas_list(response: ListSchemasResponse) -> None:
|
|
63
|
+
"""Present list of schemas with Rich table formatting.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
response: List schemas response from server
|
|
67
|
+
"""
|
|
68
|
+
output = OutputService.get()
|
|
69
|
+
|
|
70
|
+
if not response.schemas:
|
|
71
|
+
output.info("No schemas found")
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
# Transform schemas for display
|
|
75
|
+
display_items = [_transform_schema_for_display(s) for s in response.schemas]
|
|
76
|
+
|
|
77
|
+
# Define table columns with compact layout configuration
|
|
78
|
+
# Line 1 (primary): ID, version, format, scope, created - machine-readable data
|
|
79
|
+
# Line 2 (detail): Name, description - human-readable content
|
|
80
|
+
columns = [
|
|
81
|
+
ColumnConfig(
|
|
82
|
+
source_field="id",
|
|
83
|
+
header_label="ID",
|
|
84
|
+
compact_line=1,
|
|
85
|
+
compact_style="cyan",
|
|
86
|
+
),
|
|
87
|
+
ColumnConfig(
|
|
88
|
+
source_field="version",
|
|
89
|
+
header_label="Ver",
|
|
90
|
+
align="right",
|
|
91
|
+
formatter=lambda x: f"v{x}" if x else "-",
|
|
92
|
+
compact_line=1,
|
|
93
|
+
compact_style="yellow",
|
|
94
|
+
),
|
|
95
|
+
ColumnConfig(
|
|
96
|
+
source_field="schema_format_id",
|
|
97
|
+
header_label="Format",
|
|
98
|
+
compact_line=1,
|
|
99
|
+
compact_style="magenta",
|
|
100
|
+
),
|
|
101
|
+
ColumnConfig(
|
|
102
|
+
source_field="scope",
|
|
103
|
+
header_label="Scope",
|
|
104
|
+
compact_line=1,
|
|
105
|
+
compact_style="dim",
|
|
106
|
+
),
|
|
107
|
+
ColumnConfig(
|
|
108
|
+
source_field="created_at",
|
|
109
|
+
header_label="Created",
|
|
110
|
+
compact_line=1,
|
|
111
|
+
compact_style="blue",
|
|
112
|
+
),
|
|
113
|
+
ColumnConfig(
|
|
114
|
+
source_field="schema_name",
|
|
115
|
+
header_label="Name",
|
|
116
|
+
compact_line=2,
|
|
117
|
+
compact_style="white bold",
|
|
118
|
+
),
|
|
119
|
+
ColumnConfig(
|
|
120
|
+
source_field="description",
|
|
121
|
+
header_label="Description",
|
|
122
|
+
formatter=_format_description,
|
|
123
|
+
compact_line=2,
|
|
124
|
+
compact_style="dim",
|
|
125
|
+
),
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
# Render table
|
|
129
|
+
output.table(
|
|
130
|
+
items=display_items, # type: ignore[arg-type]
|
|
131
|
+
title=f"Schemas ({response.total})",
|
|
132
|
+
columns=columns,
|
|
133
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""Schema update command implementation."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
|
|
13
|
+
from cli.commands.shared_flags import CLEAR_DESCRIPTION, DESCRIPTION, FILE_INPUT
|
|
14
|
+
from cli.commands.schemas.update.presenter import present_schema_update_success
|
|
15
|
+
from cli.infrastructure.command import async_command, authenticated_client
|
|
16
|
+
from cli.infrastructure.file_content import FileContentError, resolve_content
|
|
17
|
+
from alloy_runtime_types.dtos.schemas import UpdateSchemaRequest
|
|
18
|
+
from alloy_runtime_sdk.exceptions.errors import NotFoundError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class EditorError(Exception):
|
|
22
|
+
"""Raised when editor operations fail."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _get_editor() -> str:
|
|
26
|
+
"""Get the user's preferred editor.
|
|
27
|
+
|
|
28
|
+
Checks in order:
|
|
29
|
+
1. $EDITOR environment variable
|
|
30
|
+
2. $VISUAL environment variable
|
|
31
|
+
3. Common editors on PATH (nano, vim, vi)
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Path/name of editor to use
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
EditorError: If no suitable editor is found
|
|
38
|
+
"""
|
|
39
|
+
# Check environment variables first
|
|
40
|
+
editor = os.environ.get("EDITOR") or os.environ.get("VISUAL")
|
|
41
|
+
if editor:
|
|
42
|
+
return editor
|
|
43
|
+
|
|
44
|
+
# Fall back to common editors
|
|
45
|
+
for fallback in ("nano", "vim", "vi"):
|
|
46
|
+
if shutil.which(fallback):
|
|
47
|
+
return fallback
|
|
48
|
+
|
|
49
|
+
raise EditorError(
|
|
50
|
+
"No editor found. Set $EDITOR environment variable or install nano/vim."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _open_editor_for_schema(initial_content: str, schema_format: str) -> str | None:
|
|
55
|
+
"""Open editor with schema-specific file extension for syntax highlighting.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
initial_content: Initial schema definition content
|
|
59
|
+
schema_format: Schema format ID (json_schema or regex)
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Edited content or None if editor failed
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
EditorError: If no editor is available
|
|
66
|
+
"""
|
|
67
|
+
editor = _get_editor()
|
|
68
|
+
|
|
69
|
+
# Choose file extension based on schema format
|
|
70
|
+
if schema_format == "json_schema":
|
|
71
|
+
suffix = ".json"
|
|
72
|
+
# Pretty-print JSON for better editing experience
|
|
73
|
+
try:
|
|
74
|
+
parsed = json.loads(initial_content)
|
|
75
|
+
initial_content = json.dumps(parsed, indent=2, ensure_ascii=False)
|
|
76
|
+
except (json.JSONDecodeError, TypeError):
|
|
77
|
+
# If parsing fails, use as-is
|
|
78
|
+
pass
|
|
79
|
+
else:
|
|
80
|
+
# Regex pattern
|
|
81
|
+
suffix = ".txt"
|
|
82
|
+
|
|
83
|
+
# Create temp file
|
|
84
|
+
with tempfile.NamedTemporaryFile(
|
|
85
|
+
mode="w",
|
|
86
|
+
suffix=suffix,
|
|
87
|
+
delete=False,
|
|
88
|
+
) as f:
|
|
89
|
+
f.write(initial_content)
|
|
90
|
+
temp_path = Path(f.name)
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
# Get file modification time before editing
|
|
94
|
+
mtime_before = temp_path.stat().st_mtime
|
|
95
|
+
|
|
96
|
+
# Open editor and wait for it to close
|
|
97
|
+
editor_parts = editor.split()
|
|
98
|
+
cmd = editor_parts + [str(temp_path)]
|
|
99
|
+
|
|
100
|
+
result = subprocess.call(cmd)
|
|
101
|
+
|
|
102
|
+
if result != 0:
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
# Check if file was modified
|
|
106
|
+
mtime_after = temp_path.stat().st_mtime
|
|
107
|
+
if mtime_after == mtime_before:
|
|
108
|
+
# File wasn't modified - still return content in case no changes needed
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
# Read the edited content
|
|
112
|
+
content = temp_path.read_text()
|
|
113
|
+
return content
|
|
114
|
+
|
|
115
|
+
finally:
|
|
116
|
+
# Clean up temp file
|
|
117
|
+
try:
|
|
118
|
+
temp_path.unlink()
|
|
119
|
+
except OSError:
|
|
120
|
+
pass # Best effort cleanup
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def schemas_update_command(
|
|
124
|
+
schema: str = typer.Argument(..., help="Schema name or UUID"),
|
|
125
|
+
# Metadata fields
|
|
126
|
+
description: Optional[str] = DESCRIPTION,
|
|
127
|
+
# Definition fields
|
|
128
|
+
definition: Optional[str] = typer.Option(
|
|
129
|
+
None,
|
|
130
|
+
"-D",
|
|
131
|
+
"--definition",
|
|
132
|
+
help="Schema definition (or @file)",
|
|
133
|
+
),
|
|
134
|
+
definition_file: Optional[Path] = FILE_INPUT,
|
|
135
|
+
# Clear flags
|
|
136
|
+
clear_description: bool = CLEAR_DESCRIPTION,
|
|
137
|
+
) -> None:
|
|
138
|
+
"""Update an existing schema.
|
|
139
|
+
|
|
140
|
+
By default, opens interactive editor. Use flags for non-interactive mode.
|
|
141
|
+
Name and format cannot be changed.
|
|
142
|
+
|
|
143
|
+
Examples:
|
|
144
|
+
|
|
145
|
+
# Interactive (default)
|
|
146
|
+
ai schemas update my-schema
|
|
147
|
+
|
|
148
|
+
# Update description
|
|
149
|
+
ai schemas update my-schema -d "New description"
|
|
150
|
+
|
|
151
|
+
# Update definition from file
|
|
152
|
+
ai schemas update my-schema -f schema.json
|
|
153
|
+
|
|
154
|
+
# Update definition inline
|
|
155
|
+
ai schemas update my-schema -D '{"type": "object", ...}'
|
|
156
|
+
"""
|
|
157
|
+
# Validate definition source - can't have both file and inline
|
|
158
|
+
if definition_file is not None and definition is not None:
|
|
159
|
+
raise typer.BadParameter("Cannot specify both --file and --definition")
|
|
160
|
+
|
|
161
|
+
# Validate clear flags
|
|
162
|
+
if clear_description and description is not None:
|
|
163
|
+
raise typer.BadParameter(
|
|
164
|
+
"Cannot specify both --description and --clear-description"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# Check if any flags were provided (non-interactive mode)
|
|
168
|
+
has_flags = any(
|
|
169
|
+
[
|
|
170
|
+
description is not None,
|
|
171
|
+
definition is not None,
|
|
172
|
+
definition_file is not None,
|
|
173
|
+
clear_description,
|
|
174
|
+
]
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if has_flags:
|
|
178
|
+
# Non-interactive mode - execute with provided flags
|
|
179
|
+
_execute_update_non_interactive(
|
|
180
|
+
schema_identifier=schema,
|
|
181
|
+
description=description,
|
|
182
|
+
definition=definition,
|
|
183
|
+
definition_file=definition_file,
|
|
184
|
+
clear_description=clear_description,
|
|
185
|
+
)
|
|
186
|
+
else:
|
|
187
|
+
# Interactive mode - fetch current data and launch editor
|
|
188
|
+
_execute_update_interactive(schema_identifier=schema)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _execute_update_interactive(schema_identifier: str) -> None:
|
|
192
|
+
"""Launch interactive editor for updating schema.
|
|
193
|
+
|
|
194
|
+
This function is synchronous because editor operations are blocking.
|
|
195
|
+
We use asyncio.run() just for the initial schema fetch, then
|
|
196
|
+
run the editor synchronously.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
schema_identifier: Schema name or UUID
|
|
200
|
+
|
|
201
|
+
Raises:
|
|
202
|
+
ConfigurationError: If environment variables are missing
|
|
203
|
+
AuthenticationError: If API key is invalid
|
|
204
|
+
NotFoundError: If schema doesn't exist
|
|
205
|
+
ServerError: If server returns 5xx error
|
|
206
|
+
"""
|
|
207
|
+
import asyncio
|
|
208
|
+
|
|
209
|
+
from cli.infrastructure.error_display import display_error
|
|
210
|
+
from cli.infrastructure.output import OutputService
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
# Fetch current schema data (async operation, run in its own event loop)
|
|
214
|
+
async def fetch_schema():
|
|
215
|
+
async with authenticated_client() as (_, client):
|
|
216
|
+
return await client.get_schema(schema_identifier)
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
current_data = asyncio.run(fetch_schema())
|
|
220
|
+
except NotFoundError:
|
|
221
|
+
raise typer.BadParameter(
|
|
222
|
+
f"Schema '{schema_identifier}' not found. "
|
|
223
|
+
"Use 'ai schemas list' to see available schemas."
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
output = OutputService.get()
|
|
227
|
+
|
|
228
|
+
# Show current schema info
|
|
229
|
+
output.info(
|
|
230
|
+
f"Schema: {current_data.schema_name} (v{current_data.version})\n"
|
|
231
|
+
f"Format: {current_data.schema_format_id}\n"
|
|
232
|
+
f"Description: {current_data.description or '(none)'}"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Open editor with current definition
|
|
236
|
+
with output.console.status(
|
|
237
|
+
f"Opening editor for {current_data.schema_name}...", spinner="dots"
|
|
238
|
+
):
|
|
239
|
+
pass # Just show briefly before opening editor
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
edited_content = _open_editor_for_schema(
|
|
243
|
+
initial_content=current_data.schema_definition,
|
|
244
|
+
schema_format=current_data.schema_format_id,
|
|
245
|
+
)
|
|
246
|
+
except EditorError as e:
|
|
247
|
+
raise typer.BadParameter(str(e))
|
|
248
|
+
|
|
249
|
+
if edited_content is None:
|
|
250
|
+
output.warning("Editor exited with error. Update cancelled.")
|
|
251
|
+
raise typer.Exit(code=0)
|
|
252
|
+
|
|
253
|
+
# Check if definition was modified
|
|
254
|
+
definition_changed = (
|
|
255
|
+
edited_content.strip() != current_data.schema_definition.strip()
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if not definition_changed:
|
|
259
|
+
output.info("No changes to schema definition. Update cancelled.")
|
|
260
|
+
raise typer.Exit(code=0)
|
|
261
|
+
|
|
262
|
+
# Prompt for description update
|
|
263
|
+
output.info("\nSchema definition has been modified.")
|
|
264
|
+
update_description = typer.confirm(
|
|
265
|
+
"Do you want to update the description as well?",
|
|
266
|
+
default=False,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
new_description: Optional[str] = None
|
|
270
|
+
if update_description:
|
|
271
|
+
new_description = typer.prompt(
|
|
272
|
+
"Enter new description (leave empty to clear)",
|
|
273
|
+
default=current_data.description or "",
|
|
274
|
+
)
|
|
275
|
+
# Empty string means clear (strip to handle whitespace-only input)
|
|
276
|
+
if new_description and not new_description.strip():
|
|
277
|
+
new_description = ""
|
|
278
|
+
|
|
279
|
+
# Build request
|
|
280
|
+
request = UpdateSchemaRequest(
|
|
281
|
+
schema_definition=edited_content.strip(),
|
|
282
|
+
description=new_description,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Execute update via API
|
|
286
|
+
async def update_schema():
|
|
287
|
+
async with authenticated_client() as (_, client):
|
|
288
|
+
# Resolve to UUID (server only accepts UUID for update)
|
|
289
|
+
return await client.update_schema(current_data.id, request)
|
|
290
|
+
|
|
291
|
+
response = asyncio.run(update_schema())
|
|
292
|
+
|
|
293
|
+
# Present success output
|
|
294
|
+
present_schema_update_success(response)
|
|
295
|
+
|
|
296
|
+
except typer.Exit:
|
|
297
|
+
# Re-raise Exit exceptions (don't treat as errors)
|
|
298
|
+
raise
|
|
299
|
+
except Exception as e:
|
|
300
|
+
display_error(e)
|
|
301
|
+
raise typer.Exit(code=1)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
@async_command
|
|
305
|
+
async def _execute_update_non_interactive(
|
|
306
|
+
schema_identifier: str,
|
|
307
|
+
description: Optional[str],
|
|
308
|
+
definition: Optional[str],
|
|
309
|
+
definition_file: Optional[Path],
|
|
310
|
+
clear_description: bool,
|
|
311
|
+
) -> None:
|
|
312
|
+
"""Execute the schema update operation in non-interactive mode.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
schema_identifier: Schema name or UUID
|
|
316
|
+
description: Optional new description
|
|
317
|
+
definition: Optional new definition (inline or @file)
|
|
318
|
+
definition_file: Optional definition file path
|
|
319
|
+
clear_description: If True, clear the description
|
|
320
|
+
|
|
321
|
+
Raises:
|
|
322
|
+
ConfigurationError: If environment variables are missing
|
|
323
|
+
AuthenticationError: If API key is invalid
|
|
324
|
+
NotFoundError: If schema doesn't exist
|
|
325
|
+
ValidationError: If update data is invalid
|
|
326
|
+
ServerError: If server returns 5xx error
|
|
327
|
+
"""
|
|
328
|
+
# Resolve content from @file references
|
|
329
|
+
try:
|
|
330
|
+
definition = resolve_content(definition)
|
|
331
|
+
except FileContentError as e:
|
|
332
|
+
raise typer.BadParameter(str(e))
|
|
333
|
+
|
|
334
|
+
# Get definition from file if specified
|
|
335
|
+
schema_definition: Optional[str] = None
|
|
336
|
+
if definition_file is not None:
|
|
337
|
+
schema_definition = definition_file.read_text()
|
|
338
|
+
elif definition is not None:
|
|
339
|
+
schema_definition = definition
|
|
340
|
+
|
|
341
|
+
# Handle description
|
|
342
|
+
final_description: Optional[str] = description
|
|
343
|
+
if clear_description:
|
|
344
|
+
final_description = ""
|
|
345
|
+
|
|
346
|
+
# Build update request - only include fields that were explicitly provided
|
|
347
|
+
request = UpdateSchemaRequest(
|
|
348
|
+
description=final_description
|
|
349
|
+
if (description is not None or clear_description)
|
|
350
|
+
else None,
|
|
351
|
+
schema_definition=schema_definition,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Execute API call with authenticated client
|
|
355
|
+
async with authenticated_client() as (_config, client):
|
|
356
|
+
# First resolve schema identifier to get UUID and current data
|
|
357
|
+
try:
|
|
358
|
+
schema_data = await client.get_schema(schema_identifier)
|
|
359
|
+
except NotFoundError:
|
|
360
|
+
raise typer.BadParameter(
|
|
361
|
+
f"Schema '{schema_identifier}' not found. "
|
|
362
|
+
"Use 'ai schemas list' to see available schemas."
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
# Execute update (server requires UUID)
|
|
366
|
+
response = await client.update_schema(schema_data.id, request)
|
|
367
|
+
|
|
368
|
+
# Present success output
|
|
369
|
+
present_schema_update_success(response)
|