dsh-fs-encoding
Encoding-governed read/write/edit/grep tools for DeepSeek Harness (dsh): UTF-8 BOM fidelity and byte-exact round-trips for GBK, Big5, Shift-JIS, EUC-KR, Windows-1251 and UTF-16 text files.
一句话定位
Encoding-governed read/write/edit/grep tools for DeepSeek Harness (dsh): UTF-8 BOM fidelity and byte-exact round-trips for GBK, Big5, Shift-JIS, EUC-KR, Windows-1251 and UTF-16 text files.
安装方式
在 DSH 的 web profile 中执行下面的命令;装完刷新页面即可。
$ dsh plugin --profile web add dsh-fs-encoding@1.5.3
兼容的 DSH 版本
>=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0 || >=0.1.7-alpha.1 <0.2.0 || >=0.2.0-alpha.1 <0.3.0 || >=0.2.1-alpha.1 <0.3.0 || >=0.2.2-alpha.1 <0.3.0
作者与热度
MrWeiCodes · ★ 19 · 更新于 2026-11-05
关于这个插件
dsh-fs-encoding — DSH 文件编码守护
> 为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)提供的文件编码治理插件:让 AI 读写文件时不再弄坏 BOM 与多字节编码
🌏 中文 | [English](README_EN.md)
dsh · dsh-plugin · plugin · encoding · BOM · GBK · Big5 · Shift-JIS · UTF-16 · AI agent · 编码 · 文件编码 · 乱码
简介
DSH 自带的 read / write / edit / grep 四个文件工具只认 UTF-8,遇到中文、日文、韩文项目里常见的编码就会出问题:
- GBK、Big5、Shift-JIS 等编码的文件根本读不了,直接报
invalid UTF-8 text,AI 只能干看着; - 带 BOM 的 UTF-8 文件能读,但 BOM 会被悄悄吃掉——AI 随手改一次,文件开头那三个字节就没了。对 PHP、旧版编译器、部分 Windows 软件来说,文件头少了 BOM 就可能解析出错或直接乱码;
grep搜非 UTF-8 文件时,命中的行显示成(line is not valid UTF-8);搜中文时更糟——返回 0 条且不报错,看起来像"文件里没有",实际是根本没搜;- 更麻烦的是没有任何警告:你只会在某天发现文件坏了,却不知道是哪次编辑弄坏的。
本插件接管这四个工具,在完整保留原有行为(沙箱围栏、读后写保护、版本校验、diff 展示)的前提下,让非 UTF-8 文件和 BOM 都能正确读写:文件原来是什么编码,改完还是什么编码。
功能特性
- 字节级保真:文件编码在首次读取时确定一次,之后每次保存都按原编码写回。改一个 GBK 文件,它仍然是一个 GBK 文件,不会被偷偷转成 UTF-8。
- BOM 保真:原本有 BOM 就精确还原,原本没有就绝不擅自添加——两个方向都不会出错。
- 换行符保真:CRLF / LF / CR 在读取时识别、保存时还原,Windows 项目不会被改成 LF。
- 绝不静默损坏:如果目标编码表示不了新内容(比如往 GBK 文件里写 emoji),插件会直接拒绝写入并说明原因,文件保持原样——而不是写进去一堆
?把文件毁掉。 - 读不了会告诉你怎么办:遇到非 UTF-8 文件时,插件会列出最可能的几种编码和各自的解码效果,AI(或你)选一个重新读即可,就像 VS Code 的「通过编码重新打开」。
grep也能搜非 UTF-8 文件:命中的行显示真实内容而不是占位符;搜中文、日文时不会静默漏报。判定不出来的文件会附上候选编码,read打开一次之后grep就跟着会用。- 十九种编码:UTF-8(含 BOM)、UTF-16、UTF-32,以及 GBK、Big5、Shift-JIS、EUC-KR 和 Windows-125x 全系(西欧、中欧、西里尔、希腊、土耳其、希伯来、阿拉伯、波罗的海)。
- 零学习成本:
read/write/edit/grep的参数、返回格式与原版完全一致,是直接替换,原有提示词和工作习惯都不用改;read和write各多了一个可选的encoding参数(write的只用于新建文件,见下)。 - 能建指定编码的新文件:
write加一个encoding就能直接生成 GBK、Shift-JIS 等编码的文件,不用先写 UTF-8 再转码。 - 多三个工具:
insert(按行号插入,原生没有这个能力)、undo_last_edit(撤销上一次编辑,内容与编码一并还原)和str_replace_editor(4 个子命令的兼容层,同样带编码治理)。见下方「另外三个工具」。 - 配置简单:一个 YAML 文件,几项开关,都能用环境变量覆盖。
使用
开箱即用
装好就能用,不需要任何配置。 插件没有必填项、没有初始化步骤,也不会改动你的项目——装上之后,AI 照常用 read / write / edit,编码的事插件自己处理:
- 读 UTF-8 文件(含带 BOM 的):和原版完全一样,BOM 不会再被吃掉。
- 读带 BOM 的 UTF-16 / UTF-32 文件:自动识别。
- 改 GBK、Shift-JIS 等老编码文件:按原编码写回,不会被悄悄转成 UTF-8。
- 写新文件:默认 UTF-8,需要别的编码时加一个参数即可。
这些都不需要你做任何事,也不需要 AI 改调用习惯。日常使用中,AI 的调用方式与原版完全一致。
AI 的调用区别
只有一种情况会不一样:无 BOM 的非 UTF-8 文件(典型是 GBK / Big5 / Shift-JIS 的老文件)。此时插件不会擅自猜,而是停下来让 AI 用显式编码重读一次:
[E_NOT_TEXT] legacy.txt is not valid UTF-8. Most likely gbk. Re-read with
read({ file_path: "legacy.txt", encoding: "gbk" }) to decode it, or set
autoGuessEncoding: true in the plugin config to decode automatically.
Candidates: gbk("你好,世界"), big5("斕疑"), shift_jis("ト羲")
AI 照着提示里的调用重读一次即可,它会自己完成——你不需要介入。重读之后编码就从「猜测」变成了「已知事实」,后续每次写入都按它进行。
read 和 write 因此各多了一个可选参数:
read({ file_path: "legacy.txt", encoding: "gbk" })
write({ file_path: "run.bat", content: "echo 中文\r\n", encoding: "gbk" })
> 无 BOM 的 UTF-16 / UTF-32 文件同理,用 read({ file_path: "<路径>", encoding: "utf16le" }) 显式指定即可正常读写(这类文件在 Windows 上较少见,且无 BOM 时无法可靠自动区分字节序,因此不做猜测)。
> 为什么默认要问一下? GBK、Big5、Shift-JIS 的字节范围在短文本上互相重叠,猜错在界面上是看不出来的——而且会按错误的编码写回,把文件彻底弄坏。所以插件默认选择「宁可失败,不可猜错」。如果你更希望它尽力解码,把 autoGuessEncoding 设为 true 即可。
>
> 即使开了 autoGuessEncoding,也有一种情况仍然会报错并列出候选:文件极短(几个字节),且两个独立的识别器给出了不同的答案。此时没有任何依据能判断谁对——实测这种情况下的首选有约 79% 是错的——插件宁可让你从候选里挑一个,也不替你赌一把。只要两者给出相同的答案,就会直接采用;文件稍长一些(几十字节以上)也基本不会再出现这种歧义。
>
> 另一种会报错的情况:识别器把文件判成了 ISO-8859-1 / Windows-1252 这类单字节编码,但按它解码出来的文本几乎全是非 ASCII 字符。真实的西文以字母和空格为主,不会长这样;而中文/日文/韩文/俄文的双字节被当成单字节读时,每个字符会变成两个拉丁字符,正好就是这个特征。这时插件不会采用这个判断,而是报错并列出候选——实测这一步能拦下 24 个本会被静默读错的文件,且不会误伤任何原本读对的文件。
新建指定编码的文件
默认新文件是 UTF-8(无 BOM)。要给旧系统生成一个 GBK 文件,加 encoding 即可:
write({ file_path: "run.bat", content: "echo 中文\r\n", encoding: "gbk" })
支持的编码名与 read 相同,别名和大小写都不敏感(cp936、Shift-JIS 都行)。名字里带 BOM 的(utf8bom、utf16le、utf16be、utf32le、utf32be)会写入对应的 BOM;其余都不写 BOM。编码表示不了的字符同样拒绝写入,不会写成 ?。
> encoding 只对新建文件有效。 文件已存在时传它会直接报错 E_ENCODING_NOT_APPLICABLE,不会转换——因为「保持文件原有编码」是本插件的核心承诺,而转换会重写整个文件,AI 从返回结果里看不出区别。不要为了转换而先删除文件:删除会绕过「先读后写」闸门,让未读过的内容在返回结果里以 before: null 静默消失;而如果本会话读过该文件,删除后的第一次写入会报 FS_STALE_VERSION,重试一次即可重建。本插件不提供编码转换;确实需要一份另一种编码的副本时,请写到新路径上。
另外三个工具
除上面三个之外,插件还注册三个工具,同样带编码治理(写入按文件原有编码落盘)。
insert —— 按行号插入,原生没有这个能力。字面替换只能插在能引用到上下文的地方,「在文件开头加一行」之类就得先读到那一行再原样复述,很不方便:
insert({ file_path: "config.ini", insert_line: 0, new_string: "[core]" })
insert_line 指插入到该行之后:0 插到最前,等于文件行数时追加到末尾。行号与 read 显示的完全一致。
undo_last_edit —— 撤销某个文件的上一次编辑,内容与编码一并还原:
undo_last_edit({ file_path: "config.ini" })
改错了、或者 AI 发现自己上一次改动不对时用它。几条要点:
- 只保留最近一次。同一个文件编辑两次,只有第二次能撤销;撤销一次后就没有了(不支持重做)。
- 编码一起还原。如果那次编辑把 GBK 文件转成了 UTF-8(见
normalizeToUtf8),撤销会把文件变回 GBK,而不只是内容回去。 - 文件被改过就拒绝。撤销前会核对文件是否仍等于那次编辑写入的内容;如果之后有人改过(你、其他工具、其他会话),撤销会拒绝并说明,绝不覆盖那些改动。
- 只存在内存里。不写磁盘、不污染仓库,所以 DSH 重启后无法撤销(会明确告诉你没有可撤销的历史,而不是假装成功)。
- 新建文件不产生撤销点:「撤销一次新建」等于删文件,破坏性太大,请直接删。
str_replace_editor —— 4 个子命令的兼容层,让按这套工具写的提示词与习惯直接可用:
| 命令 | 作用 |
|---|---|
| view | 显示文件(带行号,可用 view_range 限定范围);路径是目录时列出两层结构,跳过隐藏项、node_modules、__pycache__ |
| create | 新建文件,已存在则拒绝 |
同分类对比
同一分类下 Star 最高的 5 个,便于横向比较。
| 插件 | 作者 | Star | 版本 | 更新 |
|---|---|---|---|---|
| Mole | tw93 | 74.5K | 0.0.0 | 2026-11-10 |
| DeepSeek-Reasonix | esengine | 36.1K | 0.0.0 | 2026-11-10 |
| dsh-desktop | anywhere-labs | 35.6K | 0.4.1 | 2026-11-06 |
| awesome-dsh-plugin | awesome-dsh-plugin | 24.1K | 0.1.0 | 2026-11-10 |
| dsh-market | dsh-market | 11.8K | 1.73.17 | 2026-11-09 |