dshplugin.devDeepSeek Harness Plugins
DSH Bash Encoding plugin logo
DeepSeek Harness Plugin

DSH Bash Encoding

3
Published by lhh010

DSH bash 输出编码自动识别插件:替换 ctx.bash,自管 spawn 收集原始字节,自动检测 UTF-16LE/UTF-8/GBK 等编码并正确解码,修复 WSL/Windows 下 bash 工具的中文乱码。

Developer Toolsdshdsh-plugin

Get this plugin

Review the source, then continue to the publisher.

dsh plugin add @dsh-external/dsh-bash-encoding@latest
Get this plugin
Share on X ↗

About this plugin

Source snapshot 8/13/2026

dsh-bash-encoding

简体中文 | English

DSH bash 输出编码自动识别插件:替换 ctx.bash,自管 spawn 收集原始字节,自动检测 UTF-16LE / UTF-8 / GBK 等编码并正确解码,修复 Windows/WSL 下 bash 工具的中文乱码。

版本兼容 / Version compatibility

兼容 DSH snapshot0808(snapshots/20260808T121140Z)与 snapshot0809(snapshots/20260809T140917Z):宿主侧插件,替换 ctx.bash 执行器,只依赖 bash 缝合线与 ctx.sandbox/ctx.sandboxPolicy 探测面——这些在 0808/0809 上均未变化,typecheck 与实机加载已验证。

npm 发版兼容:兼容 DSH npm 发版 @deepseek-ai/dsh@0.0.1-rc.1(即 snapshot0810 的 npm 发版;npx -p @deepseek-ai/dsh@0.0.1-rc.1 dsh web 可访问指定版本并启动,lib 生产模式)。实测(同源本地基线):npm 基线安装后运行时加载通过,单元测试 26 例中 25 通过(唯一失败为本机 WSL localhost 代理警告混入 stderr 的环境噪音,解码行为本身正确)。注意:peerDependencies.cordis 声明为 ^4.0.0-rc.7,而 npm 发版将 vendored cordis 一并按 0.0.1-rc.? 统一预发布版本号发布——纯 npm install 报 peer 冲突(ERESOLVE)时加 --legacy-peer-deps 即可;经 dsh plugin/pnpm 安装自动处理,运行不受影响。

0809 兼容要点(实机验证)

  • 0809 运行中的 dsh web 下,本插件正常替换 ctx.bash(patch 停用 bash-sandbox + 插入本插件的接入方式不变):每次 bash 调用 stderr 里的 WSL UTF-16LE 代理警告均被正确解码为中文,无乱码——核心修复路径实测有效。
  • 0809 保留 bash 缝合线(服务名 ctx.bashBashExecutor 继承面)与 ctx.sandbox/ctx.sandboxPolicy 探测面,插件无需改动、沿用既有 lib/ 构建即可。
  • 本插件无客户端 bundle,不受 0809 客户端插件机制(dshClient 声明/ClientPackageCompositionError 启动校验)影响。

Windows 原生 profile 停用说明

Windows 原生(无 WSL)profile 下,本插件默认停用cordis.patch.yml 注释段),原因:

  • 平台层 windows.cordis.patch.yml 已插入 pwsh-sandboxSandboxPwshExecutor),与本插件一样会注册 ctx.bash;同一 context 只允许一个 ctx.bash 实现,同时启用会启动失败(service bash has been registered at <EncodingBashExecutorPlugin>)。
  • 本插件以 bash -c 方式 spawn,面向 POSIX bash 组合(替换 dsh-bash-local);Windows 原生 profile 走 pwsh 栈、无 bash runner,本就不适用。

需要时(POSIX/WSL profile,或显式替换 dsh-bash-local)按下方「安装」节接入即可——这是 profile 配置层的停用决定,不是代码弃用。

使用环境(重点)

本插件解决的是 Windows + WSL 组合下的中文乱码,典型触发条件:

条件说明
操作系统Windows(DSH 运行在 Windows 侧,bash 经 WSL 执行)
WSL 网络模式NAT 模式%UserProfile%\.wslconfig 未设置 networkingMode=mirrored
代理配置环境变量 HTTP_PROXY / HTTPS_PROXY 指向 localhost

当以上条件同时满足时,每次执行 bash 命令wsl.exe 启动器都会向 stderr 输出一条 UTF-16LE 编码的代理警告,而 DSH 核心以 UTF-8 有损解码 → 必现乱码(见下方对比 1)。

附带修复的场景:任何输出非 UTF-8 字节的程序(GBK 中文工具、UTF-16 输出等), 以及 UTF-16LE 警告与命令自身 UTF-8 输出混合在同一管道的情况(最棘手,见对比 2/3)。

问题根因

DSH 核心的 subprocess 层对所有输出执行 Buffer.toString('utf8') 有损解码readFrom() 只暴露解码后的文本,原始字节在转换中丢失),于是 UTF-16LE 字节变成 不可恢复的乱码。任何包在 ctx.subprocess 之上的包装都无法修复——因为看到的已经是 乱码文本。本插件绕过该层:自己 spawn 子进程、自己收集原始 Buffer、检测后解码

效果对比(前后)

对比 1:WSL 代理警告(最典型,每次命令必现)

❌ 修复前(DSH 核心 exec):
w s l: �hKm0R localhost �NtM�nFO*g\��P0R WSL0NAT !j_N�v WSL \rN/e c localhost �Nt

✅ 修复后(本插件):
wsl: 检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。

对比 2:UTF-16LE 警告 + 命令自身 UTF-8 输出(同一 stderr 管道)

❌ 修复前:
wsl: 检测到 localhost 代理配置
釥戒护鑷: 涓枃鏄剧ず姝e父 hello        ← 命令输出被当作 UTF-16 解

✅ 修复后:
wsl: 检测到 localhost 代理配置
命令自身输出: 中文显示正常 hello

对比 3:ASCII 前缀 + 中文(STDERR: ... 形态)

❌ 修复前:
STDERR: 呓䕄剒›命令自己的错误信息       ← ASCII 前缀被 UTF-16 吞并

✅ 修复后:
STDERR: 命令自己的错误信息

对比 4:GBK 输出(Windows 中文代码页工具)

❌ 修复前(核心 exec 按 UTF-8 解 GBK 字节):  乱码
✅ 修复后:  GBK编码测试输出

对比 5:长 UTF-16 流跨管道 chunk(8KB 以上必现)

❌ 修复前:  这是一段非常长的UTF-16中文输úQ(uNKm...   ← 管道 chunk 边界处错位
✅ 修复后:  这是一段非常长的UTF-16中文输出用于测试跨chunk解码(完整)

测试场景表(全部通过,26/26)

#场景说明结果
1WSL 代理警告(stderr,UTF-16LE)每次命令必现,最典型场景
2警告 + UTF-8 输出混合流(同管道)wsl.exe 警告与命令输出合并进同一 buffer
3ASCII 前缀 + 中文(STDERR: ...大写字母前缀不再被 UTF-16 吞并
4GBK 输出Windows 中文代码页工具
5长 UTF-16 流跨管道 chunk8KB+ 含 ASCII 子串(UTF-16),1024B chunk 切割
611 字节小 chunk 分片纯中文 UTF-16 流被切成奇数长度小块
7后台任务混合编码run_in_background + UTF-16LE/UTF-8 混合
8多段写入混合流警告 + 多次 UTF-8 写入 + 跨 chunk 中文
9纯 ASCII 输出hello world 不被误判 UTF-16
10纯 UTF-8 中文长输出50 行中文无回归
11中英混排输出hello world 你好世界
12UTF-16 尾字节跨 chunk半个 code unit 正确配对
13单元测试解码内核:BOM/NUL 启发式/严格 UTF-8/GBK/GB18030
14执行器端到端真实 spawn:exit code/stdin/超时/后台/spawn 失败

安装

# 在插件目录安装依赖(DSH 需要 Node ^22.19 || >=24)
cd /path/to/dsh-bash-encoding && pnpm install && pnpm build

将插件接入 DSH web profile(与 dsh-shell-windows 等外部插件同样的方式):

cd "${DSH_HOME:-$HOME/.dsh}/profiles/web"
pnpm add -w link:/path/to/dsh-bash-encoding

配置

在 profile 的 cordis.yml(或 cordis.patch.yml)中替换 bash 条目 (@deepseek-ai/dsh-bash-local@deepseek-ai/dsh-bash-sandbox 二选一被本插件替代; 同一 context 只能有一个 ctx.bash):

# ... 原有其他条目不变 ...
- id: bash
  name: '@dsh-external/dsh-bash-encoding'
  config:
    cwd: null            # 默认工作目录(默认 process.cwd())
    timeoutMs: 120000    # 前台命令默认超时
    maxTimeoutMs: 600000 # 单次超时上限
    maxOutputBytes: 65536  # 每流输出上限(超限截断并标记 lossy)
    graceMs: 3000        # SIGTERM→SIGKILL 宽限期

注意(patch 文件):patch 的 name 字段只做校验、不能替换插件。若通过 cordis.patch.yml 接入,需先 disabled: true 停用原 bash 条目,再 insert 本插件。

重启 dsh web 后生效。bash 工具、后台任务、hooks 桥的所有输出都自动经过编码检测。

编码检测顺序

  1. 纯 ASCII 快速路径(无高字节 → UTF-8,避免 ASCII 字母误判 UTF-16)
  2. BOM:UTF-8 (EF BB BF) / UTF-16LE (FF FE) / UTF-16BE (FE FF)
  3. UTF-16 段检测(流式、chunk 内分段):
    • NUL 奇偶位锚定(ASCII 子段,如 wsl:
    • CJK 高字节优势锚定(纯中文段)
    • 段内信任延伸 + 连续 4 个可打印 ASCII code unit 回退断段(区分 STDERR/
    • UTF-8 三字节签名硬断(lead + 双续字节)
  4. 严格 UTF-8 校验(fatal decoder)通过 → UTF-8
  5. GBK,再 GB18030(Windows 中文 OEM 代码页 936/54936 的兜底)
  6. Latin-1 最后兜底(永不失败)

验证

pnpm test   # 26 个用例:解码内核 + 真实 spawn 端到端(UTF-16LE/GBK/混合流/超时/后台/失败路径)

范围与限制

状态说明
bash 工具输出(Web/TUI/hooks/后台)✅ 修复替换 ctx.bash 后所有下游自动受益
沙箱兼容✅ 支持运行时探测 ctx.sandbox/ctx.sandboxPolicy,非 full-access 走 confine 路径,sandboxMode 惰性读取
read 工具读 GBK/UTF-16 文件⏳ 路线图 v2FileSystem 是抽象 seam;需包装 readText 且保留沙箱链
node-pty 交互终端(tool-pty / dsh-web-terminal)❌ 不可修复node-pty 内部已按 UTF-8 有损解码,插件层拿不到原始字节
subprocess 核心层❌ 不改动基础服务替换风险大,不做

其他说明:

  • 环境净化:继承环境中 DSH_* 前缀与名称含 KEY/PASSWORD/SECRET/TOKEN 的变量会被 清除(对齐 subprocess seam 的 hygiene),托管变量经 dshEnv 显式传入。
  • 大输出:超过 maxOutputBytes 保留头部并标记 lossy(不做 spill 文件)。
  • 治本建议(可选,与插件互补):将 .wslconfignetworkingMode 改为 mirrored, 或设置 WSL_UTF8=1,可从源头消除 WSL 警告本身的输出。

结构

src/decode-core.ts   # 编码检测内核(ChunkDecoder 流式分段解码):纯函数、零依赖、可独立测试
src/executor.ts      # EncodingBashExecutor:自管 spawn + 原始字节 + 检测解码 + 沙箱
src/index.ts         # 插件入口(schemastery Config)
tests/               # node:test 单元 + 端到端

许可

BSD-3-Clause