dsh-composer-color-fix
September 3, 2026 · View on GitHub
English TL;DR — DeepSeek Harness (DSH)
0.1.1-rc.xstyles its composer<textarea>ascolor: transparent; -webkit-text-fill-color: transparentand paints the text you actually read in a sibling.backdropoverlay. When that overlay falls out of sync with the textarea value (reliably reproducible after refreshing a long-lived session), you keep typing but see nothing. This is a client-only DSH profile bundle that detects the transparent-painted surface at runtime and forces the theme foreground colour back on. It is deliberately self-disabling: once upstream ships a composer with an opaquecolor, the shim does nothing at all, so you can leave it installed across upgrades.
修复 DSH(DeepSeek Harness)输入框「能打字但看不见字」的问题。
工作原理 / How it works
主要处理路径、异常分支和人工检查点。 / The main processing path, exception branches, and human review points.
症状
在一个聊了较久的会话里:
- 输入框突然完全无法输入;
Cmd+R刷新后能输入了,但键入的字符不显示—— 光标在动、发送按钮会亮、底部状态栏字数在涨、@ 补全下拉也能弹出, 就是看不见字。
新建一个会话却一切正常。所以它是会话状态相关的 bug,不是 DSH 整体坏了。
根因
在 @deepseek-ai/dsh 0.1.1-rc.2 里,composer(InputBar)是一个双层结构:
/* packages/client/ui-conversation/src/client/skeleton/InputBar.module.css */
.input {
position: absolute;
color: transparent; /* ← 故意透明 */
-webkit-text-fill-color: transparent; /* ← 双保险,也透明 */
caret-color: var(--dsw-alias-state-business-primary);
background: 0 0; border: none; outline: none;
overflow: hidden;
}
.backdrop {
position: absolute;
color: var(--dsw-alias-label-primary); /* ← 你看到的字是这层画的 */
pointer-events: none;
overflow: hidden;
}
- 真正持有
value的是<textarea>,但故意不可见; - 你看到的字(含语法高亮、文件 chip、@ 引用)来自同位置的
.backdrop叠加层; - 一旦 React 没把某次草稿更新同步进 backdrop,value 进去了、视觉上空了。
这不是任何第三方插件造成的——@deepseek-ai/dsh-client-ui-conversation 的原生设计。
一个佐证:.input 的注释里写着「caret is the textarea's and every visible glyph is the
backdrop's」,作者知道这个耦合,但没给失同步时兜底。
影响范围
| 版本 | 状态 |
|---|---|
0.1.1-rc.2(npm latest,2026-08-21) | ❌ 有 bug —— 本仓库的目标版本 |
0.1.2-alpha.3(npm alpha,2026-08-31) | ✅ 已修:composer 重写为 Lexical contenteditable,color: var(--dsw-alias-label-primary),透明层与 backdrop 全部移除 |
| 更新版本(推测) | ✅ 沿用重写后的实现 |
注意:官方仓库 deepseek-ai/deepseek-harness 的 issue tracker 是关闭的
(has_issues: false),所以这个问题全网没有现成的公开方案,也没有地方提交。
修复思路
本 shim 不猜类名、不改选择器,只做一件事:问浏览器「这块可编辑区域现在是不是被画成全透明了」,是就把主题前景色强行贴回去。
三个设计原则,都是为了让它在 DSH 升级后自动退役而不是崩掉:
-
运行时探测,不猜类名
textarea[class*="_input"]这类写法依赖 CSS-module 哈希(uV2eYG_),换个构建就废。 这里只调getComputedStyle()看color/-webkit-text-fill-color的 alpha 是否为 0。 -
内联
!important终结特异性军备竞赛 按 CSS Cascade Level 4,作者样式的优先级是:普通声明 < 内联样式 < !important 声明 < 内联 !important。 直接把属性写到元素的style上,无论未来 DSH 用什么选择器都盖不住它。 -
自废
if (!isTransparent(fill) && !isTransparent(color)) return false;上游修好之后(alpha 提到 0.1.2+ 即生效),探针返回 false,shim 一行代码都不执行。 可以放心留着跨版本升级,不用惦记卸载。
覆盖范围:textarea / input / [contenteditable] 全扫,MutationObserver 盯整棵子树
(composer 挂载晚、切会话会重挂),外加 focusin + 三次延迟补偿。
安装
一键脚本(推荐)
git clone https://github.com/BaymaxStudio/dsh-composer-color-fix.git
cd dsh-composer-color-fix
chmod +x install.sh
./install.sh web # 参数是 profile 名,默认 web
脚本会:拷贝源码到 ~/.dsh/profiles/<profile>/_shims/ → 软链到 node_modules/
→ 写入 dependencies 和 dsh.profile.bundles → 用 dsh --dump-config 自检(失败自动回滚)。
装完必须重启 DSH web 服务——客户端 bundle 清单一只在服务启动时构建一次:
pkill -f "dsh web"
cd "<你的工作区目录>" && dsh web --no-open
然后在浏览器里 Cmd+Shift+R 硬刷新。
手动安装
SHIM=~/.dsh/profiles/web/_shims/dsh-composer-color-fix
mkdir -p "$SHIM/lib"
cp package.json cordis.patch.yml "$SHIM/"
cp lib/*.js "$SHIM/lib/"
ln -sfn "$SHIM" ~/.dsh/profiles/web/node_modules/dsh-composer-color-fix
再编辑 ~/.dsh/profiles/web/package.json,加两处:
{
"dependencies": {
"dsh-composer-color-fix": "file:/Users/<你>/.dsh/profiles/web/_shims/dsh-composer-color-fix"
},
"dsh": {
"profile": {
"bundles": [ "...", "dsh-composer-color-fix" ] // 追加到末尾
}
}
}
三个必须知道的坑
dsh.profile.bundles≠dependencies。ClientModuleRegistry.flush()只扫bundles。写进dependencies的包不会被装进__DSH_BOOT__清单(DSH 没有 client 插件自动发现机制)。- profile bundle 必须声明
dsh.bundle.patch,指向一个cordis.patch.yml, 否则loadProfile直接抛错。 - HTML 里的
__DSH_BOOT__是服务启动时一次性构建的,注册新 bundle 后不重启不会生效。
验证
# 1) profile 配置能加载
dsh --profile web --dump-config
# 2) shim 出现在启动清单里
curl -s http://127.0.0.1:3080/ | grep -c "dsh-composer-color-fix" # 期望 >= 1
# 3) bundle 能被服务
curl -s -o /dev/null -w "%{http_code}\n" \
http://127.0.0.1:3080/plugins/dsh-composer-color-fix/client.js # 期望 200
浏览器里 DevTools Console 跑一行看补丁有没有打上:
document.querySelector('textarea').dataset.dshTextFix // 期望 "1"
打上之后 getComputedStyle(textarea).color 应该是实际颜色(如 rgb(15, 17, 21)),
而不是 rgba(0, 0, 0, 0)。
卸载
./install.sh --uninstall web
或手动三步:删软链 → 从 package.json 的 dependencies 和 dsh.profile.bundles 里去掉条目
→ rm -rf ~/.dsh/profiles/web/_shims/dsh-composer-color-fix,然后重启 DSH。
已知副作用
启用后,textarea 本身的文字会显示出来,而 backdrop 仍在原位置画它的富文本层。 因此在粘贴图片、@ 引用文件产生 chip 的位置,两层会有轻微叠影。 不影响输入与发送——这是「看不见字」和「chip 偶尔叠一下」之间的取舍。
给上游的话
根因不在插件层,而在 InputBar 的双层耦合本身:把「持有 value」和「负责显示」拆到两个元素上,
就必然要承担它们失同步的风险,且失同步时没有降级路径(用户拿到的是一个静默不可用的输入框)。
0.1.2-alpha.3 改成 Lexical contenteditable + 正常 color 是对的方向。
在此之前,更稳妥的兜底是:backdrop 未跟上时,让 textarea 自己显示文字。
详细的 bug report 模板见 docs/UPSTREAM-REPORT.md。
环境
在以下环境实测通过:
- macOS (darwin),Chrome
@deepseek-ai/dsh0.1.1-rc.2,profileweb- 同时加载 8 个 profile bundle(含
@linxin666/dsh-web-ui-all、@nanmicoder/dsh-agent-teams、@omdsh-dev/dsh-genui、@anionex/dsh-vision-toolkit)
License
MIT