add CLI parity commands for credential, block, and browser (#4793)
This commit is contained in:
110
skyvern/cli/credential.py
Normal file
110
skyvern/cli/credential.py
Normal file
@@ -0,0 +1,110 @@
|
||||
"""Credential CLI commands with MCP-parity output and validation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from typing import Any, Callable, Coroutine
|
||||
|
||||
import typer
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from skyvern.config import settings
|
||||
from skyvern.utils.env_paths import resolve_backend_env_path
|
||||
|
||||
from .commands._output import output, output_error
|
||||
from .mcp_tools.credential import skyvern_credential_delete as tool_credential_delete
|
||||
from .mcp_tools.credential import skyvern_credential_get as tool_credential_get
|
||||
from .mcp_tools.credential import skyvern_credential_list as tool_credential_list
|
||||
|
||||
credential_app = typer.Typer(
|
||||
help="MCP-parity credential commands (list/get/delete). Use `skyvern credentials add` for secure creation.",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
|
||||
|
||||
def _emit_tool_result(result: dict[str, Any], *, json_output: bool) -> None:
|
||||
if json_output:
|
||||
json.dump(result, sys.stdout, indent=2, default=str)
|
||||
sys.stdout.write("\n")
|
||||
if not result.get("ok", False):
|
||||
raise SystemExit(1)
|
||||
return
|
||||
|
||||
if result.get("ok", False):
|
||||
output(result.get("data"), action=str(result.get("action", "")), json_mode=False)
|
||||
return
|
||||
|
||||
err = result.get("error") or {}
|
||||
output_error(str(err.get("message") or "Unknown error"), hint=str(err.get("hint") or ""), json_mode=False)
|
||||
|
||||
|
||||
def _run_tool(
|
||||
runner: Callable[[], Coroutine[Any, Any, dict[str, Any]]],
|
||||
*,
|
||||
json_output: bool,
|
||||
hint_on_exception: str,
|
||||
) -> None:
|
||||
try:
|
||||
result: dict[str, Any] = asyncio.run(runner())
|
||||
_emit_tool_result(result, json_output=json_output)
|
||||
except typer.BadParameter:
|
||||
raise
|
||||
except Exception as e:
|
||||
output_error(str(e), hint=hint_on_exception, json_mode=json_output)
|
||||
|
||||
|
||||
@credential_app.callback()
|
||||
def credential_callback(
|
||||
api_key: str | None = typer.Option(
|
||||
None,
|
||||
"--api-key",
|
||||
help="Skyvern API key",
|
||||
envvar="SKYVERN_API_KEY",
|
||||
),
|
||||
) -> None:
|
||||
"""Load environment and optional API key override."""
|
||||
load_dotenv(resolve_backend_env_path())
|
||||
if api_key:
|
||||
settings.SKYVERN_API_KEY = api_key
|
||||
|
||||
|
||||
@credential_app.command("list")
|
||||
def credential_list(
|
||||
page: int = typer.Option(1, "--page", min=1, help="Page number (1-based)."),
|
||||
page_size: int = typer.Option(10, "--page-size", min=1, max=100, help="Results per page."),
|
||||
json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
|
||||
) -> None:
|
||||
"""List stored credentials (metadata only)."""
|
||||
|
||||
async def _run() -> dict[str, Any]:
|
||||
return await tool_credential_list(page=page, page_size=page_size)
|
||||
|
||||
_run_tool(_run, json_output=json_output, hint_on_exception="Check your API key and Skyvern connection.")
|
||||
|
||||
|
||||
@credential_app.command("get")
|
||||
def credential_get(
|
||||
credential_id: str = typer.Option(..., "--id", "--credential-id", help="Credential ID (starts with cred_)."),
|
||||
json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
|
||||
) -> None:
|
||||
"""Get credential metadata by ID."""
|
||||
|
||||
async def _run() -> dict[str, Any]:
|
||||
return await tool_credential_get(credential_id=credential_id)
|
||||
|
||||
_run_tool(_run, json_output=json_output, hint_on_exception="Check your API key and credential ID.")
|
||||
|
||||
|
||||
@credential_app.command("delete")
|
||||
def credential_delete(
|
||||
credential_id: str = typer.Option(..., "--id", "--credential-id", help="Credential ID (starts with cred_)."),
|
||||
json_output: bool = typer.Option(False, "--json", help="Output as JSON."),
|
||||
) -> None:
|
||||
"""Delete a credential by ID."""
|
||||
|
||||
async def _run() -> dict[str, Any]:
|
||||
return await tool_credential_delete(credential_id=credential_id)
|
||||
|
||||
_run_tool(_run, json_output=json_output, hint_on_exception="Check your API key and credential ID.")
|
||||
Reference in New Issue
Block a user