thestage 0.6.5__tar.gz → 0.6.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. {thestage-0.6.5 → thestage-0.6.7}/PKG-INFO +4 -2
  2. {thestage-0.6.5 → thestage-0.6.7}/pyproject.toml +2 -1
  3. {thestage-0.6.5 → thestage-0.6.7}/thestage/__init__.py +1 -1
  4. {thestage-0.6.5 → thestage-0.6.7}/thestage/color_scheme/color_scheme.py +1 -0
  5. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/base_controller.py +4 -3
  6. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/config_controller.py +16 -4
  7. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/container_controller.py +151 -106
  8. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/instance_controller.py +35 -9
  9. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/project_controller.py +335 -89
  10. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/container.py +5 -3
  11. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/project_inference_simulator.py +2 -1
  12. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/project_inference_simulator_model.py +2 -2
  13. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/project_task.py +2 -3
  14. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/rented_instance.py +2 -2
  15. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/self_hosted_instance.py +2 -2
  16. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/error_handler.py +1 -1
  17. {thestage-0.6.5 → thestage-0.6.7}/thestage/main.py +1 -1
  18. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/git/git_client.py +1 -1
  19. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/api_client.py +142 -109
  20. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/base_controller/connect_resolve_response.py +22 -0
  21. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/container_param_request.py +1 -1
  22. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/container_response.py +1 -21
  23. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +2 -1
  24. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +5 -1
  25. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +2 -1
  26. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +1 -0
  27. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +2 -1
  28. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_request.py → thestage-0.6.7/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_request.py +3 -2
  29. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_response.py → thestage-0.6.7/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_response.py +1 -1
  30. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +2 -1
  31. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/instance_rented_response.py +38 -0
  32. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +3 -3
  33. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +13 -0
  34. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +1 -0
  35. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +2 -1
  36. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +2 -4
  37. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +3 -0
  38. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +16 -0
  39. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/project_response.py +20 -0
  40. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +2 -20
  41. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +1 -1
  42. thestage-0.6.7/thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +10 -0
  43. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +1 -1
  44. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +4 -1
  45. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +0 -2
  46. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/config_provider/config_provider.py +2 -2
  47. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/connect/connect_service.py +77 -74
  48. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/container/container_service.py +120 -41
  49. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/container/mapper/container_mapper.py +2 -1
  50. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/instance/instance_service.py +13 -20
  51. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/instance/mapper/instance_mapper.py +1 -3
  52. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/instance/mapper/selfhosted_mapper.py +3 -4
  53. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/logging_service.py +45 -48
  54. thestage-0.6.7/thestage/services/project/dto/inference_simulator_dto.py +14 -0
  55. thestage-0.6.7/thestage/services/project/dto/inference_simulator_model_dto.py +13 -0
  56. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/dto/project_config.py +2 -2
  57. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/mapper/project_inference_simulator_mapper.py +1 -0
  58. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/mapper/project_inference_simulator_model_mapper.py +2 -2
  59. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/mapper/project_task_mapper.py +2 -3
  60. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/project_service.py +174 -140
  61. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/remote_server_service.py +1 -0
  62. thestage-0.6.7/thestage/services/task/dto/task_dto.py +20 -0
  63. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +0 -19
  64. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +0 -10
  65. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/currency_type.py +0 -10
  66. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +0 -9
  67. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/disk_type.py +0 -7
  68. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/drive_type.py +0 -7
  69. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/instance_type.py +0 -7
  70. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/location_region.py +0 -11
  71. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/enums/power_status.py +0 -10
  72. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/instance_rented_response.py +0 -71
  73. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +0 -21
  74. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/price_definition.py +0 -14
  75. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +0 -14
  76. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/project_response.py +0 -32
  77. thestage-0.6.5/thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +0 -8
  78. thestage-0.6.5/thestage/services/project/dto/inference_simulator_dto.py +0 -23
  79. thestage-0.6.5/thestage/services/project/dto/inference_simulator_model_dto.py +0 -21
  80. thestage-0.6.5/thestage/services/task/dto/task_dto.py +0 -40
  81. {thestage-0.6.5 → thestage-0.6.7}/LICENSE.txt +0 -0
  82. {thestage-0.6.5 → thestage-0.6.7}/README.md +0 -0
  83. {thestage-0.6.5 → thestage-0.6.7}/thestage/.env +0 -0
  84. {thestage-0.6.5 → thestage-0.6.7}/thestage/__main__.py +0 -0
  85. {thestage-0.6.5 → thestage-0.6.7}/thestage/cli_command.py +0 -0
  86. {thestage-0.6.5 → thestage-0.6.7}/thestage/cli_command_helper.py +0 -0
  87. {thestage-0.6.5 → thestage-0.6.7}/thestage/config/__init__.py +0 -0
  88. {thestage-0.6.5 → thestage-0.6.7}/thestage/config/config_storage.py +0 -0
  89. {thestage-0.6.5 → thestage-0.6.7}/thestage/config/env_base.py +0 -0
  90. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/__init__.py +0 -0
  91. {thestage-0.6.5 → thestage-0.6.7}/thestage/controllers/utils_controller.py +0 -0
  92. {thestage-0.6.5 → thestage-0.6.7}/thestage/debug_main.dist.py +0 -0
  93. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/__init__.py +0 -0
  94. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/enums/__init__.py +0 -0
  95. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/enums/order_direction_type.py +0 -0
  96. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/enums/shell_type.py +0 -0
  97. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/enums/tail_output_type.py +0 -0
  98. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/enums/yes_no_response.py +0 -0
  99. {thestage-0.6.5 → thestage-0.6.7}/thestage/entities/file_item.py +0 -0
  100. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/__init__.py +0 -0
  101. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/auth_exception.py +0 -0
  102. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/base_exception.py +0 -0
  103. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/business_logic_exception.py +0 -0
  104. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/config_exception.py +0 -0
  105. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/file_system_exception.py +0 -0
  106. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/git_access_exception.py +0 -0
  107. {thestage-0.6.5 → thestage-0.6.7}/thestage/exceptions/remote_server_exception.py +0 -0
  108. {thestage-0.6.5 → thestage-0.6.7}/thestage/git/ProgressPrinter.py +0 -0
  109. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/__init__.py +0 -0
  110. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/exception_hook.py +0 -0
  111. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/logger/__init__.py +0 -0
  112. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/logger/app_logger.py +0 -0
  113. {thestage-0.6.5 → thestage-0.6.7}/thestage/helpers/ssh_util.py +0 -0
  114. {thestage-0.6.5 → thestage-0.6.7}/thestage/i18n/en_GB/messages.po +0 -0
  115. {thestage-0.6.5 → thestage-0.6.7}/thestage/i18n/translation.py +0 -0
  116. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/.env +0 -0
  117. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/__init__.py +0 -0
  118. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/abstract_mapper.py +0 -0
  119. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/abstract_service.py +0 -0
  120. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/app_config_service.py +0 -0
  121. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/__init__.py +0 -0
  122. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/git/__init__.py +0 -0
  123. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/__init__.py +0 -0
  124. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/core/api_client_core.py +0 -0
  125. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/core/http_client_exception.py +0 -0
  126. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/__init__.py +0 -0
  127. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/base_response.py +0 -0
  128. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_response.py +0 -0
  129. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/docker_container_mapping.py +0 -0
  130. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/entity_filter_request.py +0 -0
  131. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/__init__.py +0 -0
  132. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/container_pending_action.py +0 -0
  133. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/container_status.py +0 -0
  134. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/cpu_type.py +0 -0
  135. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/gpu_name.py +0 -0
  136. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/inference_model_status.py +0 -0
  137. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/inference_simulator_status.py +0 -0
  138. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/instance_rented_status.py +0 -0
  139. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/provider_name.py +0 -0
  140. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/selfhosted_status.py +0 -0
  141. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/task_execution_status.py +0 -0
  142. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/enums/task_status.py +0 -0
  143. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/frontend_status.py +0 -0
  144. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_response.py +0 -0
  145. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -0
  146. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_response.py +0 -0
  147. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +0 -0
  148. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +0 -0
  149. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/installed_service.py +0 -0
  150. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/instance_detected_gpus.py +0 -0
  151. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/logging_controller/docker_container_log_stream_request.py +0 -0
  152. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_response.py +0 -0
  153. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/logging_controller/task_log_stream_request.py +0 -0
  154. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_response.py +0 -0
  155. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/paginated_entity_list.py +0 -0
  156. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/pagination_data.py +0 -0
  157. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py +0 -0
  158. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py +0 -0
  159. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -0
  160. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +0 -0
  161. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_request.py +0 -0
  162. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_response.py +0 -0
  163. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_request.py +0 -0
  164. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py +0 -0
  165. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +0 -0
  166. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -0
  167. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/clients/thestage_api/dtos/validate_token_response.py +0 -0
  168. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/config_provider/__init__.py +0 -0
  169. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/connect/dto/remote_server_config.py +0 -0
  170. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/container/__init__.py +0 -0
  171. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/container/mapper/__init__.py +0 -0
  172. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/core_files/config_entity.py +0 -0
  173. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/filesystem_service.py +0 -0
  174. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/instance/__init__.py +0 -0
  175. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/instance/mapper/__init__.py +0 -0
  176. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/byte_print_style.py +0 -0
  177. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/dto/log_message.py +0 -0
  178. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/dto/log_type.py +0 -0
  179. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/exception/log_polling_exception.py +0 -0
  180. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/logging/logging_constants.py +0 -0
  181. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/__init__.py +0 -0
  182. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/project/mapper/__init__.py +0 -0
  183. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/service_factory.py +0 -0
  184. {thestage-0.6.5 → thestage-0.6.7}/thestage/services/validation_service.py +0 -0
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: thestage
3
- Version: 0.6.5
3
+ Version: 0.6.7
4
4
  Summary:
5
+ License-File: LICENSE.txt
5
6
  Author: TheStage AI team
6
7
  Author-email: hello@thestage.ai
7
8
  Requires-Python: >=3.9,<=3.13
@@ -20,6 +21,7 @@ Requires-Dist: pydantic (>=2.4.2,<3.0.0)
20
21
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
21
22
  Requires-Dist: python-gettext-translations (>=1.1.0,<2.0.0)
22
23
  Requires-Dist: requests (>=2.31.0,<3.0.0)
24
+ Requires-Dist: rich (>=14.2.0,<15.0.0)
23
25
  Requires-Dist: tabulate (>=0.9.0,<0.10.0)
24
26
  Requires-Dist: typer[all] (>=0.15.2,<0.16.0)
25
27
  Description-Content-Type: text/markdown
@@ -1,7 +1,7 @@
1
1
  [tool.poetry]
2
2
  name = "thestage"
3
3
 
4
- version = "0.6.5"
4
+ version = "0.6.7"
5
5
 
6
6
  description = ""
7
7
  authors = ["TheStage AI team <hello@thestage.ai>"]
@@ -34,6 +34,7 @@ paramiko = "^3.5.1"
34
34
  aioconsole = "^0.8.0"
35
35
  httpx = "^0.27.2"
36
36
  boto3 = "^1.35.80"
37
+ rich = "^14.2.0"
37
38
 
38
39
  [tool.poetry.dev-dependencies]
39
40
  pytest = "^7.4.3"
@@ -1,3 +1,3 @@
1
1
  from . import *
2
2
  __app_name__ = "thestage"
3
- __version__ = "0.6.5"
3
+ __version__ = "0.6.7"
@@ -5,3 +5,4 @@ class ColorScheme(str, Enum):
5
5
  GIT_HEADLESS = "orange_red1"
6
6
  WARNING = "orange_red1"
7
7
  USEFUL_INFO = "deep_sky_blue1"
8
+ SUCCESS = "green"
@@ -27,8 +27,9 @@ def version():
27
27
 
28
28
  @app.command(name="connect", no_args_is_help=True, help=__("Connect to server instance or container or task"), **get_command_metadata(CliCommand.CONNECT))
29
29
  def connect(
30
- uid: Optional[str] = typer.Argument(
31
- help=__("Unique ID of server instance or container or task ID"), ),
30
+ entity_identifier: Optional[str] = typer.Argument(
31
+ help="Name or ID of server instance or container or task",
32
+ ),
32
33
  username: Optional[str] = typer.Option(
33
34
  None,
34
35
  '--username',
@@ -57,7 +58,7 @@ def connect(
57
58
  connect_service: ConnectService = service_factory.get_connect_service()
58
59
 
59
60
  connect_service.connect_to_entity(
60
- uid=uid,
61
+ input_entity_identifier=entity_identifier,
61
62
  username=username,
62
63
  private_key_path=private_ssh_key_path
63
64
  )
@@ -85,13 +85,20 @@ def config_clear():
85
85
  @app.command(name='upload-ssh-key', no_args_is_help=True, help=__("Send your public SSH key to the platform and / or rented server instance"), **get_command_metadata(CliCommand.CONFIG_UPLOAD_SSH_KEY))
86
86
  def upload_ssh_key(
87
87
  ssh_public_key: str = typer.Argument(
88
- help=__("Path to your public SSH key file or your public SSH key contents"),
88
+ help=__("Path to your public SSH key file or your public SSH key contents. OpenSSH key format is required."),
89
+ ),
90
+ instance_rented_public_id: str = typer.Option(
91
+ None,
92
+ "--instance-rented-id",
93
+ "-rid",
94
+ help=__("ID of your rented instance to add the key to (optional)"),
95
+ is_eager=False,
89
96
  ),
90
97
  instance_rented_slug: str = typer.Option(
91
98
  None,
92
- "--instance-uid",
93
- "-uid",
94
- help=__("Unique ID of your rented instance to add the key to (optional)"),
99
+ "--instance-rented-name",
100
+ "-rn",
101
+ help=__("Name of your rented instance to add the key to (optional)"),
95
102
  is_eager=False,
96
103
  )
97
104
  ):
@@ -99,6 +106,10 @@ def upload_ssh_key(
99
106
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
100
107
  check_command_permission(command_name)
101
108
 
109
+ if sum(v is not None for v in [instance_rented_public_id, instance_rented_slug]) > 1:
110
+ typer.echo("Please provide a single identifier for rented instance - ID or name.")
111
+ raise typer.Exit(1)
112
+
102
113
  service_factory = ServiceFactory()
103
114
  connect_service: ConnectService = service_factory.get_connect_service()
104
115
 
@@ -131,6 +142,7 @@ def upload_ssh_key(
131
142
 
132
143
  connect_service.upload_ssh_key(
133
144
  public_key_contents=ssh_key_contents,
145
+ instance_public_id=instance_rented_public_id,
134
146
  instance_slug=instance_rented_slug,
135
147
  )
136
148
 
@@ -2,9 +2,12 @@
2
2
  import re
3
3
  from pathlib import Path
4
4
  from typing import Optional, List
5
+ from rich import print
5
6
 
6
7
  from thestage.cli_command import CliCommand
7
8
  from thestage.cli_command_helper import get_command_metadata, check_command_permission
9
+ from thestage.color_scheme.color_scheme import ColorScheme
10
+ from thestage.services.clients.thestage_api.api_client import TheStageApiClient
8
11
  from thestage.services.clients.thestage_api.dtos.enums.container_pending_action import DockerContainerAction
9
12
  from thestage.services.clients.thestage_api.dtos.container_response import DockerContainerDto
10
13
  from thestage.i18n.translation import __
@@ -35,11 +38,18 @@ def list_containers(
35
38
  help=__("Set starting page for displaying output"),
36
39
  is_eager=False,
37
40
  ),
38
- project_uid: str = typer.Option(
41
+ project_public_id: str = typer.Option(
39
42
  None,
40
- '--project-uid',
41
- '-puid',
42
- help=__("Filter containers by project unique ID"),
43
+ '--project-id',
44
+ '-pid',
45
+ help=__("Filter containers by project, using the project's ID"),
46
+ is_eager=False,
47
+ ),
48
+ project_slug: str = typer.Option(
49
+ None,
50
+ '--project-name',
51
+ '-pn',
52
+ help=__("Filter containers by project, using the project's name"),
43
53
  is_eager=False,
44
54
  ),
45
55
  statuses: List[str] = typer.Option(
@@ -54,12 +64,17 @@ def list_containers(
54
64
  app_logger.info(f'Running {command_name}')
55
65
  check_command_permission(command_name)
56
66
 
67
+ if sum(v is not None for v in [project_public_id, project_slug]) > 1:
68
+ typer.echo("Please provide a single identifier for project - ID or name.")
69
+ raise typer.Exit(1)
70
+
57
71
  service_factory = validate_config_and_get_service_factory()
58
72
  container_service: ContainerService = service_factory.get_container_service()
59
73
  container_service.print_container_list(
60
74
  row=row,
61
75
  page=page,
62
- project_uid=project_uid,
76
+ project_public_id=project_public_id,
77
+ project_slug=project_slug,
63
78
  statuses=statuses,
64
79
  )
65
80
 
@@ -69,45 +84,61 @@ def list_containers(
69
84
 
70
85
  @app.command(name="info", no_args_is_help=True, help=__("Get container info"), **get_command_metadata(CliCommand.CONTAINER_INFO))
71
86
  def container_info(
72
- container_uid: Optional[str] = typer.Argument(hidden=False, help=__("Container unique ID")),
87
+ container_public_id: str = typer.Option(
88
+ None,
89
+ '--container-id',
90
+ '-cid',
91
+ help=__("Container ID"),
92
+ is_eager=False,
93
+ ),
94
+ container_slug: str = typer.Option(
95
+ None,
96
+ '--container-name',
97
+ '-cn',
98
+ help=__("Container name"),
99
+ is_eager=False,
100
+ ),
73
101
  ):
74
102
  command_name = CliCommand.CONTAINER_INFO
75
103
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
76
104
  check_command_permission(command_name)
77
105
 
78
- if not container_uid:
79
- typer.echo(__('Container unique ID is required'))
106
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
107
+ typer.echo("Please provide a single identifier for container - ID or name.")
80
108
  raise typer.Exit(1)
81
109
 
82
110
  service_factory = validate_config_and_get_service_factory()
83
111
  container_service: ContainerService = service_factory.get_container_service()
84
112
 
85
113
  container: Optional[DockerContainerDto] = container_service.get_container(
86
- container_slug=container_uid,
114
+ container_public_id=container_public_id,
115
+ container_slug=container_slug,
87
116
  )
88
117
 
89
118
  if not container:
90
- typer.echo(__("Container not found: %container_item%", {'container_item': str(container_uid) if container_uid else ''}))
119
+ typer.echo("Container not found")
91
120
  raise typer.Exit(1)
92
121
 
93
122
  typer.echo(__("STATUS: %status%", {'status': str(container.frontend_status.status_translation if container and container.frontend_status else 'UNKNOWN')}))
94
- typer.echo(__("UNIQUE ID: %slug%", {'slug': str(container.slug)}))
95
- typer.echo(__("TITLE: %title%", {'title': str(container.title)}))
123
+ typer.echo(__("ID: %slug%", {'slug': str(container.public_id)}))
124
+ typer.echo(__("NAME: %title%", {'title': str(container.slug)}))
96
125
  typer.echo(__("IMAGE: %image%", {'image': str(container.docker_image)}))
97
126
 
127
+ typer.echo(f"CONTAINER INSTANCE:")
128
+
98
129
  if container.instance_rented:
130
+ typer.echo(f" TYPE: RENTED")
131
+ typer.echo(f" ID: {container.instance_rented.public_id}")
132
+ typer.echo(f" NAME: {container.instance_rented.slug}")
99
133
  typer.echo(
100
- __("RENTED SERVER INSTANCE UNIQUE ID: %instance_slug%", {'instance_slug': str(container.instance_rented.slug)})
101
- )
102
- typer.echo(
103
- __("RENTED SERVER INSTANCE STATUS: %instance_status%",
134
+ __("RENTED INSTANCE STATUS: %instance_status%",
104
135
  {'instance_status': str(container.instance_rented.frontend_status.status_translation if container.instance_rented.frontend_status else 'UNKNOWN')})
105
136
  )
106
137
 
107
138
  if container.selfhosted_instance:
108
- typer.echo(
109
- __("SELF-HOSTED INSTANCE UNIQUE ID: %instance_slug%", {'instance_slug': str(container.selfhosted_instance.slug)})
110
- )
139
+ typer.echo(f" TYPE: SELF-HOSTED")
140
+ typer.echo(f" ID: {container.selfhosted_instance.public_id}")
141
+ typer.echo(f" NAME: {container.selfhosted_instance.slug}")
111
142
  typer.echo(
112
143
  __("SELF-HOSTED INSTANCE STATUS: %instance_status%",
113
144
  {'instance_status': str(container.selfhosted_instance.frontend_status.status_translation if container.selfhosted_instance.frontend_status else 'UNKNOWN')})
@@ -129,7 +160,20 @@ def container_info(
129
160
 
130
161
  @app.command(name="connect", no_args_is_help=True, help=__("Connect to container"), **get_command_metadata(CliCommand.CONTAINER_CONNECT))
131
162
  def container_connect(
132
- container_uid: Optional[str] = typer.Argument(help=__("Container unique ID"),),
163
+ container_public_id: str = typer.Option(
164
+ None,
165
+ '--container-id',
166
+ '-cid',
167
+ help=__("Container ID"),
168
+ is_eager=False,
169
+ ),
170
+ container_slug: str = typer.Option(
171
+ None,
172
+ '--container-name',
173
+ '-cn',
174
+ help=__("Container name"),
175
+ is_eager=False,
176
+ ),
133
177
  username: Optional[str] = typer.Option(
134
178
  None,
135
179
  '--username',
@@ -149,8 +193,8 @@ def container_connect(
149
193
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
150
194
  check_command_permission(command_name)
151
195
 
152
- if not container_uid:
153
- typer.echo(__('Container unique ID is required'))
196
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
197
+ typer.echo("Please provide a single identifier for container - ID or name.")
154
198
  raise typer.Exit(1)
155
199
 
156
200
  if private_ssh_key_path and not Path(private_ssh_key_path).is_file():
@@ -161,7 +205,8 @@ def container_connect(
161
205
  container_service: ContainerService = service_factory.get_container_service()
162
206
 
163
207
  container_service.connect_to_container(
164
- container_uid=container_uid,
208
+ container_public_id=container_public_id,
209
+ container_slug=container_slug,
165
210
  username=username,
166
211
  input_ssh_key_path=private_ssh_key_path,
167
212
  )
@@ -173,7 +218,7 @@ def container_connect(
173
218
  @app.command(name="upload", no_args_is_help=True, help=__("Upload file to container"), **get_command_metadata(CliCommand.CONTAINER_UPLOAD))
174
219
  def upload_file(
175
220
  source_path: str = typer.Argument(help=__("Source file path"),),
176
- destination: Optional[str] = typer.Argument(help=__("Destination directory path in container. Format: container_uid:/path/to/file"),),
221
+ destination: Optional[str] = typer.Argument(help=__("Destination directory path in container. Format: container_id_or_name:/path/to/file"),),
177
222
  username: Optional[str] = typer.Option(
178
223
  None,
179
224
  '--username',
@@ -186,50 +231,22 @@ def upload_file(
186
231
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
187
232
  check_command_permission(command_name)
188
233
 
189
- container_args = re.match(r"^([\w\W]+?):([\w\W]+)$", destination)
190
-
191
- if container_args is None:
192
- typer.echo(__('Container unique ID and source file path are required as the second argument'))
193
- typer.echo(__('Example: container_uid:/path/to/file'))
194
- raise typer.Exit(1)
195
- container_slug = container_args.groups()[0]
196
- destination_path = container_args.groups()[1].rstrip("/")
197
-
198
- if not container_slug:
199
- typer.echo(__('Container unique ID is required'))
200
- raise typer.Exit(1)
201
-
202
234
  service_factory = validate_config_and_get_service_factory()
203
235
  container_service: ContainerService = service_factory.get_container_service()
204
236
 
205
- container: Optional[DockerContainerDto] = container_service.get_container(
206
- container_slug=container_slug,
237
+ container_service.put_file_to_container(
238
+ source_path=source_path,
239
+ destination=destination,
240
+ username_param=username,
207
241
  )
208
242
 
209
- if container:
210
- container_service.check_if_container_running(
211
- container=container
212
- )
213
-
214
- typer.echo(__("Uploading file(s) to container '%container-slug%'", {'container-slug': container_slug}))
215
-
216
- container_service.put_file_to_container(
217
- container=container,
218
- src_path=source_path,
219
- destination_path=destination_path,
220
- username_param=username,
221
- copy_only_folder_contents=source_path.endswith("/")
222
- )
223
- else:
224
- typer.echo(__("Container not found: %container_item%", {'container_item': container_slug}))
225
-
226
243
  app_logger.info(f'End send files to container')
227
244
  raise typer.Exit(0)
228
245
 
229
246
 
230
247
  @app.command(name="download", no_args_is_help=True, help=__("Download file from container"), **get_command_metadata(CliCommand.CONTAINER_DOWNLOAD))
231
248
  def download_file(
232
- source_path: str = typer.Argument(help=__("Source file path in container. Format: container_uid:/path/to/file"),),
249
+ source: str = typer.Argument(help=__("Source file path in container. Format: container_name:/path/to/file"),),
233
250
  destination_path: str = typer.Argument(help=__("Destination directory path on local machine"),),
234
251
  username: Optional[str] = typer.Option(
235
252
  None,
@@ -243,64 +260,50 @@ def download_file(
243
260
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
244
261
  check_command_permission(command_name)
245
262
 
246
- container_args = re.match(r"^([\w\W]+?):([\w\W]+)$", source_path)
247
-
248
- if container_args is None:
249
- typer.echo(__('Container unique ID and source directory path are required as the first argument'))
250
- typer.echo(__('Example: container-uid:/path/to/file'))
251
- raise typer.Exit(1)
252
- container_slug = container_args.groups()[0]
253
- source_path = container_args.groups()[1]
254
-
255
- if not container_slug:
256
- typer.echo(__('Container unique ID is required'))
257
- raise typer.Exit(1)
258
-
259
263
  service_factory = validate_config_and_get_service_factory()
260
264
  container_service: ContainerService = service_factory.get_container_service()
261
265
 
262
- container: Optional[DockerContainerDto] = container_service.get_container(
263
- container_slug=container_slug,
266
+ container_service.get_file_from_container(
267
+ source=source,
268
+ destination_path=destination_path.rstrip("/"),
269
+ username_param=username,
264
270
  )
265
271
 
266
- if container:
267
- container_service.check_if_container_running(
268
- container=container
269
- )
270
-
271
- typer.echo(__("Downloading files from container: '%container-slug%'", {'container-slug': container_slug}))
272
-
273
- container_service.get_file_from_container(
274
- container=container,
275
- src_path=source_path,
276
- destination_path=destination_path.rstrip("/"),
277
- username_param=username,
278
- copy_only_folder_contents=source_path.endswith("/"),
279
- )
280
- else:
281
- typer.echo(__("Container not found: %container_item%", {'container_item': container_slug}))
282
-
283
272
  app_logger.info(f'End download files from container')
284
273
  raise typer.Exit(0)
285
274
 
286
275
 
287
276
  @app.command(name="start", no_args_is_help=True, help=__("Start container"), **get_command_metadata(CliCommand.CONTAINER_START))
288
277
  def start_container(
289
- container_uid: Optional[str] = typer.Argument(help=__("Container unique ID"), ),
278
+ container_public_id: str = typer.Option(
279
+ None,
280
+ '--container-id',
281
+ '-cid',
282
+ help=__("Container ID"),
283
+ is_eager=False,
284
+ ),
285
+ container_slug: str = typer.Option(
286
+ None,
287
+ '--container-name',
288
+ '-cn',
289
+ help=__("Container name"),
290
+ is_eager=False,
291
+ ),
290
292
  ):
291
293
  command_name = CliCommand.CONTAINER_START
292
294
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
293
295
  check_command_permission(command_name)
294
296
 
295
- if not container_uid:
296
- typer.echo(__('Container unique ID is required'))
297
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
298
+ typer.echo("Please provide a single identifier for container - ID or name.")
297
299
  raise typer.Exit(1)
298
300
 
299
301
  service_factory = validate_config_and_get_service_factory()
300
302
  container_service: ContainerService = service_factory.get_container_service()
301
303
 
302
304
  container_service.request_docker_container_action(
303
- container_uid=container_uid,
305
+ container_public_id=container_public_id,
306
+ container_slug=container_slug,
304
307
  action=DockerContainerAction.START
305
308
  )
306
309
 
@@ -310,21 +313,35 @@ def start_container(
310
313
 
311
314
  @app.command(name="stop", no_args_is_help=True, help=__("Stop container"), **get_command_metadata(CliCommand.CONTAINER_STOP))
312
315
  def stop_container(
313
- container_uid: Optional[str] = typer.Argument(help=__("Container unique ID"), ),
316
+ container_public_id: str = typer.Option(
317
+ None,
318
+ '--container-id',
319
+ '-cid',
320
+ help=__("Container ID"),
321
+ is_eager=False,
322
+ ),
323
+ container_slug: str = typer.Option(
324
+ None,
325
+ '--container-name',
326
+ '-cn',
327
+ help=__("Container name"),
328
+ is_eager=False,
329
+ ),
314
330
  ):
315
331
  command_name = CliCommand.CONTAINER_STOP
316
332
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
317
333
  check_command_permission(command_name)
318
334
 
319
- if not container_uid:
320
- typer.echo(__('Container unique ID is required'))
335
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
336
+ typer.echo("Please provide a single identifier for container - ID or name.")
321
337
  raise typer.Exit(1)
322
338
 
323
339
  service_factory = validate_config_and_get_service_factory()
324
340
  container_service: ContainerService = service_factory.get_container_service()
325
341
 
326
342
  container_service.request_docker_container_action(
327
- container_uid=container_uid,
343
+ container_public_id=container_public_id,
344
+ container_slug=container_slug,
328
345
  action=DockerContainerAction.STOP
329
346
  )
330
347
 
@@ -334,21 +351,35 @@ def stop_container(
334
351
 
335
352
  @app.command(name="restart", no_args_is_help=True, help=__("Restart container"), **get_command_metadata(CliCommand.CONTAINER_RESTART))
336
353
  def restart_container(
337
- container_uid: Optional[str] = typer.Argument(help=__("Container unique ID"), ),
354
+ container_public_id: str = typer.Option(
355
+ None,
356
+ '--container-id',
357
+ '-cid',
358
+ help=__("Container ID"),
359
+ is_eager=False,
360
+ ),
361
+ container_slug: str = typer.Option(
362
+ None,
363
+ '--container-name',
364
+ '-cn',
365
+ help=__("Container name"),
366
+ is_eager=False,
367
+ ),
338
368
  ):
339
369
  command_name = CliCommand.CONTAINER_RESTART
340
370
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
341
371
  check_command_permission(command_name)
342
372
 
343
- if not container_uid:
344
- typer.echo(__('Container unique ID is required'))
373
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
374
+ typer.echo("Please provide a single identifier for container - ID or name.")
345
375
  raise typer.Exit(1)
346
376
 
347
377
  service_factory = validate_config_and_get_service_factory()
348
378
  container_service: ContainerService = service_factory.get_container_service()
349
379
 
350
380
  container_service.request_docker_container_action(
351
- container_uid=container_uid,
381
+ container_public_id=container_public_id,
382
+ container_slug=container_slug,
352
383
  action=DockerContainerAction.RESTART
353
384
  )
354
385
 
@@ -358,7 +389,20 @@ def restart_container(
358
389
 
359
390
  @app.command(name="logs", no_args_is_help=True, help=__("Stream real-time Docker container logs or view last logs for a container"), **get_command_metadata(CliCommand.CONTAINER_LOGS))
360
391
  def container_logs(
361
- container_uid: Optional[str] = typer.Argument(help=__("Container unique id")),
392
+ container_public_id: str = typer.Option(
393
+ None,
394
+ '--container-id',
395
+ '-cid',
396
+ help=__("Container ID"),
397
+ is_eager=False,
398
+ ),
399
+ container_slug: str = typer.Option(
400
+ None,
401
+ '--container-name',
402
+ '-cn',
403
+ help=__("Container name"),
404
+ is_eager=False,
405
+ ),
362
406
  logs_number: Optional[int] = typer.Option(
363
407
  None,
364
408
  '--number',
@@ -371,8 +415,8 @@ def container_logs(
371
415
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
372
416
  check_command_permission(command_name)
373
417
 
374
- if not container_uid:
375
- typer.echo(__('Container unique ID is required'))
418
+ if sum(v is not None for v in [container_public_id, container_slug]) != 1:
419
+ typer.echo("Please provide a single identifier for container - ID or name.")
376
420
  raise typer.Exit(1)
377
421
 
378
422
  service_factory = validate_config_and_get_service_factory()
@@ -380,10 +424,11 @@ def container_logs(
380
424
 
381
425
  if logs_number is None:
382
426
  logging_service.stream_container_logs_with_controls(
383
- container_uid=container_uid
427
+ container_public_id=container_public_id,
428
+ container_slug=container_slug,
384
429
  )
385
430
  else:
386
- logging_service.print_last_container_logs(container_uid=container_uid, logs_number=logs_number)
431
+ logging_service.print_last_container_logs(container_public_id=container_public_id, container_slug=container_slug, logs_number=logs_number)
387
432
 
388
433
  app_logger.info(f'Container logs - end')
389
434
  raise typer.Exit(0)
@@ -64,8 +64,19 @@ def rented_list(
64
64
 
65
65
  @rented.command(name="connect", no_args_is_help=True, help=__("Connect to rented server instance"), **get_command_metadata(CliCommand.INSTANCE_RENTED_CONNECT))
66
66
  def instance_connect(
67
- instance_uid: Optional[str] = typer.Argument(
68
- help=__("Rented server instance unique ID"),
67
+ public_id: Optional[str] = typer.Option(
68
+ None,
69
+ '--rented-instance-id',
70
+ '-rid',
71
+ help="Rented instance ID",
72
+ is_eager=False,
73
+ ),
74
+ slug: Optional[str] = typer.Option(
75
+ None,
76
+ '--rented-instance-name',
77
+ '-rn',
78
+ help="Rented instance name",
79
+ is_eager=False,
69
80
  ),
70
81
  private_ssh_key_path: str = typer.Option(
71
82
  None,
@@ -79,8 +90,8 @@ def instance_connect(
79
90
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
80
91
  check_command_permission(command_name)
81
92
 
82
- if not instance_uid:
83
- typer.echo(__('Rented server instance unique ID is required'))
93
+ if sum(v is not None for v in [public_id, slug]) != 1:
94
+ typer.echo("Please provide a single identifier for rented instance - ID or name.")
84
95
  raise typer.Exit(1)
85
96
 
86
97
  if private_ssh_key_path and not Path(private_ssh_key_path).is_file():
@@ -91,7 +102,8 @@ def instance_connect(
91
102
  instance_service: InstanceService = service_factory.get_instance_service()
92
103
 
93
104
  instance_service.connect_to_rented_instance(
94
- instance_rented_slug=instance_uid,
105
+ instance_rented_public_id=public_id,
106
+ instance_rented_slug=slug,
95
107
  input_ssh_key_path=private_ssh_key_path
96
108
  )
97
109
 
@@ -142,7 +154,20 @@ def self_hosted_list(
142
154
 
143
155
  @self_hosted.command(name="connect", no_args_is_help=True, help=__("Connect to self-hosted instance"), **get_command_metadata(CliCommand.INSTANCE_SELF_HOSTED_CONNECT))
144
156
  def self_hosted_connect(
145
- instance_slug: Optional[str] = typer.Argument(help=__("Self-hosted instance unique ID"),),
157
+ public_id: Optional[str] = typer.Option(
158
+ None,
159
+ '--self-hosted-instance-id',
160
+ '-sid',
161
+ help="Self-hosted instance ID",
162
+ is_eager=False,
163
+ ),
164
+ slug: Optional[str] = typer.Option(
165
+ None,
166
+ '--self-hosted-instance-name',
167
+ '-sn',
168
+ help="Self-hosted instance name",
169
+ is_eager=False,
170
+ ),
146
171
  username: Optional[str] = typer.Option(
147
172
  None,
148
173
  '--username',
@@ -162,8 +187,8 @@ def self_hosted_connect(
162
187
  app_logger.info(f'Running {command_name} from {get_current_directory()}')
163
188
  check_command_permission(command_name)
164
189
 
165
- if not instance_slug:
166
- typer.echo(__('Self-hosted instance unique ID is required'))
190
+ if sum(v is not None for v in [public_id, slug]) != 1:
191
+ typer.echo("Please provide a single identifier for self-hosted instance - ID or name.")
167
192
  raise typer.Exit(1)
168
193
 
169
194
  if private_ssh_key_path and not Path(private_ssh_key_path).is_file():
@@ -174,7 +199,8 @@ def self_hosted_connect(
174
199
  instance_service: InstanceService = service_factory.get_instance_service()
175
200
 
176
201
  instance_service.connect_to_selfhosted_instance(
177
- selfhosted_instance_slug=instance_slug,
202
+ selfhosted_instance_public_id=public_id,
203
+ selfhosted_instance_slug=slug,
178
204
  username=username,
179
205
  input_ssh_key_path=private_ssh_key_path
180
206
  )