dsh-utf8-output:修复 Windows 下 DSH 子进程中文乱码

前言

在 Windows 上用 DeepSeek Harness(DSH)跑 cmd.exe、powershell.exe 或常见本地命令时,agent 看到的 stdout/stderr 里中文经常变成一串 � 或乱字符。错误信息、路径、日志都不可读,排查会偏离真实输出。问题来自子进程按系统 OEM 代码页(简体中文多为 GBK/CP936)写字节,而 DSH 子进程服务却一律用 UTF-8 解码。本文介绍社区插件 dsh-utf8-output(维护者 TLEWA,分类:客户端):在不改内核的前提下,从保留的原始字节重新解码后再交给上层。

这是什么

dsh-utf8-output 是 DSH 的 cordis 插件,挂到 subprocess 服务上,包装 spawn(),对 OutputCollector 的 readFrom() / finalize() 做重解码。目标用户是 Windows 上使用 DSH 桌面版(profile desktop)、需要正确阅读子进程中文输出的开发者。许可证为 MIT;npm 当前版本为 0.1.1(见 package.json)。

乱码从哪来

@deepseek-ai/dsh-subprocess-local 对 stdout/stderr 原始字节使用 Buffer#toString("utf8")。Windows 上子进程普遍按 OEM 代码页输出,例如简体中文 936 / GBK,繁体 950 / Big5,日文 932 / CP932。非法 UTF-8 会被替换成 U+FFFD(�),信息不可逆丢失,agent 只能看到乱码;这与 bash 工具或命令写法无关。

README 中的对比例子:乱码时类似 ����λ�� ��:1 �ַ�: 134;安装插件后同一输出为 所在位置 行:1 字符: 134。

本插件只实现简体中文相关代码页:936 / GBK / GB18030 / CP936。950、932、949 没有对应解码器,这些语言输出仍保持内核原样(可能仍是乱码),不会用 GB18030 去猜解以免错字。

核心功能

接入方式

  1. apply(ctx) 取得 subprocess 服务并包装 spawn()。
  2. 每个 handle 的 handle.collected.stdout / .stderr 保留原始字节的 OutputCollector。
  3. 替换上述 collector 的 readFrom() 与 finalize(),从原始字节重新解码后交给上层。

不改命令、参数、退出码、超时和 spillPath;纯 UTF-8 / ASCII 在第 1 步判据下原样返回。覆盖所有走 subprocess 的调用(如 ops_bash、bash、pwsh 等)。重复加载、apply() 幂等;dispose 会还原 spawn。非 Windows 平台 apply() 直接返回,不安装补丁。

解码顺序

步骤 判据 结果
1 严格 UTF-8(fatal: true)能解 原样返回
2 仅窗口首/尾截断(≤3 字节残片),其余为干净 UTF-8 宽容 UTF-8(边缘可保留一个 U+FFFD)
3 按 GB18030 严格可解(必要时跳过 1–3 字节重新对齐) 按 GBK 解码
4 都不成立 原样返回,不比内核更差

第 2 步针对 collector 内存尾部窗口边界截断字符的场景,避免把大段正常中文误判为非 UTF-8。

安装与启用

要求:

  • DSH 0.2.0 或更新;
  • 内核 OutputCollector 暴露 snapshot()(0.2.x 桌面版),或早期构建的 chunks / total 字段。

插件以当前 DSH 进程权限运行;安装前请自行查看 GitHub 仓库 源码与 MIT 许可证。

从 npm 安装(推荐)

  1. 侧边栏 插件 → 安装插件,输入:
   dsh-utf8-output
  1. 重启 DSH(host 插件在 profile 启动时加载)。

命令行等价写法:

dsh plugin --profile desktop add dsh-utf8-output

从 GitHub 安装

https://github.com/TLEWA/dsh-utf8-output

固定到标签:

dsh plugin --profile desktop add github:TLEWA/dsh-utf8-output#v0.1.0

从源码安装

git clone https://github.com/TLEWA/dsh-utf8-output.git
cd dsh-utf8-output
npm test
dsh plugin --profile desktop add .

经过上面的步骤并重启后,无需额外配置项;子进程输出解码即由插件接管。

典型用法

没有单独的配置文件或开关。安装并重启后,在 Windows 上通过 DSH 执行会走 subprocess 的命令即可验证:例如 PowerShell 报错信息、含中文路径的 dir 输出,应与系统控制台语义一致,而不再是满屏 �。

开发与自测可在克隆仓库后执行:

npm test    # node test/run.mjs
npm run check

测试覆盖解码判定(UTF-8 截断、GBK 错位等)以及 spawn 包装、幂等性与旧内核回退逻辑(见 README「开发与测试」)。

适用场景与注意

适合: Windows + 简体中文 OEM 代码页(GBK/CP936)环境下的 DSH 用户;依赖 agent 阅读本地命令 stderr/stdout 的场景。

已知限制(摘自 README):

  • GBK 字节序列若恰好是合法 UTF-8,会按 UTF-8 解(概率极低)。
  • 窗口首字节截断且残片自成合法字符时,可能出现头部错字;插件不用启发式猜解。
  • 混合 UTF-8 与 GBK 按整体判断,不分段嗅探;UTF-16/UTF-32 不处理。
  • Big5、CP932、CP949 无解码器。
  • 超大输出高频轮询时,读取成本仍可能偏高(窗口约 2.8KB,单次约 10µs 量级,但复杂场景仍为 O(n²) 量级行为)。

DSH 生态主张「一切皆插件」;SkillHub 目录页 为社区收录,与 DeepSeek / 幻方无官方从属关系。

结尾

dsh-utf8-output 在字节进入 agent 之前,用 GB18030/GBK 路径重解 Windows OEM 中文输出,并尽量保持 UTF-8 输出不变。若你在 Windows 上被 DSH 子进程乱码拖慢排障,可按上文 npm 或 GitHub 方式安装后重启验证。

  • 目录页:https://www.skillhub.cn/plugins/TLEWA/dsh-utf8-output
  • 源码与文档:https://github.com/TLEWA/dsh-utf8-output
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜