CMDC.Sandbox behaviour (cmdc v0.5.3)

Copy Markdown View Source

文件操作和命令执行的抽象层。

Sandbox behaviour 将工具层(ReadFile/WriteFile/Shell 等)与底层执行环境解耦, 支持在不同环境下替换实现(本地 OS、Docker 容器、远程沙箱等), 而不需要修改任何工具代码。

默认实现

CMDC.Sandbox.Local — 直接调用本地操作系统,适合开发和受信任环境。

自定义实现示例

defmodule MyApp.DockerSandbox do
  @behaviour CMDC.Sandbox

  @impl true
  def read_file(path, opts) do
    working_dir = Keyword.get(opts, :working_dir, ".")
    # 在 Docker 容器内读取文件
    docker_exec("cat #{Path.join(working_dir, path)}")
  end

  # ... 其他回调实现
end

工具层透明代理模式

def execute(args, %{sandbox: sandbox} = ctx) when not is_nil(sandbox) do
  sandbox.execute(args["command"], working_dir: ctx.working_dir)
end

def execute(args, ctx) do
  CMDC.Sandbox.Local.execute(args["command"], working_dir: ctx.working_dir)
end

选项

所有回调均接受 opts keyword list,常见选项:

  • :working_dir — 操作相对目录,默认 "."
  • :timeout — 超时毫秒数(仅 execute/2 适用)
  • :offset — 读取偏移行数(仅 read_file/2 适用)
  • :limit — 读取最大行数(仅 read_file/2 适用)

Summary

Types

目录条目,描述单个文件或子目录。

glob 匹配文件条目。

grep 搜索匹配结果条目。

Callbacks

精确字符串替换文件内容(str_replace 模式)。

执行 shell 命令。

检查文件或目录是否存在。

在指定路径下搜索匹配 glob 模式的文件。

在指定路径下搜索匹配正则模式的文件行。

列出目录内容。

读取文件内容。

写入文件内容(覆盖)。若父目录不存在则自动创建。

Types

dir_entry()

@type dir_entry() :: %{
  name: String.t(),
  type: :file | :directory,
  size: non_neg_integer() | nil
}

目录条目,描述单个文件或子目录。

glob_match()

@type glob_match() :: %{path: String.t(), type: :file | :directory}

glob 匹配文件条目。

grep_match()

@type grep_match() :: %{
  file: String.t(),
  line: non_neg_integer(),
  content: String.t()
}

grep 搜索匹配结果条目。

Callbacks

edit_file(path, old_string, new_string, opts)

@callback edit_file(
  path :: String.t(),
  old_string :: String.t(),
  new_string :: String.t(),
  opts :: keyword()
) :: {:ok, non_neg_integer()} | {:error, :not_found | :not_unique | String.t()}

精确字符串替换文件内容(str_replace 模式)。

  • 要求 old_string 在文件中唯一出现,否则返回 {:error, :not_unique}
  • 成功时返回 {:ok, replacement_count}

选项:

  • :working_dir — 工作目录(默认 "."

execute(command, opts)

@callback execute(command :: String.t(), opts :: keyword()) ::
  {:ok, String.t()} | {:error, String.t()}

执行 shell 命令。

选项:

  • :working_dir — 命令执行目录(默认 "."
  • :timeout — 超时毫秒数(默认 30_000)
  • :env — 额外环境变量 keyword list

file_exists?(path, opts)

@callback file_exists?(path :: String.t(), opts :: keyword()) :: boolean()

检查文件或目录是否存在。

选项:

  • :working_dir — 工作目录(默认 "."

glob(pattern, path, opts)

@callback glob(pattern :: String.t(), path :: String.t(), opts :: keyword()) ::
  {:ok, [glob_match()]} | {:error, String.t()}

在指定路径下搜索匹配 glob 模式的文件。

选项:

  • :working_dir — 工作目录(默认 "."
  • :max_results — 最大返回结果数(默认 500)

grep(pattern, path, opts)

@callback grep(pattern :: String.t(), path :: String.t(), opts :: keyword()) ::
  {:ok, [grep_match()]} | {:error, String.t()}

在指定路径下搜索匹配正则模式的文件行。

选项:

  • :working_dir — 工作目录(默认 "."
  • :include — glob 过滤,如 "*.ex"(默认全部)
  • :case_insensitive — 是否忽略大小写(默认 false)
  • :max_results — 最大返回结果数(默认 100)

list_dir(path, opts)

@callback list_dir(path :: String.t(), opts :: keyword()) ::
  {:ok, [dir_entry()]} | {:error, String.t()}

列出目录内容。

选项:

  • :working_dir — 工作目录(默认 "."

read_file(path, opts)

@callback read_file(path :: String.t(), opts :: keyword()) ::
  {:ok, String.t()} | {:error, String.t()}

读取文件内容。

选项:

  • :working_dir — 工作目录(默认 "."
  • :offset — 从第几行开始读取(1 起始,默认 1)
  • :limit — 最多读取多少行(nil 则读取全部)

write_file(path, content, opts)

@callback write_file(path :: String.t(), content :: String.t(), opts :: keyword()) ::
  :ok | {:error, String.t()}

写入文件内容(覆盖)。若父目录不存在则自动创建。

选项:

  • :working_dir — 工作目录(默认 "."