dsh-composer-live
Verifieddsh-composer-live · v0.2.13 · MIT · Web UI
DSH Web 0.1.5+ 输入框增强(Lexical contenteditable 架构版):markdown 实时渲染 + 代码块语法高亮/段落级等宽 + 格式工具栏(常驻顶条 + 选区浮动条)+ 70vh 展开 + 大段粘贴包代码块 + Esc 分发。纯浏览器端插件,零依赖,不改官方源码。仿 Open WebUI 输入体验。
Install
dsh plugin add dsh-composer-live Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-composer-live
为 DeepSeek Harness(DSH)Web 输入框带来 Markdown 实时渲染与输入体验增强。
dsh-composer-live 把 DSH Web 的输入框变成 Open WebUI 风格的实时编辑器:你打 Markdown,它边打边渲染——加粗、斜体、带语法高亮的代码块、列表、引用、表格——而草稿本身始终是纯 Markdown 源文本,发送出去的就是你输入的原文。
它是一个纯浏览器端插件:零运行时依赖、不注入任何官方服务、不改官方源码。它在官方 0.1.5 Lexical 输入框之上叠加增强,不重复 DSH 已原生提供的功能。
找 DSH 0.1.x(textarea 架构输入框)的版本?那是
dsh-composer-md——本插件的前身,已停止维护。
截图
Markdown 实时渲染

代码块

选区浮动格式条

功能
Markdown 实时渲染
- 行内样式边打边生效:
**加粗**、*斜体*、`行内代码`(品牌蓝胶囊)、~~删除线~~、[链接](url)(白名单协议)、胶囊。 - 光标字符级精确对齐。标记字符(
**、`、~~、[]())淡化显示但保留精确宽度,粗体/标题用 paint-only 伪粗——渲染行与编辑器透明文字逐字符完全对齐,光标落在行内任何位置(包括格式区间内部)都精确贴齐,打字零漂移。 - 任务列表项:
- [ ]/- [x]渲染成勾选胶囊;已完成项内容划线。 - 草稿始终是纯 Markdown 源文本。渲染纯视觉——发送的消息就是你输入的源文本。
代码块
- 输入 ``` 时按普通文本显示,直到围栏闭合——不会出现打一半就被渲染的残块。
- 未闭合围栏行上按 Shift+Enter 自动补全封闭块(块内空行 + 闭合围栏 + 块后空行),光标落回块内,直接开写。
- 已闭合块最后一个内容行按 ↓ 直接跳出,落到块后的普通行。
- 零依赖正则语法高亮:js/ts/py/sh/json/yml/css/html,未标语言按内容自动推断——中文长文不会误判成代码。
- 围栏行右上角语言标签;GitHub-dark / GitHub-light 两套块主题;围栏字符淡化。
- 等宽:草稿含已闭合代码块期间,整个输入框(编辑器 + 渲染层)同步切换等宽字体栈(与官方代码字体同源)。中文字符刻意保持界面字体,两侧换行点永不发散。
列表、引用、表格
- 列表行尾按 Enter 自动续项:无序列表保持符号(
-*+)、有序列表递增编号(1.→2.、3)→4))、缩进保留。空列表项上按 Enter 退出列表——两次 Shift+Enter 结束一个列表。 >引用行同样续项(>text无空格也算);空引用项上按 Enter 退出。- Tab / Shift+Tab 缩进 / 反缩进两空格——单行或整块选区。光标在列表标记或行首空白处按 Tab 即嵌套子列表。Tab 全境拦截:焦点永远不会被切出输入框。
- 表格首行(
|列A|列B|,至少 2 列)行尾按 Enter 自动补|---|---|分隔行加一个空行,光标落空行。
工具栏与快捷键
- 常驻顶部工具栏:加粗 / 斜体 / 行内代码 / 链接 / 列表 / 代码块 / 展开。选中文字时包裹、未选中插入空标记;光标落在
**…**内时加粗键自动点亮。工具栏钉在滚动区顶部,永不与正文或图片附件重叠。 - 选区浮动格式条(Open WebUI 形态):选中一段文字,加粗/斜体/代码/链接四键浮现在选区上方。
- Ctrl+B / Ctrl+I / Ctrl+E 快捷加粗 / 斜体 / 行内代码——同时拦掉浏览器对 contenteditable 的原生加粗(那会悄悄往草稿里插入真正的
<b>标签)。
粘贴处理
- 大段粘贴(超过 8 行或 4KB)且内容像代码/日志时,自动用代码围栏包起来——单一撤销单元,配 toast 轻提示。中文长文不误判;光标已在代码块内或内容本身含围栏时不包。
Esc 分发、主题、兼容
- Esc 按语境做对的事:官方候选菜单开着 → 归官方处理;展开态 → 收起;AI 生成中 → 停止生成。
- 一键展开 70vh 长文写作模式。
- 明暗主题自适应;输入法安全(拼音组字不闪烁);渲染按 rAF 合帧、增量进行。
- @ 引用胶囊保持官方原样、可编辑。含胶囊的段落优雅降级为官方显示(胶囊宽度无法复刻,零错位优先)。热词文本装饰不受影响。
- 顺带修复官方在图片附件在场时的两个定位问题:候选菜单悬空浮出输入框、工具栏盖住缩略图。
不与 DSH 0.1.5 重复
官方输入框已原生提供、本插件刻意不重做的:/ 命令菜单、@ 文件引用、粘贴图片/文件转附件、Enter 发送 / Shift+Enter 换行、输入法保护、草稿持久化。
速查表
| 按键 | 语境 | 行为 |
|---|---|---|
| Enter | 普通行 | 发送(官方) |
| Shift+Enter | 普通行 | 换行(官方) |
| Enter / Shift+Enter | 列表 / 引用行尾 | 续标记(有序递增编号) |
| Enter / Shift+Enter | 空列表 / 空引用项 | 删标记,退出列表 / 引用 |
| Enter / Shift+Enter | 未闭合围栏行 | 封闭代码块;光标落块内 |
| Enter / Shift+Enter | 表格首行(≥ 2 列) | 补分隔行 + 空行 |
| Tab | 代码块内 | 光标处插 2 空格 |
| Tab | 列表/引用标记头或行首空白 | 行首缩进(嵌套列表) |
| Tab | 其他位置 | 光标处插 2 空格 |
| Tab / Shift+Tab | 多行选区 | 整块缩进 / 反缩进 |
| Shift+Tab | 任意行 | 行首反缩进最多 2 空格(无缩进时只吞按键) |
| Ctrl+B / Ctrl+I / Ctrl+E | 任意 | 包裹选中加粗 / 斜体 / 代码,或插入空标记 |
| ↓ | 已闭合块最后一个内容行 | 跳到块后 |
| Esc | 菜单开着→官方 · 展开态→收起 · 生成中→停止 | 按语境分发 |
环境要求
- DSH ≥ 0.1.5-rc.2,
webprofile——本插件面向 0.1.5 的 Lexical contenteditable 输入框。 - Chromium 系浏览器(Chrome、Edge 等):透明化技术依赖
-webkit-text-fill-color。 - 与操作系统无关——纯 DOM/CSS,无原生依赖。
安装
# 从 npm 安装(推荐)
dsh plugin --profile web add dsh-composer-live
# 或从本地目录安装(file: 安装为物理拷贝)
dsh plugin --profile web add "file:/path/to/dsh-composer-live"
装完必须重启 web 实例。 插件按启动时快照加载,光刷新页面会新旧 bundle 并存。
跑的是隔离实例?用 DSH_HOME 指向它,插件就装进那个实例(否则装进默认的 ~/.dsh):
DSH_HOME=/path/to/your/.dsh dsh plugin --profile web add dsh-composer-live
使用
装上即全量生效——安装、重启、直接在输入框里打 Markdown。
典型工作流:
- 代码块:输入
```js,按 Shift+Enter——封闭块出现、光标在块内。写代码实时高亮;Tab 缩进两空格;最后一个内容行按 ↓ 跳出块后。 - 列表:输入
- 项目,Shift+Enter 逐项续写;空项上再按一次 Shift+Enter 结束列表。Tab 嵌套,Shift+Tab 升回。 - 长文写作:点展开键——输入框拉到 70vh;Esc 收起。
- 贴日志:一大段代码或日志自动变成代码块;不想要就 Ctrl+Z。
工作原理
官方输入框是一个 Lexical contenteditable 编辑器。本插件用 -webkit-text-fill-color: transparent 把它的文字变透明(color 属性保留,所以光标和官方装饰照常工作),再绘制自己的渲染层——每个渲染字符都定位在编辑器文字的真实坐标上(逐字符测量 Range rect)。
渲染层从不自己排版,所以对齐类问题(漂移、抖动、错位)在架构上不存在:实测各场景偏差 ≤ 0.02px,连续打字逐帧偏差 0.00。
插件不注入任何官方服务。它直接读编辑器 DOM 推导「投影文本」(胶囊 → U+FFFC,<br>/段落边界 → 换行),对官方 client API 变化免疫;DOM 锚定用稳定的 data- 属性而非哈希过的 CSS Modules 类名。改动草稿的操作(列表续项、围栏补全、缩进……)走 Lexical 原生通道——保撤销栈的合成 beforeinput 事件——绝不直接改 DOM。
完整深读见 docs/architecture.md。
已知限制
- 含 @ 胶囊的段落按官方纯文本显示(胶囊宽度无法复刻,零错位优先)。热词文本装饰不受影响。
- 块级视觉(标题、引用、列表、表格标记)只上色/加粗/加背景——不改字号、行高、缩进;源文布局保留,行度量永不变化。
- 只要草稿含已闭合代码块,整个输入框切等宽(不是逐行——字面
\n单文本节点的草稿形态让逐行换字体物理不可行)。 - 围栏补全的光标落位等 80ms(Lexical 异步提交);极慢机器上光标可能偶发落位偏后。
- ↓ 跳出仅在已闭合块最后一个内容行触发;未闭合围栏走官方默认行为。
- 「停止生成」按 aria-label 双语枚举匹配;官方改文案时请直接点按钮。
- 仅
webprofile;仅 Chromium 系浏览器。
开发
node test-live.cjs # 188 项单测(纯函数,无需浏览器)
node e2e/run-e2e.mjs # 62 场景 × 10 不变量的 E2E 套件(对着运行中的实例测)
E2E runner 要求被测实例已部署当前源码,路径全部由环境变量推导:DSH_CL_PORT(默认 8124)与 DSH_CL_DSH_HOME(默认取 DSH_HOME,再默认 ~/.dsh)定位部署副本做版本对照,鉴权 cookie 自动获取。完整变量表见 e2e/README.md。
套件复刻六种真实输入通道(字面 \n / 字面 \r\n / 逐行 br / insertParagraph / 合成 paste / 刷新恢复多段落),用一份独立投影与插件自身的投影逐字符交叉验证。
版本纪律:每次改动 bump package.json 并在 CHANGELOG.md 记一笔。
FAQ
为什么只支持 Chromium 系?
透明化手法(-webkit-text-fill-color)和若干光标行为是 Chromium 特有的。Firefox/Safari 需要另一套方案。
会改变我发送的内容吗? 不会。草稿始终是纯 Markdown 源文本,渲染纯视觉。
逐字符测量不慢吗?
按渲染帧合批,合并成少量绝对定位 span。渲染层 pointer-events: none 且脱离文档流,不引起编辑器重排。实测逐击键偏差为 0,无可感知输入延迟。
DSH 升级会弄坏它吗?
零服务注入 + data- 属性锚定让它对日常升级(类名哈希变化、client API 重构)免疫。当官方输入框架构本身变化时——比如 0.1.1 → 0.1.5 从 textarea 换成 Lexical——插件需要重写。本插件正是那次重写的产物:dsh-composer-md 是它的 0.1.x 前身,现已停止维护。