lib/bb/mcp/resources/robot_commands.ex

# SPDX-FileCopyrightText: 2026 James Harton
#
# SPDX-License-Identifier: Apache-2.0

defmodule BB.MCP.Resources.RobotCommands do
  @moduledoc """
  Declared commands on a robot, with typed argument schemas.

  Read via `bb://robots/{robot}/commands`. The same data is available
  via the `list_commands` tool — this resource exists so agents can
  load the command catalogue as context before invoking anything.
  """

  use Anubis.Server.Component,
    type: :resource,
    uri_template: "bb://robots/{robot}/commands",
    name: "robot_commands"

  alias Anubis.Server.Response
  alias BB.Dsl.Info
  alias BB.MCP.JsonSchema
  alias BB.MCP.Resources

  @impl true
  def description, do: "Commands declared in the robot's Spark DSL"

  @impl true
  def mime_type, do: "application/json"

  @impl true
  def read(params, frame) do
    case Resources.fetch_robot(params) do
      {:ok, module} ->
        commands =
          module
          |> Info.commands()
          |> Enum.map(fn cmd ->
            %{
              "name" => Atom.to_string(cmd.name),
              "category" => to_string(cmd.category || ""),
              "allowed_states" => Enum.map(cmd.allowed_states, &Atom.to_string/1),
              "timeout" => format_timeout(cmd.timeout),
              "arguments" => JsonSchema.for_command(cmd)
            }
          end)

        {:reply, Response.json(Response.resource(), %{"commands" => commands}), frame}

      {:error, error} ->
        {:error, error, frame}
    end
  end

  defp format_timeout(:infinity), do: "infinity"
  defp format_timeout(timeout) when is_integer(timeout), do: timeout
end