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.
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/PKG-INFO +17 -17
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli.py +5 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli_test.py +3 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/containers.py +13 -4
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/containers_test.py +32 -0
- meshagent_cli-0.52.0/meshagent/cli/custom_domains.py +181 -0
- meshagent_cli-0.52.0/meshagent/cli/custom_domains_test.py +137 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/image.py +159 -73
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/image_test.py +69 -6
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process.py +1 -1
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process_test.py +1 -1
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/routes.py +12 -0
- meshagent_cli-0.52.0/meshagent/cli/version.py +1 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/PKG-INFO +17 -17
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/SOURCES.txt +2 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/requires.txt +16 -16
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/pyproject.toml +16 -16
- meshagent_cli-0.51.5/meshagent/cli/version.py +0 -1
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/LICENSE +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/README.md +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/__init__.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/_filedrop.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_cli_options_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_package_cli.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agent_package_cli_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agents.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/agents_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/ask.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/ask_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/async_typer.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/async_typer_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_async.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_async_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/auth_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/call.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/chatbot.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/cli_mcp.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/common_options.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/config.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/config_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/__init__.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/backend-agent/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/contact-form/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/channel.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/scripts/configure-slack.py +0 -0
- {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
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/slack-channel/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/task-queue-dashboard/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/channel.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/scripts/configure-telegram.py +0 -0
- {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
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/telegram-channel/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/twilio-channel/channel.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/twilio-channel/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/webserver/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/whatsapp-channel/channel.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_project_templates/python/whatsapp-channel/server.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/create_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/dataset.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/dataset_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/developer.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/developer_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_dockerfiles/__init__.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_templates/__init__.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/doctor_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/feeds.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/feeds_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helper.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helper_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/helpers.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/host.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/iam.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/iam_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/launch.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/launch_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/llm.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/llm_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/local_settings.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/local_settings_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailbot.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailbot_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailboxes.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mailboxes_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meeting_transcriber.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/memory.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/memory_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meshagent_images.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/meshagent_images_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/messaging.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/messaging_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/mounts.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/multi.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/oci_archive.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/oci_archive_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/participant_token.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/port.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/port_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/preamble_rules.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/preamble_rules_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/process_live_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/projects.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/projects_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/queue.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/queue_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/registry.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/registry_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_connect.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_connect_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_services.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/room_services_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/rooms.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/rooms_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/root_commands.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/root_commands_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/routes_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sample_channel_http_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sample_channel_live_e2e_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/scheduled_tasks.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/scheduled_tasks_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/secrets.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/secrets_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/service_accounts.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/service_accounts_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/services.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/services_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sessions.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sessions_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sqlite.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sqlite_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/storage.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/storage_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/subscriptions.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sync.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/sync_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/task_runner.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/task_runner_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/testing.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_inspect.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_inspect_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/thread_sidebar.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_call_summary.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_call_summary_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_integrations.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tool_integrations_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/__init__.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/auth_switch.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/auth_switch_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/create.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/deploy_room.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/deploy_room_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/project_activate.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/project_activate_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup_splash_frames.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/tui/setup_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/version_check.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/version_check_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/voicebot.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/volumes.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/volumes_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/webserver.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/webserver_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/worker.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent/cli/worker_test.py +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/dependency_links.txt +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/entry_points.txt +0 -0
- {meshagent_cli-0.51.5 → meshagent_cli-0.52.0}/meshagent_cli.egg-info/top_level.txt +0 -0
- {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.
|
|
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.
|
|
26
|
-
Requires-Dist: meshagent-codex==0.
|
|
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.
|
|
36
|
-
Requires-Dist: meshagent-api[all]==0.
|
|
37
|
-
Requires-Dist: meshagent-commoncrawl==0.
|
|
38
|
-
Requires-Dist: meshagent-scrapy==0.
|
|
39
|
-
Requires-Dist: meshagent-computers==0.
|
|
40
|
-
Requires-Dist: meshagent-openai==0.
|
|
41
|
-
Requires-Dist: meshagent-anthropic==0.
|
|
42
|
-
Requires-Dist: meshagent-otel==0.
|
|
43
|
-
Requires-Dist: meshagent-mcp==0.
|
|
44
|
-
Requires-Dist: meshagent-tools==0.
|
|
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.
|
|
49
|
-
Requires-Dist: meshagent-api==0.
|
|
50
|
-
Requires-Dist: meshagent-mcp==0.
|
|
51
|
-
Requires-Dist: meshagent-tools==0.
|
|
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
|
-
|
|
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
|
-
|
|
524
|
-
|
|
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])
|