前言¶
DeepSeek Harness(簡稱 DSH)是 DeepSeek 開源的智能體運行時,官方倉庫把核心理念寫成「Everything is a Plugin」(一切皆插件)。bash 工具是其中最常用的能力之一:模型下發一條命令,宿主把 stdout / stderr 收上來,再交給後續推理。
在 Linux 或 macOS 上,這條鏈路大多按 UTF-8 工作,問題不明顯。到了 Windows + WSL 組合裏,情況就不一樣了。DSH 跑在 Windows 側,bash 經 wsl.exe 執行;當 WSL 仍是 NAT 網絡、同時 HTTP_PROXY / HTTPS_PROXY 指向 localhost 時,啓動器會在 stderr 上打一條 UTF-16LE 編碼的代理警告。DSH 核心的 subprocess 層對所有輸出做 Buffer.toString('utf8'),原始字節在這一步丟掉,警告變成不可恢復的亂碼。更麻煩的是,這條警告經常和命令自己的 UTF-8 輸出擠在同一條管道里,按某一種編碼通解,會把另一段也解壞。
社區維護者 lhh010 做了 dsh-bash-encoding,專門替換 ctx.bash 執行器:自己 spawn、自己收集原始 Buffer、檢測後再解碼。它被收錄在社區插件目錄的「工具與能力」分類下。需要先說明:這個目錄站點(deepseek-harness-plugin.com)是獨立社區索引,和 DeepSeek / 幻方沒有官方從屬關係,安裝前仍要以倉庫源碼和許可證爲準。
這是什麼¶
dsh-bash-encoding 是一個宿主側 DSH 插件,npm 包名爲 @dsh-external/dsh-bash-encoding,當前版本 0.1.0,許可證 BSD-3-Clause,主要語言 TypeScript。GitHub 倉庫爲 lhh010/dsh-bash-encoding,截至 2026-08-18 星標 7。
它解決的問題很具體:自動識別 bash 輸出裏的 UTF-16LE / UTF-8 / GBK(以及 GB18030、UTF-16BE、帶 BOM 的變體),把 Web、TUI、hooks 橋和後臺任務裏看到的中文從亂碼還原成可讀文本。它不改 DSH 的 subprocess 核心服務,而是繞過那一層有損解碼——任何包在 ctx.subprocess 之上的包裝都修不了這個問題,因爲拿到的已經是亂碼文本。
倉庫 README 寫明兼容 DSH snapshot0808(snapshots/20260808T121140Z)、snapshot0809(snapshots/20260809T140917Z),以及 npm 發版 @deepseek-ai/dsh@0.0.1-rc.1。這些版本號以倉庫說明爲準;換 snapshot 前仍建議對照當前 DSH 的 bash 縫合線是否還叫 ctx.bash。官方文檔裏這條縫合線會拆到 dsh-bash-local、dsh-bash-sandbox 等包,本插件替換的是其中的 ctx.bash 實現。
編碼檢測怎麼做¶
插件把執行器換成 EncodingBashExecutor:子進程由插件自己 spawn,stdout / stderr 先按原始字節收集,再交給 src/decode-core.ts 裏的流式分段解碼。檢測順序在 README 裏寫得很清楚:
- 純 ASCII 快速路徑:沒有高字節就按 UTF-8 處理,避免把
STDERR、wsl:這類字母誤判成 UTF-16。 - BOM:UTF-8(
EF BB BF)、UTF-16LE(FF FE)、UTF-16BE(FE FF)。 - UTF-16 段檢測:按 chunk 分段。用 NUL 奇偶位錨定 ASCII 子段,用 CJK 高字節優勢錨定純中文段;連續 4 個可打印 ASCII code unit 會斷段(用來區分
STDERR和「個」「片」這類字),遇到 UTF-8 三字節簽名則硬斷。 - 嚴格 UTF-8(fatal decoder)通過,則定爲 UTF-8。
- 再試 GBK,然後 GB18030(對應 Windows 中文 OEM 代碼頁 936 / 54936)。
- 最後 Latin-1 兜底,保證解碼不會失敗。
同一條管道里混着 WSL 的 UTF-16LE 警告和命令自己的 UTF-8 輸出,是這個檢測鏈要處理的難點。倉庫給出的對比大致是這樣。
修復前(核心 exec 按 UTF-8 解 UTF-16LE):
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 代理。
GBK 工具的輸出、8KB 以上跨 chunk 的長 UTF-16 流,以及 STDERR: 這種 ASCII 前綴後跟中文的形態,README 裏都有對照示例。倉庫提供 26 個測試用例,覆蓋解碼內核和真實 spawn 的退出碼、stdin、超時、後臺任務、失敗路徑,用下面這條命令跑:
pnpm test
作者在 npm 發版基線上的實測記錄是 25/26 通過,唯一失敗被寫成「本機 WSL localhost 代理警告混入 stderr 的環境噪音」,解碼行爲本身仍被標記爲正確。
安裝與啓用¶
社區目錄頁給出的安裝命令是:
dsh plugin add github:lhh010/dsh-bash-encoding
目錄頁同時提示:如需可復現安裝,應固定 commit 哈希。當前 main 分支 HEAD 爲 30ecc056cbdade90292ff8ad72a2cd8324fe863f(提交於 2026-08-13),可以寫成:
dsh plugin add github:lhh010/dsh-bash-encoding#30ecc056cbdade90292ff8ad72a2cd8324fe863f
插件以當前 dsh 進程的權限運行,安裝時可能執行代碼。安裝前請檢查源代碼倉庫和許可證。
同一 context 裏只能有一個 ctx.bash 實現。接入後需要在 profile 的 cordis.yml(或 cordis.patch.yml)裏替換原來的 bash 條目,@deepseek-ai/dsh-bash-local 和 @deepseek-ai/dsh-bash-sandbox 二選一被本插件替代,不能並存。倉庫給出的配置如下:
- id: bash
name: '@dsh-external/dsh-bash-encoding'
config:
cwd: null # 默認工作目錄(默認 process.cwd())
timeoutMs: 120000 # 前臺命令默認超時
maxTimeoutMs: 600000 # 單次超時上限
maxOutputBytes: 65536 # 每流輸出上限(超限截斷並標記 lossy)
graceMs: 3000 # SIGTERM→SIGKILL 寬限期
各項含義按 README 原文:
cwd:默認工作目錄,缺省爲process.cwd()。timeoutMs:前臺命令默認超時。maxTimeoutMs:單次超時上限。maxOutputBytes:每條流的輸出上限,超限截斷並標記lossy。graceMs:先發 SIGTERM,再等這麼久才 SIGKILL。
如果走 cordis.patch.yml,README 特別指出:patch 的 name 字段只做校驗、不能替換插件。正確做法是先把原 bash 條目設爲 disabled: true,再 insert 本插件。改完後重啓 dsh web 生效。bash 工具、後臺任務、hooks 橋的輸出都會經過編碼檢測。
倉庫另外寫了一種本地 link 的接入方式(DSH 要求 Node ^22.19 || >=24):
cd /path/to/dsh-bash-encoding && pnpm install && pnpm build
cd "${DSH_HOME:-$HOME/.dsh}/profiles/web"
pnpm add -w link:/path/to/dsh-bash-encoding
純 npm install 時還有一個版本號坑:peerDependencies.cordis 聲明爲 ^4.0.0-rc.7,而 DSH npm 發版把內置 cordis 按 0.0.1-rc.? 統一預發佈號發出去,可能報 ERESOLVE。README 的處理是加 --legacy-peer-deps。經 dsh plugin 或 pnpm 安裝會自動處理,運行不受影響。
適用場景與注意事項¶
適合誰:在 Windows 上跑 DSH、bash 走 WSL,並且經常看到中文亂碼的人。典型觸發條件同時滿足下面三條:
- 操作系統是 Windows,DSH 在 Windows 側,bash 經 WSL 執行。
- WSL 網絡仍是 NAT(
%UserProfile%\.wslconfig未設置networkingMode=mirrored)。 - 環境變量
HTTP_PROXY/HTTPS_PROXY指向localhost。
附帶能修好的還有:GBK 中文工具、UTF-16 輸出,以及警告和命令輸出混在同一管道的情況。
不適合、或者明確做不到的,倉庫寫得很直接:
- Windows 原生(無 WSL)profile 默認停用。 平臺層已經插入
pwsh-sandbox(SandboxPwshExecutor),同樣會註冊ctx.bash;兩邊一起開會啓動失敗(service bash has been registered)。本插件用bash -cspawn,面向 POSIX bash 棧,本來也不適用 pwsh 棧。這是 profile 配置層的停用,不是代碼棄用。 - read 工具讀 GBK / UTF-16 文件 不在當前範圍,README 標成路線圖 v2。
- node-pty 交互終端(
tool-pty/dsh-web-terminal)修不了:node-pty 內部已經按 UTF-8 有損解碼,插件拿不到原始字節。 - 不改 subprocess 核心層,避免替換基礎服務。
- 超過
maxOutputBytes時保留頭部並標記lossy,不做 spill 文件。 - 繼承環境裏
DSH_*前綴、以及名稱含KEY/PASSWORD/SECRET/TOKEN的變量會被清掉,託管變量經dshEnv顯式傳入,這點和 DSH 官方 bash 縫合線的 hygiene 對齊。
如果只是想少看那條 WSL 代理警告,也可以從環境側處理:把 .wslconfig 的 networkingMode 改成 mirrored,或設置 WSL_UTF8=1。這是和插件互補的做法,不是替代關係。
沙箱方面,插件會在運行時探測 ctx.sandbox / ctx.sandboxPolicy,非 full-access 走 confine 路徑,sandboxMode 惰性讀取。它沒有客戶端 bundle,不受 snapshot0809 客戶端插件機制(dshClient 聲明 / ClientPackageCompositionError)影響。
小結¶
dsh-bash-encoding 做的事情很窄:把 bash 輸出的原始字節留下來,按 UTF-16LE / UTF-8 / GBK 等編碼解開,專門對付 Windows + WSL 下那類「每次命令都亂碼」的情況。它不是官方內置插件,星標也不高,但對卡在這條鏈路上的人,比在模型側猜測亂碼更直接。安裝前檢查源碼和 BSD-3-Clause 許可證,需要可復現環境時固定 commit。
目錄頁:https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-bash-encoding/
GitHub:https://github.com/lhh010/dsh-bash-encoding