# 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 模式返回结构

```json
{
  "path": "...",
  "size": 145,
  "search": "keyword",
  "matches": [{ "line": 12, "content": "匹配行内容" }],
  "total": 3,
  "has_more": false
}
```

> `line` 为 **1 基行号**（与 offset 的 0 基不同）。最多返回 50 条匹配。

### 默认（分页）返回结构

```json
{
  "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 备份 | 误操作可恢复 |

### 返回结构

```json
{
  "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。

> 详见 [patch_file 使用指南](./patch_file使用指南.md)

---

## append_file

向文件末尾追加内容，文件不存在则自动创建。

### 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `path` | string | ✅ | 文件路径 |
| `content` | string | ✅ | 追加的文本内容 |

### 返回结构

```json
{ "path": "...", "bytes_written": 128, "new_size": 1024 }
```

> 避免 read-merge-write 竞态：日志追加/增量写入直接用此工具。

---

## file_info

获取文件或目录的元信息，**不读取文件内容**。

### 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `path` | string | ✅ | 文件/目录路径 |

### 返回结构

```json
{
  "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** |

### 返回结构

```json
{
  "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 |

### 返回结构

```json
{
  "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 走 `MoveFileExW` UTF-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/` |

### 返回结构

```json
// 软删除
{ "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 |

### 返回结构

```json
{
  "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")` |
