1. 任务定约
这一节把“我想要一个很强大的文件 CLI”翻译成可执行、可验证的工程目标,避免后续实现一开始就因为边界不清而膨胀。
Objective
- 设计一个名为
fileglide的 CLI 工具,用于文件与路径管理、遍历、检索、尺寸感知与精确读写编辑。 - 把工具设计成对 AI agent 友好的结构化能力层,而不是偏人类交互的小脚本集合。
- 在编码适配上把
utf-8 without bom作为第一优先,同时兼容常见中文、日文及非 ASCII 语言文本。 - 把“文件名模糊匹配”和“文件内容正则检索”设计成一等能力,而不是附加选项。
Non-goals
- 本阶段不实现 GUI、不实现远程分布式文件系统、不设计数据库索引服务。
- 本阶段不引入过重守护进程或后台常驻服务。
- 本阶段不尝试做 IDE 级别的 AST 重构工具;精确编辑仍以文本模型为主。
- 本阶段不处理复杂权限提升工作流与系统级沙箱。
Scope
- 创建、删除、列举、搜索、读取、写入、追加、插入、按行精确编辑。
- 全局与局部范围控制。
- 结构化输出与 agent 友好返回。
- 编码探测、文本归一化、异常反馈、验证策略。
Verification
- 命令契约测试:参数、输出格式、错误码、危险操作确认链路。
- 文件语义测试:覆盖写、尾追加、中间插入、行区间替换、编码保真。
- 搜索测试:正则内容检索、Levenshtein 文件名匹配排序、范围约束。
- 跨编码回归:UTF-8、UTF-8 with BOM、GBK、GB18030、Shift-JIS、EUC-JP、Latin-1 等样本集。
2. 设计原则
2.1 Agent First
所有命令都应同时服务人类和 agent,但默认优先保证 agent 可解析性:输出结构统一、字段稳定、错误有代码、行为不隐式。
2.2 薄入口
参考 OpenTrade,入口层只负责 CLI 暴露与装配,不承载业务逻辑。命令定义、执行器、服务层、编码与搜索能力彼此分离。
2.3 默认最小副作用
读取默认安全;写入、删除、批量变更必须显式;高风险命令默认支持预览、dry-run 或确认策略。
2.4 可组合
遍历结果、搜索结果、精确定位结果应使用统一记录模型,使后续过滤、写回、批量操作可以复用同一套执行编排。
2.5 文本保真
读取与编辑必须尽可能保留原始换行风格、编码和 BOM 信息,并让调用方显式知道当前操作是否发生编码规范化。
2.6 模式导向
用命令模式、策略模式、门面模式、模板方法控制复杂度,避免 CLI 逻辑、文件逻辑、编码逻辑糊成一团。
3. 能力范围与能力矩阵
用户需求中的 1.x 与 2.x 能力,工程上可以整理成六类能力域。每一类都要有明确的数据输入、范围控制和输出结构。
| 能力域 | 目标 | 典型命令 | 输出重点 |
|---|---|---|---|
| 路径与文件生命周期 | 创建、删除、覆盖存在项、递归创建、递归删除 | path create、path delete、file create、file delete | 是否变更、影响对象、失败原因 |
| 遍历与枚举 | 全局/局部列出路径与文件,支持深度、过滤、排序 | path list、file list、tree scan | 条目清单、统计、裁剪信息 |
| 搜索与检索 | 按文件名、路径名、文件内容进行匹配、模糊排序、正则搜索 | path search、file search、text grep | 命中项、评分、上下文片段、位置信息 |
| 尺寸与统计 | 文件大小、目录聚合大小、子树大小、条目数、编码统计 | size file、size path | 字节数、可读化尺寸、统计维度 |
| 文本读取 | 整文件、尾部、范围、行、行区间、精确片段读取 | file read、file lines、file slice | 文本、行号、偏移、编码元数据 |
| 文本写入与编辑 | 覆盖、尾追加、中部插入、行替换、范围替换、精确编辑 | file write、file append、file insert、file patch | 变更摘要、前后 diff、写回结果 |
4. CLI 命令面设计
命令面建议沿用 OpenTrade 的 root command + group + leaf command 组织方式。这样可读、可测试,也便于后续自动生成命令目录与 agent 文档。
4.1 顶层命令树
fileglide
|-- file
| |-- create
| |-- delete
| |-- read
| |-- lines
| |-- write
| |-- append
| |-- insert
| |-- patch
| |-- list
| |-- search
| `-- stat
|-- path
| |-- create
| |-- delete
| |-- list
| |-- search
| `-- stat
|-- tree
| |-- scan
| |-- summary
| `-- size
|-- text
| |-- grep
| |-- extract
| `-- replace-preview
|-- inspect
| |-- encoding
| |-- newline
| `-- bom
`-- batch
|-- run-plan
`-- apply-plan
4.2 顶层设计理由
file 与 path 分离
路径和文件虽然都属于 filesystem entry,但其副作用、返回结构和用户意图不同。拆开后更利于参数语义清晰,也更利于测试。
tree 聚合视角
tree 不做单个实体操作,而做子树视角的扫描、摘要和大小统计,作为全局/局部遍历与容量分析入口。
text 独立
内容检索与文本提取是“基于文件内容”的一类能力,不应被埋进 file search 一个命令里,否则内容匹配和文件名匹配会混淆。
inspect 面向诊断
编码识别、换行风格、BOM 检查应独立成诊断工具,既能为写入前决策服务,也便于排障。
4.3 统一运行时参数
| 参数 | 作用 | 说明 |
|---|---|---|
--root | 限定操作根目录 | 用于局部作用域控制,是 agent 安全执行的关键参数。 |
--recursive | 递归遍历 | 默认关闭或按命令设置明确默认值,避免误扫大目录。 |
--max-depth | 限制深度 | 全局扫描必须支持深度裁剪。 |
--format | 输出格式 | 建议支持 table、json、jsonl、text。 |
--dry-run | 预演副作用 | 删除、批量编辑、覆盖写入默认支持。 |
--encoding | 显式编码 | 当调用方已知编码时应允许跳过探测。 |
--output | 写到目标文件 | 面向 agent 的流水线式使用。 |
5. 架构分层
fileglide 的核心不是“命令很多”,而是“层次清楚”。只有分层清楚,后续能力扩展才不会让 CLI、编码探测、文本编辑和搜索逻辑相互污染。
CLI Entry
-> App Assembly
-> Command Builders
-> Executor
-> Facade
-> Domain Services
- TraversalService
- SearchService
- EncodingService
- TextReadService
- TextEditService
- StatService
-> Filesystem Gateway
-> Renderers
5.1 Entry Layer
main.py 与 __main__.py 只暴露 CLI,不承载领域逻辑。
5.2 App Layer
app.py 负责装配命令树,保持极薄,作用类似 OpenTrade 的应用装配入口。
5.3 Command Layer
commands/ 负责 Click 命令组、参数定义、帮助文本和命令树构建。
5.4 Executor Layer
把 CLI 请求转成标准化执行请求,统一处理 dry-run、输出格式、错误映射、批量调用。
5.5 Facade Layer
门面负责把高层命令意图分派给遍历、搜索、编码、编辑等领域服务,并聚合标准结果。
5.6 Domain Layer
真正处理文件系统、编码探测、文本定位、Levenshtein 排序、正则检索与精确编辑。
5.7 关键模式落点
| 模式 | 落点 | 价值 |
|---|---|---|
| Command Pattern | CLI 命令与执行请求对象 | 让命令结构和执行逻辑解耦,便于测试和批量计划执行。 |
| Facade Pattern | facade.py | 统一暴露文件系统能力,避免 CLI 直接依赖底层细节。 |
| Strategy Pattern | 编码探测、匹配排序、写回策略 | 编码兼容与匹配逻辑未来一定扩展,策略模式更合适。 |
| Template Method | 读取、编辑、写回流程骨架 | 在“探测 -> 解析 -> 操作 -> 校验 -> 写回”流程中保持稳定步骤顺序。 |
| Value Object | 路径、文本范围、行区间、匹配结果 | 降低字符串乱飞和状态混乱。 |
6. 核心数据模型
若没有统一的记录模型,遍历、搜索和编辑的结果就无法复用。AI agent 场景下尤其需要结构化对象而非一堆随意拼装的字典。
6.1 EntryRecord
EntryRecord
- path: str
- kind: file | directory | symlink | other
- name: str
- relative_path: str
- size_bytes: int | null
- exists: bool
- encoding: str | null
- newline: lf | crlf | cr | mixed | null
- bom: utf8-bom | utf16-le | utf16-be | none | unknown
- modified_at: str | null6.2 TextSlice
TextSlice
- path: str
- encoding_used: str
- line_start: int | null
- line_end: int | null
- char_start: int | null
- char_end: int | null
- byte_start: int | null
- byte_end: int | null
- text: str
- newline: str | null6.3 SearchHit
SearchHit
- path: str
- hit_type: filename | pathname | content
- score: float | null
- matcher: exact | regex | levenshtein | contains
- line_number: int | null
- column_start: int | null
- column_end: int | null
- preview: str | null6.4 EditPlan / EditResult
EditPlan
- operation: overwrite | append | insert | replace-lines | replace-range
- target_path: str
- expected_version: str | null
- backup: bool
- payload: ...
EditResult
- changed: bool
- bytes_before: int
- bytes_after: int
- diff_preview: str | null
- encoding_kept: bool
- newline_kept: bool7. 编码与文本策略
这是 fileglide 区别于普通文件工具的关键部分。用户明确要求“UTF-8 without BOM 完美适配,以及其他所有常见编码完美适配”。工程上不能写成空话,必须给出明确的解码、保真、写回和失败策略。
7.1 编码处理原则
- 默认写回目标: 新建文本文件默认写为
utf-8无 BOM。 - 读取优先级: 先显式参数,再 BOM 判断,再已知编码候选,再启发式探测,再保底替换读取。
- 写回优先级: 默认保留原编码、原 BOM、原换行风格;除非用户显式要求规范化。
- 错误策略: 区分“无法探测编码”“可读取但存在替换字符”“写回将丢失字符”。
- 文本与字节双轨: 所有精确编辑命令既要理解文本位置,也要在必要时能报告字节偏移。
7.2 推荐支持的编码层次
| 层次 | 编码 | 说明 |
|---|---|---|
| 第一优先 | utf-8 / utf-8-sig | 项目默认,面向 agent 与跨平台协作的主流编码。 |
| 中文常见 | gbk / gb18030 | Windows 中文环境常见,必须完整覆盖。 |
| 日文常见 | shift_jis / cp932 / euc_jp | 日文工程与历史文本常见。 |
| Unicode 扩展 | utf-16-le / utf-16-be / utf-32 | 通常结合 BOM 识别。 |
| 兼容保底 | latin-1 等 | 用于尽量不报错地打开文本,但需要明确提示可信度较低。 |
7.3 编码服务职责
EncodingService.detect()
- 读取字节样本与完整文件头。
- 识别 BOM。
- 根据显式参数或优先候选尝试严格解码。
- 输出置信度、替换字符风险、是否适合写回。
EncodingService.encode_for_write()
- 决定最终写回编码、BOM、换行。
- 提前检查字符是否可编码,避免部分写入后失败。
- 必要时向调用方返回“需规范化写回”的显式风险。
8. 检索与匹配设计
8.1 文件名 / 路径名检索
文件名与路径名检索分为四种模式:exact、contains、glob、fuzzy。其中 fuzzy 必须基于 vortezwohl.nlp.LevenshteinDistance 实现,这是用户明确要求,不应替换成自定义低质量近似算法。
fuzzy 搜索建议流程
1. 遍历候选文件名或相对路径
2. 先做大小写归一化与 Unicode 规范化
3. 使用 LevenshteinDistance.rank() 进行排序
4. 结合 exact / prefix / contains 结果做分层加权
5. 输出 score、distance、matched_part 和排序原因
为什么必须引入分层加权
纯 Levenshtein 距离会把很多“编辑距离接近但语义差很远”的候选排得过高。实际工程应把 exact/prefix/contains 放在更高优先级。
为什么路径搜索要支持相对路径
AI agent 在工作区内常持有相对定位上下文。只搜 basename 不够,必须支持相对路径模糊检索。
8.2 文件内容检索
内容检索建议采用“遍历层 + 文本解码层 + 匹配层”三段式设计。匹配层应支持普通子串、正则表达式、大小写控制、上下文窗口和行号输出。
| 能力 | 设计要求 | 返回信息 |
|---|---|---|
| 普通文本搜索 | 支持大小写控制、限制命中数、上下文行数 | 命中行、预览、命中次数 |
| 正则搜索 | 支持 Python 风格正则、编译失败提示、可选多行模式 | 命中分组、偏移、预览片段 |
| 全局 / 局部搜索 | 必须支持 --root、--include、--exclude、--max-depth | 范围约束回显 |
| 大文件控制 | 可设置最大读取大小、二进制文件跳过策略 | 跳过原因、阈值信息 |
8.3 大目录搜索性能策略
- 遍历层先过滤文件类型和路径模式,避免无意义打开大量文件。
- 读取层支持采样与大小阈值,避免超大文件拖垮全局搜索。
- 可选引入线程池并发读取,但必须保留输出顺序或显式排序回放。
- 若后续用到并发,可优先复用
vortezwohl.concurrent.ThreadPool,而不是自写松散线程控制。
9. 精确编辑设计
文件编辑是最容易把“工具做强”变成“工具做危险”的部分。设计上要把不同编辑语义拆开,而不是用一个 write 命令包打天下。
9.1 编辑能力拆分
| 命令 | 语义 | 适用场景 |
|---|---|---|
file write | 整文件覆盖写入 | 新建或整体重写文本文件 |
file append | 尾部追加 | 日志、尾部补充内容 |
file insert | 按字符偏移、字节偏移或定位锚点插入 | 中部插入文本 |
file patch | 按行号、行区间、文本范围、锚点规则替换 | 精确编辑和批量规则化修改 |
file lines | 按单行或行区间读取 | 给 agent 精确上下文 |
file slice | 按字符、字节、正则命中区间读取 | 精确读取某片段 |
9.2 编辑执行骨架
1. 读取原始字节
2. 探测编码、BOM、换行风格
3. 解码为文本,并记录文本与字节映射
4. 定位目标区间(按行/按字符/按锚点/按正则)
5. 生成变更计划与 diff 预览
6. 校验是否满足预期前置条件
7. 按原编码或目标编码写回
8. 重新读取并做最小验证
9.3 定位方式设计
按行定位
最稳定,适合 agent 已知上下文时的精确编辑。需要定义 1-based 行号还是 0-based 行号,建议统一使用 1-based。
按范围定位
支持字符区间、字节区间。字节区间更适合诊断和保底,但文本编辑默认应优先字符区间。
按锚点定位
适合“在某段后插入”“替换某个唯一块”。需要支持 before/after/replace-first/replace-all 等模式。
9.4 并发与防误改控制
- 编辑命令建议支持
--expect-hash或--expect-mtime,防止文件被外部修改后误覆盖。 - 高风险编辑默认支持
--backup与--dry-run。 - 返回结果要明确说明是否保留原编码、原 BOM、原换行风格。
10. 安全、错误模型与一致性策略
10.1 错误模型
fileglide 不应只输出“失败了”。应建立结构化错误类型,例如:PathNotFound、EncodingDetectFailed、UnsafeDeleteDenied、AnchorNotFound、MultipleAnchorsMatched、TextNotEncodable、BinaryFileSkipped。
10.2 删除类操作原则
- 默认拒绝明显危险的根路径、工作区根路径或过宽范围递归删除,除非显式传入强确认参数。
- 删除前返回命中数量与路径预览,支持
--dry-run。 - 对递归删除建议区分“空目录删除”和“强制删除子树”。
10.3 二进制文件处理
- 默认识别并标记二进制文件,不把二进制误当文本。
- 内容搜索默认跳过二进制,除非用户显式要求按字节搜索。
- 文本编辑命令若发现目标疑似二进制,应直接拒绝并提示原因。
10.4 一致性策略
输出一致性
无论是 list、search、read 还是 patch,尽量复用同类字段,如 path、relative_path、encoding、line_number。
副作用一致性
所有会改文件系统的命令统一支持 dry-run、结构化结果、失败码和变更摘要,避免每个命令风格不同。
11. 测试与验证设计
这个项目如果没有系统性的文件测试,很容易在“看起来能用”的阶段埋下大量跨平台与编码坑。测试应被当成主线,不是收尾动作。
11.1 测试分层
| 层级 | 重点 | 示例 |
|---|---|---|
| 单元测试 | 编码探测、行区间解析、Levenshtein 排序、锚点定位 | 同一路径名候选排序是否稳定 |
| 服务测试 | 遍历服务、文本服务、编辑服务 | GBK 文件读出后按原编码写回是否无损 |
| CLI 测试 | 参数、输出、错误码、命令树 | fileglide file lines --path demo.txt --start 3 --end 5 |
| 回归测试 | 复杂目录、混合编码、超大文件、模糊匹配排序 | 中文/日文/emoji/阿拉伯语样本 |
11.2 必测样本集
文本样本
中文、日文、韩文、俄文、阿拉伯文、emoji、混合标点、制表符、空文件、超长单行。
编码样本
UTF-8 无 BOM、UTF-8 BOM、GBK、GB18030、Shift-JIS、UTF-16 LE/BE、Latin-1。
路径样本
长路径、空格路径、中文路径、日文路径、大小写接近路径、深层子树。
11.3 验收标准建议
- 关键命令具备稳定 JSON 输出结构。
- 核心编码样本的读取和原样写回回归通过。
- Levenshtein 模糊检索排序对固定样本保持确定性。
- 精确编辑在至少三种编码与两种换行风格下通过。
12. 分阶段实施路线
阶段 A:最小闭环
- 搭建 CLI 骨架、命令树、标准输出结构。
- 实现文件/路径创建删除、基础 list、基础 read/write、UTF-8 优先编码处理。
- 完成最小 CLI 测试与编码样本测试。
阶段 B:搜索与尺寸能力
- 实现文件名/路径名搜索。
- 引入
vortezwohlLevenshtein 排序。 - 实现内容正则搜索、目录大小聚合。
阶段 C:精确编辑能力
- 实现按行读取、按行替换、区间读取、区间替换。
- 实现中部插入与锚点型编辑。
- 补齐预演与并发防误写保护。
阶段 D:Agent 强化层
- 批量计划执行、变更预览、结构化 diff 返回。
- 输出摘要与上下文裁剪策略。
- 更丰富的 inspect / diagnostics 命令。
13. 建议目录结构
fileglide/
|-- pyproject.toml
|-- README.md
|-- docs/
| `-- fileglide-architecture.html
|-- fileglide/
| |-- __init__.py
| |-- __main__.py
| |-- main.py
| |-- app.py
| |-- executor.py
| |-- facade.py
| |-- models.py
| |-- errors.py
| |-- rendering.py
| |-- commands/
| | |-- __init__.py
| | |-- root.py
| | |-- file_commands.py
| | |-- path_commands.py
| | |-- tree_commands.py
| | |-- text_commands.py
| | `-- inspect_commands.py
| |-- services/
| | |-- __init__.py
| | |-- traversal_service.py
| | |-- search_service.py
| | |-- stat_service.py
| | |-- text_read_service.py
| | |-- text_edit_service.py
| | `-- encoding_service.py
| |-- matchers/
| | |-- __init__.py
| | |-- name_matcher.py
| | `-- regex_matcher.py
| |-- filesystem/
| | |-- __init__.py
| | |-- gateway.py
| | `-- safety.py
| `-- util/
| |-- __init__.py
| |-- path_utils.py
| `-- text_utils.py
`-- tests/
|-- cli/
|-- services/
|-- fixtures/
| |-- encodings/
| `-- trees/
`-- regression/
14. 未决问题与后续决策点
14.1 CLI 框架
建议使用 click,因为 OpenTrade 已验证其多层命令树、参数帮助、测试友好性较好。若无强烈理由,不建议改用 Typer。
14.2 输出契约
是否默认输出 JSON 还是 table,需要根据“主要服务对象是 agent 还是人”最终裁定。当前建议读取类默认 text/table,agent 场景显式 --format json。
14.3 二进制边界
是否要支持二进制级别切片与写入,目前建议延后。否则会明显扩大问题域。
14.4 批量执行计划
若后续支持 batch run-plan,建议采用显式计划文件结构,而非让命令直接执行模糊自然语言指令。
建议的下一步实现切片
- 先搭 CLI 基础骨架与目录结构。
- 实现
file read、file write、path list、file search的最小闭环。 - 补充编码探测与保真写回测试。
- 再进入精确行编辑与模糊匹配排序。