Current section

Files

Jump to
cmdc lib cmdc tool edit_file.ex
Raw

lib/cmdc/tool/edit_file.ex

defmodule CMDC.Tool.EditFile do
@moduledoc """
通过精确字符串替换编辑文件(str_replace 模式)。
使用 `old_string` 定位文件中唯一的目标片段并替换为 `new_string`
`old_string` 必须在文件中**唯一出现**;若有多处匹配则返回错误,要求提供更多上下文。
- 有 Sandbox 时走 `sandbox.edit_file/4`
- 无 Sandbox 时走 `CMDC.Sandbox.Local`
## 使用示例
# 替换特定代码片段
edit_file(path: "lib/app.ex",
old_string: "def hello, do: :world",
new_string: "def hello, do: :universe"
)
# 删除一段内容(new_string 为空字符串)
edit_file(path: "lib/app.ex",
old_string: "\\n # TODO: remove this line",
new_string: ""
)
"""
@behaviour CMDC.Tool
alias CMDC.Sandbox.Local, as: SandboxLocal
@impl true
def name, do: "edit_file"
@impl true
def description,
do:
"Edit a file by replacing a unique string occurrence. " <>
"old_string must appear exactly once in the file. " <>
"Use read_file first to identify the exact string to replace."
@impl true
def meta(%{"path" => path}), do: "Edit #{path}"
def meta(_), do: "Edit file"
@impl true
def parameters do
%{
"type" => "object",
"properties" => %{
"path" => %{
"type" => "string",
"description" => "Path to the file to edit (relative to working_dir or absolute)"
},
"old_string" => %{
"type" => "string",
"description" =>
"The exact string to find and replace. Must appear exactly once in the file."
},
"new_string" => %{
"type" => "string",
"description" =>
"The replacement string. Use empty string \"\" to delete the old_string."
}
},
"required" => ["path", "old_string", "new_string"]
}
end
@impl true
def execute(
%{"path" => path, "old_string" => old_string, "new_string" => new_string},
%CMDC.Context{} = ctx
) do
opts = [working_dir: ctx.working_dir]
result =
if ctx.sandbox do
ctx.sandbox.edit_file(path, old_string, new_string, opts)
else
SandboxLocal.edit_file(path, old_string, new_string, opts)
end
case result do
{:ok, _count} ->
{:ok, "Edit applied to: #{path}"}
{:error, :not_found} ->
{:error,
"old_string not found in #{path}. " <>
"Use read_file to verify the exact content and try again."}
{:error, :not_unique} ->
{:error,
"old_string appears multiple times in #{path}. " <>
"Provide a longer, more unique string with surrounding context."}
{:error, reason} ->
{:error, reason}
end
end
def execute(_args, _ctx),
do: {:error, "Missing required parameters: path, old_string, and new_string"}
end