meshagent-cli 0.51.5__tar.gz → 0.52.0__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 (174) hide show
  1. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/PKG-INFO +17 -17
  2. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli.py +5 -0
  3. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli_test.py +3 -0
  4. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/containers.py +13 -4
  5. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/containers_test.py +32 -0
  6. meshagent_cli-0.52.0/meshagent/cli/custom_domains.py +181 -0
  7. meshagent_cli-0.52.0/meshagent/cli/custom_domains_test.py +137 -0
  8. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/image.py +159 -73
  9. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/image_test.py +69 -6
  10. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process.py +1 -1
  11. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process_test.py +1 -1
  12. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/routes.py +12 -0
  13. meshagent_cli-0.52.0/meshagent/cli/version.py +1 -0
  14. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/PKG-INFO +17 -17
  15. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/SOURCES.txt +2 -0
  16. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/requires.txt +16 -16
  17. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/pyproject.toml +16 -16
  18. meshagent_cli-0.51.5/meshagent/cli/version.py +0 -1
  19. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/LICENSE +0 -0
  20. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/README.md +0 -0
  21. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/__init__.py +0 -0
  22. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/_filedrop.py +0 -0
  23. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent.py +0 -0
  24. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_cli_options_test.py +0 -0
  25. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_package_cli.py +0 -0
  26. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_package_cli_test.py +0 -0
  27. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agents.py +0 -0
  28. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agents_test.py +0 -0
  29. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/ask.py +0 -0
  30. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/ask_test.py +0 -0
  31. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/async_typer.py +0 -0
  32. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/async_typer_test.py +0 -0
  33. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth.py +0 -0
  34. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_async.py +0 -0
  35. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_async_test.py +0 -0
  36. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_test.py +0 -0
  37. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/call.py +0 -0
  38. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/chatbot.py +0 -0
  39. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli_mcp.py +0 -0
  40. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/common_options.py +0 -0
  41. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/config.py +0 -0
  42. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/config_test.py +0 -0
  43. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create.py +0 -0
  44. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/__init__.py +0 -0
  45. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/backend-agent/server.py +0 -0
  46. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/contact-form/server.py +0 -0
  47. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/channel.py +0 -0
  48. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/scripts/configure-slack.py +0 -0
  49. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/scripts/setup-slack-dev-route.py +0 -0
  50. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/server.py +0 -0
  51. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/task-queue-dashboard/server.py +0 -0
  52. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/channel.py +0 -0
  53. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/configure-telegram.py +0 -0
  54. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/create-bot-token.py +0 -0
  55. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/server.py +0 -0
  56. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/twilio-channel/channel.py +0 -0
  57. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/twilio-channel/server.py +0 -0
  58. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/webserver/server.py +0 -0
  59. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/whatsapp-channel/channel.py +0 -0
  60. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/whatsapp-channel/server.py +0 -0
  61. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_test.py +0 -0
  62. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/dataset.py +0 -0
  63. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/dataset_test.py +0 -0
  64. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/developer.py +0 -0
  65. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/developer_test.py +0 -0
  66. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor.py +0 -0
  67. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_dockerfiles/__init__.py +0 -0
  68. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_templates/__init__.py +0 -0
  69. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_test.py +0 -0
  70. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/feeds.py +0 -0
  71. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/feeds_test.py +0 -0
  72. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helper.py +0 -0
  73. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helper_test.py +0 -0
  74. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helpers.py +0 -0
  75. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/host.py +0 -0
  76. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/iam.py +0 -0
  77. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/iam_test.py +0 -0
  78. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/launch.py +0 -0
  79. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/launch_test.py +0 -0
  80. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/llm.py +0 -0
  81. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/llm_test.py +0 -0
  82. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/local_settings.py +0 -0
  83. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/local_settings_test.py +0 -0
  84. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailbot.py +0 -0
  85. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailbot_test.py +0 -0
  86. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailboxes.py +0 -0
  87. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailboxes_test.py +0 -0
  88. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meeting_transcriber.py +0 -0
  89. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/memory.py +0 -0
  90. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/memory_test.py +0 -0
  91. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meshagent_images.py +0 -0
  92. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meshagent_images_test.py +0 -0
  93. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/messaging.py +0 -0
  94. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/messaging_test.py +0 -0
  95. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mounts.py +0 -0
  96. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/multi.py +0 -0
  97. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/oci_archive.py +0 -0
  98. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/oci_archive_test.py +0 -0
  99. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/participant_token.py +0 -0
  100. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/port.py +0 -0
  101. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/port_test.py +0 -0
  102. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/preamble_rules.py +0 -0
  103. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/preamble_rules_test.py +0 -0
  104. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process_live_test.py +0 -0
  105. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/projects.py +0 -0
  106. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/projects_test.py +0 -0
  107. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/queue.py +0 -0
  108. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/queue_test.py +0 -0
  109. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/registry.py +0 -0
  110. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/registry_test.py +0 -0
  111. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room.py +0 -0
  112. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_connect.py +0 -0
  113. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_connect_test.py +0 -0
  114. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_services.py +0 -0
  115. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_services_test.py +0 -0
  116. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/rooms.py +0 -0
  117. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/rooms_test.py +0 -0
  118. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/root_commands.py +0 -0
  119. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/root_commands_test.py +0 -0
  120. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/routes_test.py +0 -0
  121. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sample_channel_http_test.py +0 -0
  122. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sample_channel_live_e2e_test.py +0 -0
  123. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/scheduled_tasks.py +0 -0
  124. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/scheduled_tasks_test.py +0 -0
  125. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/secrets.py +0 -0
  126. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/secrets_test.py +0 -0
  127. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/service_accounts.py +0 -0
  128. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/service_accounts_test.py +0 -0
  129. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/services.py +0 -0
  130. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/services_test.py +0 -0
  131. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sessions.py +0 -0
  132. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sessions_test.py +0 -0
  133. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sqlite.py +0 -0
  134. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sqlite_test.py +0 -0
  135. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/storage.py +0 -0
  136. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/storage_test.py +0 -0
  137. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/subscriptions.py +0 -0
  138. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sync.py +0 -0
  139. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sync_test.py +0 -0
  140. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/task_runner.py +0 -0
  141. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/task_runner_test.py +0 -0
  142. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/test.py +0 -0
  143. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/testing.py +0 -0
  144. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_inspect.py +0 -0
  145. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_inspect_test.py +0 -0
  146. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_sidebar.py +0 -0
  147. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_call_summary.py +0 -0
  148. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_call_summary_test.py +0 -0
  149. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_integrations.py +0 -0
  150. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_integrations_test.py +0 -0
  151. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/__init__.py +0 -0
  152. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/auth_switch.py +0 -0
  153. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/auth_switch_test.py +0 -0
  154. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/create.py +0 -0
  155. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/deploy_room.py +0 -0
  156. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/deploy_room_test.py +0 -0
  157. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/project_activate.py +0 -0
  158. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/project_activate_test.py +0 -0
  159. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup.py +0 -0
  160. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup_splash_frames.py +0 -0
  161. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup_test.py +0 -0
  162. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/version_check.py +0 -0
  163. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/version_check_test.py +0 -0
  164. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/voicebot.py +0 -0
  165. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/volumes.py +0 -0
  166. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/volumes_test.py +0 -0
  167. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/webserver.py +0 -0
  168. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/webserver_test.py +0 -0
  169. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/worker.py +0 -0
  170. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/worker_test.py +0 -0
  171. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/dependency_links.txt +0 -0
  172. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/entry_points.txt +0 -0
  173. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/top_level.txt +0 -0
  174. {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-cli
3
- Version: 0.51.5
3
+ Version: 0.52.0
4
4
  Summary: CLI for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -22,8 +22,8 @@ Requires-Dist: openpyxl~=3.1
22
22
  Requires-Dist: xlsxwriter~=3.2
23
23
  Requires-Dist: pathspec<2,>=1.0.3
24
24
  Requires-Dist: zstandard~=0.25.0
25
- Requires-Dist: meshagent-llm-proxy==0.51.5
26
- Requires-Dist: meshagent-codex==0.51.5
25
+ Requires-Dist: meshagent-llm-proxy==0.52.0
26
+ Requires-Dist: meshagent-codex==0.52.0
27
27
  Requires-Dist: rich~=14.3.0
28
28
  Requires-Dist: sounddevice~=0.5
29
29
  Requires-Dist: textual<9.0,>=8.2.3
@@ -32,23 +32,23 @@ Requires-Dist: prompt-toolkit~=3.0.52
32
32
  Requires-Dist: ascii-magic~=2.3
33
33
  Requires-Dist: pillow~=11.3.0
34
34
  Provides-Extra: all
35
- Requires-Dist: meshagent-agents[all]==0.51.5; extra == "all"
36
- Requires-Dist: meshagent-api[all]==0.51.5; extra == "all"
37
- Requires-Dist: meshagent-commoncrawl==0.51.5; extra == "all"
38
- Requires-Dist: meshagent-scrapy==0.51.5; extra == "all"
39
- Requires-Dist: meshagent-computers==0.51.5; extra == "all"
40
- Requires-Dist: meshagent-openai==0.51.5; extra == "all"
41
- Requires-Dist: meshagent-anthropic==0.51.5; extra == "all"
42
- Requires-Dist: meshagent-otel==0.51.5; extra == "all"
43
- Requires-Dist: meshagent-mcp==0.51.5; extra == "all"
44
- Requires-Dist: meshagent-tools==0.51.5; extra == "all"
35
+ Requires-Dist: meshagent-agents[all]==0.52.0; extra == "all"
36
+ Requires-Dist: meshagent-api[all]==0.52.0; extra == "all"
37
+ Requires-Dist: meshagent-commoncrawl==0.52.0; extra == "all"
38
+ Requires-Dist: meshagent-scrapy==0.52.0; extra == "all"
39
+ Requires-Dist: meshagent-computers==0.52.0; extra == "all"
40
+ Requires-Dist: meshagent-openai==0.52.0; extra == "all"
41
+ Requires-Dist: meshagent-anthropic==0.52.0; extra == "all"
42
+ Requires-Dist: meshagent-otel==0.52.0; extra == "all"
43
+ Requires-Dist: meshagent-mcp==0.52.0; extra == "all"
44
+ Requires-Dist: meshagent-tools==0.52.0; extra == "all"
45
45
  Requires-Dist: supabase-auth~=2.28.0; extra == "all"
46
46
  Requires-Dist: prompt-toolkit~=3.0.52; extra == "all"
47
47
  Provides-Extra: mcp-service
48
- Requires-Dist: meshagent-agents[all]==0.51.5; extra == "mcp-service"
49
- Requires-Dist: meshagent-api==0.51.5; extra == "mcp-service"
50
- Requires-Dist: meshagent-mcp==0.51.5; extra == "mcp-service"
51
- Requires-Dist: meshagent-tools==0.51.5; extra == "mcp-service"
48
+ Requires-Dist: meshagent-agents[all]==0.52.0; extra == "mcp-service"
49
+ Requires-Dist: meshagent-api==0.52.0; extra == "mcp-service"
50
+ Requires-Dist: meshagent-mcp==0.52.0; extra == "mcp-service"
51
+ Requires-Dist: meshagent-tools==0.52.0; extra == "mcp-service"
52
52
  Requires-Dist: supabase-auth~=2.28.0; extra == "mcp-service"
53
53
  Dynamic: license-file
54
54
 
@@ -216,6 +216,11 @@ app.add_lazy_command(
216
216
  module="meshagent.cli.routes",
217
217
  help="Manage routes for your project",
218
218
  )
219
+ app.add_lazy_command(
220
+ name="custom-domain",
221
+ module="meshagent.cli.custom_domains",
222
+ help="Manage custom domains for project routes",
223
+ )
219
224
  app.add_lazy_command(
220
225
  name="registry",
221
226
  module="meshagent.cli.registry",
@@ -54,6 +54,7 @@ def test_root_help_lists_create_and_doctor_but_hides_legacy_command_namespaces()
54
54
  assert "│ doctor" in result.output
55
55
  assert "│ iam" in result.output
56
56
  assert "│ service-account" in result.output
57
+ assert "│ custom-domain" in result.output
57
58
  assert "│ init" not in result.output
58
59
  assert "│ api-key" not in result.output
59
60
  assert "│ launch" in result.output
@@ -79,6 +80,8 @@ def test_root_registers_create_and_doctor_as_visible_commands() -> None:
79
80
  assert registrations["iam"].hidden is False
80
81
  assert registrations["service-account"].module == "meshagent.cli.service_accounts"
81
82
  assert registrations["service-account"].hidden is False
83
+ assert registrations["custom-domain"].module == "meshagent.cli.custom_domains"
84
+ assert registrations["custom-domain"].hidden is False
82
85
  assert "init" not in registrations
83
86
  assert "api-key" not in registrations
84
87
 
@@ -365,9 +365,15 @@ async def _drain_stream_plain(stream, *, show_progress: bool = True):
365
365
 
366
366
  t1 = asyncio.create_task(_logs())
367
367
  t2 = asyncio.create_task(_prog())
368
+ completed = False
368
369
  try:
369
- return await stream
370
+ result = await stream
371
+ completed = True
372
+ return result
370
373
  finally:
374
+ if not completed:
375
+ t1.cancel()
376
+ t2.cancel()
371
377
  await asyncio.gather(t1, t2, return_exceptions=True)
372
378
 
373
379
 
@@ -511,8 +517,10 @@ async def _drain_stream_pretty(stream):
511
517
  t_logs = asyncio.create_task(_logs())
512
518
  t_prog = asyncio.create_task(_prog())
513
519
  t_ui = asyncio.create_task(_refresh())
520
+ completed = False
514
521
  try:
515
522
  result = await stream
523
+ completed = True
516
524
  return result
517
525
  finally:
518
526
  # Hide any still-visible tasks (e.g., indeterminate ones with total=None)
@@ -520,10 +528,11 @@ async def _drain_stream_pretty(stream):
520
528
  progress.update(tid, visible=False)
521
529
  live.update(render())
522
530
 
523
- for t in (t_logs, t_prog):
524
- await t
525
-
531
+ if not completed:
532
+ t_logs.cancel()
533
+ t_prog.cancel()
526
534
  t_ui.cancel()
535
+ await asyncio.gather(t_logs, t_prog, t_ui, return_exceptions=True)
527
536
 
528
537
 
529
538
  async def _with_client(
@@ -323,6 +323,38 @@ async def test_drain_stream_plain_strips_cri_log_prefixes(
323
323
  assert capsys.readouterr().out == "step 1\nstep 2\n"
324
324
 
325
325
 
326
+ @pytest.mark.asyncio
327
+ async def test_drain_stream_plain_cancels_consumers_when_stream_is_cancelled() -> None:
328
+ consumers_cancelled = 0
329
+
330
+ class _BlockingStream:
331
+ async def _consume(self):
332
+ nonlocal consumers_cancelled
333
+ try:
334
+ await asyncio.Future()
335
+ yield None
336
+ finally:
337
+ consumers_cancelled += 1
338
+
339
+ def logs(self):
340
+ return self._consume()
341
+
342
+ def progress(self):
343
+ return self._consume()
344
+
345
+ def __await__(self):
346
+ return asyncio.Future().__await__()
347
+
348
+ task = asyncio.create_task(containers._drain_stream_plain(_BlockingStream()))
349
+ await asyncio.sleep(0)
350
+ task.cancel()
351
+
352
+ with pytest.raises(asyncio.CancelledError):
353
+ await asyncio.wait_for(task, timeout=0.5)
354
+
355
+ assert consumers_cancelled == 2
356
+
357
+
326
358
  @pytest.mark.asyncio
327
359
  async def test_stream_build_job_logs_and_wait_for_exit_uses_build_log_stream(
328
360
  monkeypatch: pytest.MonkeyPatch,
@@ -0,0 +1,181 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Annotated, Literal
5
+
6
+ import typer
7
+ from aiohttp import ClientResponseError
8
+ from rich import print
9
+
10
+ from meshagent.api.client import (
11
+ CustomDomain,
12
+ CustomDomainDnsRecord,
13
+ CustomDomainsPage,
14
+ )
15
+ from meshagent.cli import async_typer
16
+ from meshagent.cli.common_options import OutputFormatOption, ProjectIdOption
17
+ from meshagent.cli.helper import get_client, print_json_table, resolve_project_id
18
+
19
+
20
+ app = async_typer.AsyncTyper(help="Manage custom domains for project routes")
21
+
22
+
23
+ def _record(record: CustomDomainDnsRecord | None) -> str:
24
+ if record is None:
25
+ return ""
26
+ return f"{record.name} {record.type} {record.data}"
27
+
28
+
29
+ def _custom_domain_row(custom_domain: CustomDomain) -> dict[str, object]:
30
+ return {
31
+ "domain": custom_domain.domain,
32
+ "phase": custom_domain.phase,
33
+ "available": custom_domain.available,
34
+ "dns_authorization": _record(custom_domain.dns_authorization_record),
35
+ "route_dns": ", ".join(
36
+ _record(record) for record in custom_domain.routing_records
37
+ ),
38
+ "certificate": custom_domain.certificate_state or "",
39
+ }
40
+
41
+
42
+ def _print_custom_domains(
43
+ custom_domains: list[CustomDomain], *, output_format: str
44
+ ) -> None:
45
+ if output_format == "json":
46
+ print(
47
+ json.dumps(
48
+ {
49
+ "custom_domains": [
50
+ item.model_dump(mode="json", exclude_none=True)
51
+ for item in custom_domains
52
+ ]
53
+ },
54
+ indent=2,
55
+ )
56
+ )
57
+ return
58
+ print_json_table(
59
+ [_custom_domain_row(item) for item in custom_domains],
60
+ "domain",
61
+ "phase",
62
+ "available",
63
+ "dns_authorization",
64
+ "route_dns",
65
+ "certificate",
66
+ )
67
+
68
+
69
+ @app.async_command("create")
70
+ async def create_custom_domain(
71
+ *,
72
+ project_id: ProjectIdOption,
73
+ domain: Annotated[
74
+ str,
75
+ typer.Argument(help="Exact domain or wildcard such as *.example.com"),
76
+ ],
77
+ o: OutputFormatOption = "table",
78
+ ) -> None:
79
+ """Register an immutable custom domain and begin certificate provisioning."""
80
+ project_id = await resolve_project_id(project_id=project_id)
81
+ client = await get_client()
82
+ try:
83
+ custom_domain = await client.create_custom_domain(
84
+ project_id=project_id,
85
+ domain=domain,
86
+ )
87
+ finally:
88
+ await client.close()
89
+ _print_custom_domains([custom_domain], output_format=o)
90
+
91
+
92
+ @app.async_command("get")
93
+ async def get_custom_domain(
94
+ *,
95
+ project_id: ProjectIdOption,
96
+ domain: Annotated[str, typer.Argument(help="Exact registered domain")],
97
+ o: OutputFormatOption = "table",
98
+ ) -> None:
99
+ """Show availability and the DNS records that must be published."""
100
+ project_id = await resolve_project_id(project_id=project_id)
101
+ client = await get_client()
102
+ try:
103
+ try:
104
+ custom_domain = await client.get_custom_domain(
105
+ project_id=project_id,
106
+ domain=domain,
107
+ )
108
+ except ClientResponseError as error:
109
+ if error.status == 404:
110
+ print(f"[red]Custom domain not found:[/] {domain}")
111
+ raise typer.Exit(code=1) from error
112
+ raise
113
+ finally:
114
+ await client.close()
115
+ _print_custom_domains([custom_domain], output_format=o)
116
+
117
+
118
+ @app.async_command("list")
119
+ async def list_custom_domains(
120
+ *,
121
+ project_id: ProjectIdOption,
122
+ filter: Annotated[
123
+ str | None,
124
+ typer.Option("--filter", help="Lowercase contains filter"),
125
+ ] = None,
126
+ count: Annotated[
127
+ int,
128
+ typer.Option("--count", help="Maximum number of domains to return"),
129
+ ] = 100,
130
+ view: Annotated[
131
+ Literal["my", "all"],
132
+ typer.Option("--view", help="List directly accessible domains or all domains"),
133
+ ] = "my",
134
+ o: OutputFormatOption = "table",
135
+ ) -> None:
136
+ """List registered custom domains and certificate availability."""
137
+ project_id = await resolve_project_id(project_id=project_id)
138
+ client = await get_client()
139
+ custom_domains: list[CustomDomain] = []
140
+ continuation_token: str | None = None
141
+ try:
142
+ while len(custom_domains) < count:
143
+ page: CustomDomainsPage = await client.list_custom_domains(
144
+ project_id=project_id,
145
+ count=min(count - len(custom_domains), 100),
146
+ continuation_token=continuation_token,
147
+ filter=filter,
148
+ view=view,
149
+ )
150
+ custom_domains.extend(page.custom_domains)
151
+ continuation_token = page.continuation_token
152
+ if continuation_token is None:
153
+ break
154
+ finally:
155
+ await client.close()
156
+ _print_custom_domains(custom_domains[:count], output_format=o)
157
+
158
+
159
+ @app.async_command("delete")
160
+ async def delete_custom_domain(
161
+ *,
162
+ project_id: ProjectIdOption,
163
+ domain: Annotated[str, typer.Argument(help="Exact registered domain")],
164
+ ) -> None:
165
+ """Delete a custom domain after all covered routes have been removed."""
166
+ project_id = await resolve_project_id(project_id=project_id)
167
+ client = await get_client()
168
+ try:
169
+ try:
170
+ await client.delete_custom_domain(project_id=project_id, domain=domain)
171
+ except ClientResponseError as error:
172
+ if error.status == 404:
173
+ print(f"[red]Custom domain not found:[/] {domain}")
174
+ raise typer.Exit(code=1) from error
175
+ if error.status == 409:
176
+ print(f"[red]Custom domain is still assigned to a route:[/] {domain}")
177
+ raise typer.Exit(code=1) from error
178
+ raise
179
+ finally:
180
+ await client.close()
181
+ print(f"[green]Custom domain deletion requested:[/] {domain}")
@@ -0,0 +1,137 @@
1
+ from datetime import datetime, timezone
2
+
3
+ import pytest
4
+
5
+ from meshagent.api.client import CustomDomain, CustomDomainsPage
6
+ from meshagent.cli import custom_domains
7
+ from meshagent.cli.testing import CliRunner
8
+
9
+
10
+ def _domain(*, domain: str = "docs.example.com", available: bool = False):
11
+ return CustomDomain.model_validate(
12
+ {
13
+ "domain": domain,
14
+ "project_id": "resolved-project",
15
+ "phase": "available" if available else "pending_dns",
16
+ "available": available,
17
+ "dns_authorization_record": {
18
+ "name": "_acme-challenge.example.com.",
19
+ "type": "CNAME",
20
+ "data": "authorization.example.net.",
21
+ },
22
+ "routing_records": [{"name": "@", "type": "A", "data": "203.0.113.10"}],
23
+ "certificate_state": "ACTIVE" if available else "PROVISIONING",
24
+ "created_at": datetime(2026, 8, 31, tzinfo=timezone.utc),
25
+ }
26
+ )
27
+
28
+
29
+ def test_custom_domain_help_exposes_immutable_resource_commands() -> None:
30
+ result = CliRunner().invoke(custom_domains.app, ["--help"])
31
+
32
+ assert result.exit_code == 0
33
+ assert "create" in result.output
34
+ assert "get" in result.output
35
+ assert "list" in result.output
36
+ assert "delete" in result.output
37
+ assert "update" not in result.output
38
+
39
+
40
+ @pytest.mark.asyncio
41
+ async def test_create_prints_dns_and_availability(
42
+ monkeypatch: pytest.MonkeyPatch,
43
+ ) -> None:
44
+ calls: list[dict[str, str]] = []
45
+ printed_tables: list[tuple[list[dict[str, object]], tuple[str, ...]]] = []
46
+
47
+ class _FakeClient:
48
+ async def create_custom_domain(self, *, project_id: str, domain: str):
49
+ calls.append({"project_id": project_id, "domain": domain})
50
+ return _domain(domain=domain)
51
+
52
+ async def close(self) -> None:
53
+ pass
54
+
55
+ async def fake_get_client():
56
+ return _FakeClient()
57
+
58
+ async def fake_resolve_project_id(*, project_id: str | None) -> str:
59
+ assert project_id == "project-1"
60
+ return "resolved-project"
61
+
62
+ monkeypatch.setattr(custom_domains, "get_client", fake_get_client)
63
+ monkeypatch.setattr(custom_domains, "resolve_project_id", fake_resolve_project_id)
64
+ monkeypatch.setattr(
65
+ custom_domains,
66
+ "print_json_table",
67
+ lambda rows, *columns: printed_tables.append((rows, columns)),
68
+ )
69
+
70
+ await custom_domains.create_custom_domain(
71
+ project_id="project-1",
72
+ domain="docs.example.com",
73
+ o="table",
74
+ )
75
+
76
+ assert calls == [{"project_id": "resolved-project", "domain": "docs.example.com"}]
77
+ assert printed_tables[0][0][0]["available"] is False
78
+ assert "_acme-challenge.example.com." in str(
79
+ printed_tables[0][0][0]["dns_authorization"]
80
+ )
81
+ assert "203.0.113.10" in str(printed_tables[0][0][0]["route_dns"])
82
+
83
+
84
+ @pytest.mark.asyncio
85
+ async def test_list_follows_continuation_tokens(
86
+ monkeypatch: pytest.MonkeyPatch,
87
+ ) -> None:
88
+ calls: list[str | None] = []
89
+ printed: list[object] = []
90
+
91
+ class _FakeClient:
92
+ async def list_custom_domains(
93
+ self,
94
+ *,
95
+ project_id: str,
96
+ count: int,
97
+ continuation_token: str | None,
98
+ filter: str | None,
99
+ view: str,
100
+ ) -> CustomDomainsPage:
101
+ assert project_id == "resolved-project"
102
+ assert filter == "example"
103
+ assert view == "my"
104
+ calls.append(continuation_token)
105
+ if continuation_token is None:
106
+ return CustomDomainsPage(
107
+ custom_domains=[_domain(domain="a.example.com")],
108
+ continuation_token="next",
109
+ )
110
+ return CustomDomainsPage(
111
+ custom_domains=[_domain(domain="b.example.com", available=True)]
112
+ )
113
+
114
+ async def close(self) -> None:
115
+ pass
116
+
117
+ async def fake_get_client():
118
+ return _FakeClient()
119
+
120
+ async def fake_resolve_project_id(*, project_id: str | None) -> str:
121
+ return "resolved-project"
122
+
123
+ monkeypatch.setattr(custom_domains, "get_client", fake_get_client)
124
+ monkeypatch.setattr(custom_domains, "resolve_project_id", fake_resolve_project_id)
125
+ monkeypatch.setattr(custom_domains, "print", printed.append)
126
+
127
+ await custom_domains.list_custom_domains(
128
+ project_id="project-1",
129
+ filter="example",
130
+ count=2,
131
+ view="my",
132
+ o="json",
133
+ )
134
+
135
+ assert calls == [None, "next"]
136
+ assert '"a.example.com"' in str(printed[0])
137
+ assert '"b.example.com"' in str(printed[0])