Introduce explicit repro-fix, inspect, cold-start, and review-eval modes across the MCP server, CLI, and host helpers, with canonical mode-to-tool mappings, narrowed schemas, and mode-specific tool descriptions on top of the existing workspace runtime. Reposition the docs, host onramps, and use-case recipes so named modes are the primary user-facing startup story while the generic no-mode workspace-core path remains the escape hatch, and update the shared smoke runner to validate repro-fix and cold-start through mode-backed servers. Validation: UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache uv run pytest --no-cov tests/test_api.py tests/test_server.py tests/test_host_helpers.py tests/test_public_contract.py tests/test_cli.py tests/test_workspace_use_case_smokes.py; UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make check; UV_OFFLINE=1 UV_CACHE_DIR=.uv-cache make dist-check; real guest-backed make smoke-repro-fix-loop smoke-cold-start-validation outside the sandbox.
393 lines
17 KiB
Python
393 lines
17 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import asyncio
|
|
import io
|
|
import tomllib
|
|
from contextlib import redirect_stdout
|
|
from pathlib import Path
|
|
from typing import Any, cast
|
|
|
|
import pytest
|
|
|
|
from pyro_mcp import Pyro, __version__
|
|
from pyro_mcp.cli import _build_parser
|
|
from pyro_mcp.contract import (
|
|
PUBLIC_CLI_COMMANDS,
|
|
PUBLIC_CLI_DEMO_SUBCOMMANDS,
|
|
PUBLIC_CLI_ENV_SUBCOMMANDS,
|
|
PUBLIC_CLI_HOST_CONNECT_FLAGS,
|
|
PUBLIC_CLI_HOST_DOCTOR_FLAGS,
|
|
PUBLIC_CLI_HOST_PRINT_CONFIG_FLAGS,
|
|
PUBLIC_CLI_HOST_REPAIR_FLAGS,
|
|
PUBLIC_CLI_HOST_SUBCOMMANDS,
|
|
PUBLIC_CLI_MCP_SERVE_FLAGS,
|
|
PUBLIC_CLI_MCP_SUBCOMMANDS,
|
|
PUBLIC_CLI_RUN_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_CREATE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_DIFF_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_DISK_EXPORT_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_DISK_LIST_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_DISK_READ_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_EXEC_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_EXPORT_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_FILE_LIST_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_FILE_READ_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_FILE_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_FILE_WRITE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_LIST_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_PATCH_APPLY_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_PATCH_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_RESET_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_LIST_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_LOGS_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_START_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_STATUS_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_STOP_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SERVICE_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_CLOSE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_OPEN_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_READ_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_SIGNAL_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_SHELL_WRITE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SNAPSHOT_CREATE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SNAPSHOT_DELETE_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SNAPSHOT_LIST_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SNAPSHOT_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_START_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_STOP_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_SUMMARY_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SYNC_PUSH_FLAGS,
|
|
PUBLIC_CLI_WORKSPACE_SYNC_SUBCOMMANDS,
|
|
PUBLIC_CLI_WORKSPACE_UPDATE_FLAGS,
|
|
PUBLIC_MCP_COLD_START_MODE_TOOLS,
|
|
PUBLIC_MCP_INSPECT_MODE_TOOLS,
|
|
PUBLIC_MCP_MODES,
|
|
PUBLIC_MCP_PROFILES,
|
|
PUBLIC_MCP_REPRO_FIX_MODE_TOOLS,
|
|
PUBLIC_MCP_REVIEW_EVAL_MODE_TOOLS,
|
|
PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS,
|
|
PUBLIC_SDK_METHODS,
|
|
)
|
|
from pyro_mcp.vm_manager import VmManager
|
|
from pyro_mcp.vm_network import TapNetworkManager
|
|
|
|
|
|
def _subparser_choice(parser: argparse.ArgumentParser, name: str) -> argparse.ArgumentParser:
|
|
subparsers = getattr(parser, "_subparsers", None)
|
|
if subparsers is None:
|
|
raise AssertionError("parser does not define subparsers")
|
|
group_actions = cast(list[Any], subparsers._group_actions) # noqa: SLF001
|
|
if not group_actions:
|
|
raise AssertionError("parser subparsers are empty")
|
|
choices = cast(dict[str, argparse.ArgumentParser], group_actions[0].choices)
|
|
return choices[name]
|
|
|
|
|
|
def test_public_sdk_methods_exist() -> None:
|
|
assert tuple(sorted(PUBLIC_SDK_METHODS)) == PUBLIC_SDK_METHODS
|
|
for method_name in PUBLIC_SDK_METHODS:
|
|
assert hasattr(Pyro, method_name), method_name
|
|
|
|
|
|
def test_public_cli_help_lists_commands_and_run_flags() -> None:
|
|
parser = _build_parser()
|
|
help_text = parser.format_help()
|
|
assert "--version" in help_text
|
|
for command_name in PUBLIC_CLI_COMMANDS:
|
|
assert command_name in help_text
|
|
|
|
run_parser = _build_parser()
|
|
run_help = run_parser.parse_args(["run", "debian:12-base", "--", "true"])
|
|
assert run_help.command == "run"
|
|
assert run_help.environment == "debian:12-base"
|
|
assert run_help.vcpu_count == 1
|
|
assert run_help.mem_mib == 1024
|
|
|
|
run_help_text = _subparser_choice(parser, "run").format_help()
|
|
for flag in PUBLIC_CLI_RUN_FLAGS:
|
|
assert flag in run_help_text
|
|
|
|
env_help_text = _subparser_choice(parser, "env").format_help()
|
|
for subcommand_name in PUBLIC_CLI_ENV_SUBCOMMANDS:
|
|
assert subcommand_name in env_help_text
|
|
host_help_text = _subparser_choice(parser, "host").format_help()
|
|
for subcommand_name in PUBLIC_CLI_HOST_SUBCOMMANDS:
|
|
assert subcommand_name in host_help_text
|
|
host_connect_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "host"), "connect"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_HOST_CONNECT_FLAGS:
|
|
assert flag in host_connect_help_text
|
|
host_doctor_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "host"), "doctor"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_HOST_DOCTOR_FLAGS:
|
|
assert flag in host_doctor_help_text
|
|
host_print_config_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "host"), "print-config"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_HOST_PRINT_CONFIG_FLAGS:
|
|
assert flag in host_print_config_help_text
|
|
host_repair_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "host"), "repair"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_HOST_REPAIR_FLAGS:
|
|
assert flag in host_repair_help_text
|
|
mcp_help_text = _subparser_choice(parser, "mcp").format_help()
|
|
for subcommand_name in PUBLIC_CLI_MCP_SUBCOMMANDS:
|
|
assert subcommand_name in mcp_help_text
|
|
mcp_serve_help_text = _subparser_choice(_subparser_choice(parser, "mcp"), "serve").format_help()
|
|
for flag in PUBLIC_CLI_MCP_SERVE_FLAGS:
|
|
assert flag in mcp_serve_help_text
|
|
for profile_name in PUBLIC_MCP_PROFILES:
|
|
assert profile_name in mcp_serve_help_text
|
|
for mode_name in PUBLIC_MCP_MODES:
|
|
assert mode_name in mcp_serve_help_text
|
|
|
|
workspace_help_text = _subparser_choice(parser, "workspace").format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_help_text
|
|
workspace_create_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "create"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_CREATE_FLAGS:
|
|
assert flag in workspace_create_help_text
|
|
workspace_exec_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "exec"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_EXEC_FLAGS:
|
|
assert flag in workspace_exec_help_text
|
|
workspace_sync_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"),
|
|
"sync",
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_SYNC_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_sync_help_text
|
|
workspace_sync_push_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "sync"), "push"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SYNC_PUSH_FLAGS:
|
|
assert flag in workspace_sync_push_help_text
|
|
workspace_export_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "export"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_EXPORT_FLAGS:
|
|
assert flag in workspace_export_help_text
|
|
workspace_list_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "list"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_LIST_FLAGS:
|
|
assert flag in workspace_list_help_text
|
|
workspace_update_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "update"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_UPDATE_FLAGS:
|
|
assert flag in workspace_update_help_text
|
|
workspace_file_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "file"
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_FILE_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_file_help_text
|
|
workspace_file_list_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "list"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_FILE_LIST_FLAGS:
|
|
assert flag in workspace_file_list_help_text
|
|
workspace_file_read_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "read"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_FILE_READ_FLAGS:
|
|
assert flag in workspace_file_read_help_text
|
|
workspace_file_write_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "write"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_FILE_WRITE_FLAGS:
|
|
assert flag in workspace_file_write_help_text
|
|
workspace_patch_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "patch"
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_PATCH_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_patch_help_text
|
|
workspace_patch_apply_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "patch"), "apply"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_PATCH_APPLY_FLAGS:
|
|
assert flag in workspace_patch_apply_help_text
|
|
workspace_disk_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "disk"
|
|
).format_help()
|
|
for subcommand_name in ("export", "list", "read"):
|
|
assert subcommand_name in workspace_disk_help_text
|
|
workspace_disk_export_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "disk"), "export"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_DISK_EXPORT_FLAGS:
|
|
assert flag in workspace_disk_export_help_text
|
|
workspace_disk_list_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "disk"), "list"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_DISK_LIST_FLAGS:
|
|
assert flag in workspace_disk_list_help_text
|
|
workspace_disk_read_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "disk"), "read"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_DISK_READ_FLAGS:
|
|
assert flag in workspace_disk_read_help_text
|
|
workspace_diff_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "diff"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_DIFF_FLAGS:
|
|
assert flag in workspace_diff_help_text
|
|
workspace_snapshot_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"),
|
|
"snapshot",
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_SNAPSHOT_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_snapshot_help_text
|
|
workspace_snapshot_create_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "snapshot"),
|
|
"create",
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SNAPSHOT_CREATE_FLAGS:
|
|
assert flag in workspace_snapshot_create_help_text
|
|
workspace_snapshot_list_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "snapshot"),
|
|
"list",
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SNAPSHOT_LIST_FLAGS:
|
|
assert flag in workspace_snapshot_list_help_text
|
|
workspace_snapshot_delete_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "snapshot"),
|
|
"delete",
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SNAPSHOT_DELETE_FLAGS:
|
|
assert flag in workspace_snapshot_delete_help_text
|
|
workspace_reset_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "reset"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_RESET_FLAGS:
|
|
assert flag in workspace_reset_help_text
|
|
workspace_start_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "start"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_START_FLAGS:
|
|
assert flag in workspace_start_help_text
|
|
workspace_stop_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "stop"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_STOP_FLAGS:
|
|
assert flag in workspace_stop_help_text
|
|
workspace_summary_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"), "summary"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SUMMARY_FLAGS:
|
|
assert flag in workspace_summary_help_text
|
|
workspace_shell_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"),
|
|
"shell",
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_SHELL_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_shell_help_text
|
|
workspace_shell_open_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "shell"), "open"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SHELL_OPEN_FLAGS:
|
|
assert flag in workspace_shell_open_help_text
|
|
workspace_shell_read_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "shell"), "read"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SHELL_READ_FLAGS:
|
|
assert flag in workspace_shell_read_help_text
|
|
workspace_shell_write_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "shell"), "write"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SHELL_WRITE_FLAGS:
|
|
assert flag in workspace_shell_write_help_text
|
|
workspace_shell_signal_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "shell"), "signal"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SHELL_SIGNAL_FLAGS:
|
|
assert flag in workspace_shell_signal_help_text
|
|
workspace_shell_close_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "shell"), "close"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SHELL_CLOSE_FLAGS:
|
|
assert flag in workspace_shell_close_help_text
|
|
workspace_service_help_text = _subparser_choice(
|
|
_subparser_choice(parser, "workspace"),
|
|
"service",
|
|
).format_help()
|
|
for subcommand_name in PUBLIC_CLI_WORKSPACE_SERVICE_SUBCOMMANDS:
|
|
assert subcommand_name in workspace_service_help_text
|
|
workspace_service_start_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "service"), "start"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SERVICE_START_FLAGS:
|
|
assert flag in workspace_service_start_help_text
|
|
workspace_service_list_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "service"), "list"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SERVICE_LIST_FLAGS:
|
|
assert flag in workspace_service_list_help_text
|
|
workspace_service_status_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "service"), "status"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SERVICE_STATUS_FLAGS:
|
|
assert flag in workspace_service_status_help_text
|
|
workspace_service_logs_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "service"), "logs"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SERVICE_LOGS_FLAGS:
|
|
assert flag in workspace_service_logs_help_text
|
|
workspace_service_stop_help_text = _subparser_choice(
|
|
_subparser_choice(_subparser_choice(parser, "workspace"), "service"), "stop"
|
|
).format_help()
|
|
for flag in PUBLIC_CLI_WORKSPACE_SERVICE_STOP_FLAGS:
|
|
assert flag in workspace_service_stop_help_text
|
|
|
|
demo_help_text = _subparser_choice(parser, "demo").format_help()
|
|
for subcommand_name in PUBLIC_CLI_DEMO_SUBCOMMANDS:
|
|
assert subcommand_name in demo_help_text
|
|
|
|
|
|
def test_public_cli_version_matches_package_version() -> None:
|
|
parser = _build_parser()
|
|
stdout = io.StringIO()
|
|
with pytest.raises(SystemExit, match="0"), redirect_stdout(stdout):
|
|
parser.parse_args(["--version"])
|
|
assert stdout.getvalue().strip().endswith(f" {__version__}")
|
|
|
|
|
|
def test_public_mcp_tools_match_contract(tmp_path: Path) -> None:
|
|
pyro = Pyro(
|
|
manager=VmManager(
|
|
backend_name="mock",
|
|
base_dir=tmp_path / "vms",
|
|
network_manager=TapNetworkManager(enabled=False),
|
|
)
|
|
)
|
|
|
|
async def _run() -> tuple[str, ...]:
|
|
server = pyro.create_server()
|
|
tools = await server.list_tools()
|
|
return tuple(sorted(tool.name for tool in tools))
|
|
|
|
tool_names = asyncio.run(_run())
|
|
assert tool_names == tuple(sorted(PUBLIC_MCP_WORKSPACE_CORE_PROFILE_TOOLS))
|
|
|
|
|
|
def test_public_mcp_modes_are_declared_and_non_empty() -> None:
|
|
assert PUBLIC_MCP_MODES == ("repro-fix", "inspect", "cold-start", "review-eval")
|
|
assert PUBLIC_MCP_REPRO_FIX_MODE_TOOLS
|
|
assert PUBLIC_MCP_INSPECT_MODE_TOOLS
|
|
assert PUBLIC_MCP_COLD_START_MODE_TOOLS
|
|
assert PUBLIC_MCP_REVIEW_EVAL_MODE_TOOLS
|
|
|
|
|
|
def test_pyproject_exposes_single_public_cli_script() -> None:
|
|
pyproject = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
|
|
scripts = pyproject["project"]["scripts"]
|
|
assert scripts == {"pyro": "pyro_mcp.cli:main"}
|