10 KiB
AI 文件操作工具手册
最后更新:2026-06-16 | 基于代码核对(
src-tauri/src/commands/ai/tool_registry.rs)本文档覆盖 AI 助手可调用的全部文件系统工具。项目/任务/灵感等 CRUD 工具见使用手册。
工具总览
| 工具 | 用途 | 风险等级 | 需审批 |
|---|---|---|---|
read_file |
读取文件内容(全文/分页/搜索) | Low | 否 |
write_file |
创建/覆盖写入文件(文本 + base64 二进制) | Medium | 是 |
patch_file |
局部更新文件(精确匹配替换) | Medium | 是 |
append_file |
向文件末尾追加内容 | Medium | 是 |
file_info |
获取文件元信息(不读内容) | Low | 否 |
list_directory |
列出目录内容(含递归/深度控制) | Low | 否 |
search_files |
按文件名模式搜索文件 | Low | 否 |
rename_file |
重命名/移动文件(Rust 原生,中文路径无障碍) | Medium | 是 |
delete_file |
删除文件(默认软删除可恢复) | High | 是 |
run_command |
执行 shell 命令 | High | 是 |
路径安全:所有文件工具走
validate_path黑名单(禁止..路径遍历 + 敏感系统目录.ssh/.aws/.gnupg)+resolve_workspace_path双层校验(词法starts_with+canonicalize防 symlink 逃逸)。文件操作限制在 workspace 目录内。
read_file
读取文件内容,支持分页和行内搜索。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 文件路径(workspace 内) |
offset |
number | ❌ | 起始行(0 基索引),默认 0 |
limit |
number | ❌ | 读取行数,默认 200,硬上限 2000 |
search |
string | ❌ | 搜索模式:按行过滤含该子串的行(大小写敏感) |
行为规则
offset是 0 基索引:offset=0 → 第 1 行,offset=10 → 第 11 行offset超出总行数 → 返回空内容,不报错- 文件大小上限 1MB,超出报错
- 二进制文件 → 返回
{ binary: true, content: null } - 不存在的文件 → 报错
search 模式返回结构
{
"path": "...",
"size": 145,
"search": "keyword",
"matches": [{ "line": 12, "content": "匹配行内容" }],
"total": 3,
"has_more": false
}
line为 1 基行号(与 offset 的 0 基不同)。最多返回 50 条匹配。
默认(分页)返回结构
{
"path": "...",
"content": "文件文本内容",
"size": 145,
"lines": 30
}
lines和size始终返回全量值,不受 offset/limit 影响。
write_file
创建或覆盖写入文件。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 文件路径 |
content |
string | ✅ | 内容(UTF-8 文本 或 base64 编码) |
encoding |
string | ❌ | "utf-8"(默认)或 "base64"(写二进制:图片/PDF/Excel) |
行为规则
- 自动创建多级父目录
- 覆盖已有文件:覆盖前自动
.bak备份(非空文件),原子写(tmp→rename),成功后清理.bak - 疑似误覆盖检测:新内容 < 旧内容 10% 时 warn 提示(防全量覆盖事故)
- 写入大小上限 1MB
encoding="base64":解码后写字节,支持二进制文件- 返回
old_size(覆盖前大小,新建时为 null)和bytes_written
⚠️ 局部修改请用 patch_file
write_file 是全量覆盖。局部修改用 patch_file(精确匹配替换,无需重发整个文件)。
patch_file
局部更新文件,精确匹配 old_text 并替换为 new_text。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 目标文件路径 |
old_text |
string | ✅ | 要替换的精确文本(必须完全匹配含空格/缩进) |
new_text |
string | ✅ | 替换后的新文本 |
line |
number | ❌ | 行号辅助定位(快速跳转 + 去歧) |
expected_hash |
string | ❌ | 文件指纹防脏写("{mtime_secs}_{size}") |
安全机制(三层防御)
| 层 | 机制 | 作用 |
|---|---|---|
| L1 | 文件级 Mutex | 防同文件并发写冲突 |
| L2 | old_text 精确匹配 | 防内容错配(不匹配则报错,不修改) |
| L3 | expected_hash 指纹 | 防版本漂移(文件被外部修改则拒绝) |
| 兜底 | .bak 备份 | 误操作可恢复 |
返回结构
{
"path": "...",
"changed": true,
"size_diff": -42,
"matches_found": 1,
"diff": " context line\n-old line\n+new line\n",
"warning": "匹配到 3 处,仅替换第 1 处"
}
diff为行级 unified diff,供审批卡展示。多处匹配时仅替换第 1 处并返回 warning。
append_file
向文件末尾追加内容,文件不存在则自动创建。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 文件路径 |
content |
string | ✅ | 追加的文本内容 |
返回结构
{ "path": "...", "bytes_written": 128, "new_size": 1024 }
避免 read-merge-write 竞态:日志追加/增量写入直接用此工具。
file_info
获取文件或目录的元信息,不读取文件内容。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 文件/目录路径 |
返回结构
{
"path": "...",
"exists": true,
"size": 145,
"lines": 30,
"modified": 1718400000000,
"is_binary": false,
"is_dir": false
}
exists: false时其余字段不返回lines:文本文件\n计数(>2MB 跳过,二进制不返回)is_binary:读前 8KB 检测\x00
list_directory
列出目录内容,支持递归和深度控制。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 目录路径 |
recursive |
boolean | ❌ | 是否递归,默认 false |
max_depth |
number | ❌ | 递归最大深度,默认 3 |
skip_noise_dirs |
boolean | ❌ | 跳过 node_modules/.git/target,默认 true |
返回结构
{
"path": "...",
"entries": [
{ "name": "src", "type": "directory", "size": 0, "depth": 0 },
{ "name": "main.ts", "type": "file", "size": 466, "depth": 0 }
],
"truncated": false
}
search_files
按文件名模式搜索文件(字符串包含匹配,非 glob)。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 搜索根目录 |
pattern |
string | ✅ | 文件名匹配模式(子串包含) |
recursive |
boolean | ❌ | 是否递归,默认 true |
返回结构
{
"path": "...",
"pattern": ".ts",
"results": [{ "path": "src/main.ts", "size": 466 }],
"total": 5
}
最多返回 50 条。结构化 JSON 输出,比 parse
find命令更可靠。
rename_file
重命名或移动文件(一个工具覆盖 rename + move)。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
from |
string | ✅ | 源文件路径 |
to |
string | ✅ | 目标路径 |
overwrite |
boolean | ❌ | 目标存在时是否覆盖,默认 false(拒绝) |
行为规则
- 同卷:
tokio::fs::rename(原子操作,Windows 走MoveFileExWUTF-16 API,中文路径零字符集问题) - 跨卷:自动降级
copy + remove(非原子,失败回滚删 to 保 from 完整) - 仅支持文件(不支持目录,目录操作用
run_command) - 返回
{ renamed, bytes_moved, cross_volume }
为什么不用 run_command mv:run_command 走 shell.rs 的 PS/cmd 链,中文路径经 GBK 解码 UTF-8 会 mojibake → exit 0 静默失败。此工具 Rust 原生 std::fs 绕开整个 shell 层。
delete_file
删除文件,默认软删除(移入回收站可恢复)。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
path |
string | ✅ | 文件路径 |
permanent |
boolean | ❌ | true=硬删除不可恢复,false(默认)=软删除移入 .trash/ |
返回结构
// 软删除
{ "path": "...", "deleted": true, "permanent": false, "backed_up": true, "backup_path": ".trash/abc-file.md" }
// 硬删除
{ "path": "...", "deleted": true, "permanent": true, "backed_up": false }
- 仅支持文件(不支持目录)
- 软删除文件移到
workspace/.trash/<uuid>-<filename>,对齐list_trash机制
run_command
在指定工作目录执行 shell 命令。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
command |
string | ✅ | shell 命令(非交互式) |
working_dir |
string | ❌ | 工作目录(默认 workspace 根) |
timeout_secs |
number | ❌ | 超时秒数,默认 60 |
返回结构
{
"command": "npm test",
"working_dir": "...",
"exit_code": 0,
"duration_ms": 3200,
"stdout": "测试输出...",
"stderr": "",
"truncated": false
}
- stdout/stderr 各截断 10KB(尾部保留,报错堆栈在末尾)
truncated: true表示输出被截断
安全边界
- High 风险,强制人工审批(审批卡显示 command + working_dir)
- 唯一防线:人审 +
validate_path黑名单 - 未做命令黑名单/网络检测/资源限制
⚠️ 已知限制
- 中文路径:shell.rs 在 Windows 走 PS/cmd 链,中文路径经 GBK 解码可能 mojibake → exit 0 静默失败。涉及中文路径的文件操作请用原生工具(
rename_file/delete_file等) - 非交互式:避免需要用户输入的程序
快速参考:常见操作怎么做
| 我想要... | 推荐工具 |
|---|---|
| 读文件全文 | read_file(path) |
| 读第 10~15 行 | read_file(path, offset=9, limit=6) |
| 搜索文件内关键词 | read_file(path, search="keyword") |
| 创建新文件 | write_file(path, content) |
| 修改文件中某几行 | patch_file(path, old_text, new_text) |
| 追加内容到文件末尾 | append_file(path, content) |
| 写入二进制文件(图片/PDF) | write_file(path, base64_content, encoding="base64") |
| 重命名/移动文件 | rename_file(from, to) |
| 删除文件 | delete_file(path) |
| 获取文件大小/行数/类型 | file_info(path) |
| 列出项目结构 | list_directory(path, recursive=true, max_depth=3) |
| 搜索文件名 | search_files(path, pattern=".ts") |
| 跑测试/构建 | run_command("npm test") |