dsh-composer-live
打 Markdown,边打边渲染——给 DeepSeek Harness(DSH)Web 输入框带来 Open WebUI 风格的实时编辑体验,代码块语法高亮、任务列表、格式工具栏、智能粘贴。
安装
dsh plugin --profile web add dsh-composer-live
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
<p align="center"><img src="https://github.com/zeusxx/dsh-composer-live/raw/main/assets/icon-180.png" width="96" alt="dsh-composer-live 图标"></p>
<h1 align="center">dsh-composer-live</h1>
<p align="center"><b>打 Markdown,边打边渲染</b>——给 DeepSeek Harness(DSH)Web 输入框带来 Open WebUI 风格的实时编辑体验。</p>
<p align="center">[English](./README.md) · [简体中文](./README.zh-CN.md)</p>
<p align="center">
<img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT">
<img src="https://img.shields.io/badge/DSH-%3E%3D%200.1.5--rc.2-4c6ef5" alt="DSH >= 0.1.5-rc.2">
<img src="https://img.shields.io/badge/tests-206%20unit%20%C2%B7%20129%20E2E-2ea44f" alt="tests">
</p>
dsh-composer-live 把 DSH Web 的输入框变成 Open WebUI 风格的实时编辑器:你打 Markdown,它边打边渲染——加粗、斜体、带语法高亮的代码块、列表、引用、表格——而草稿本身始终是纯 Markdown 源文本,发送出去的就是你输入的原文。
它是一个纯浏览器端插件:零运行时依赖、不注入任何官方服务、不改官方源码。它在官方 0.1.5 Lexical 输入框之上叠加增强,不重复 DSH 已原生提供的功能。
找 DSH 0.1.x(textarea 架构输入框)的版本?那是 [dsh-composer-md](#faq)——本插件的前身,已停止维护。
截图
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 自动补|---|---|分隔行加一个空行,光标落空行。
工具栏与快捷键
- 常驻格式工具栏(v0.2.14 起在输入卡外正上方):加粗 / 斜体 / 行内代码 / 链接 / 列表 / 代码块 / 展开。选中文字时包裹、未选中插入空标记;光标落在
…内时加粗键自动点亮。工具栏是与输入卡等宽的独立细条,不占输入框内部高度,也永不与正文或图片附件重叠。 - 选区浮动格式条(Open WebUI 形态):选中一段文字,加粗/斜体/代码/链接四键浮现在选区上方。
- Ctrl+B / Ctrl+I / Ctrl+E 快捷加粗 / 斜体 / 行内代码——同时拦掉浏览器对 contenteditable 的原生加粗(那会悄悄往草稿里插入真正的
<b>标签)。
粘贴处理
- 大段粘贴(超过 8 行或 4KB)且内容像代码/日志时,自动用代码围栏包起来——单一撤销单元,配 toast 轻提示。中文长文不误判;光标已在代码块内或内容本身含围栏时不包。
Esc 分发、主题、兼容
- Esc 按语境做对的事:官方候选菜单开着 → 归官方处理;展开态 → 收起;AI 生成中 → 停止生成。
- 一键展开 70vh 长文写作模式。
- 明暗主题自适应;输入法安全(拼音组字不闪烁);渲染按 rAF 合帧、增量进行。
- @ 引用胶囊保持官方原样、可编辑。含胶囊的段落优雅降级为官方显示(胶囊宽度无法复刻,零错位优先)。热词文本装饰不受影响——
/命令与技能名的引用装饰在渲染层沿用官方引用色,官方 hover 背景已禁用(它画在渲染层之上,会盖住文字)。 - 顺带修复官方在图片附件在场时的两个定位问题:候选菜单悬空浮出输入框、工具栏盖住缩略图。
不与 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 · 菜单开着→官方 · 展开态→收起 · 生成中→停止 · 按语境分发
实测版本
每个版本发布前都在两个真实实例上跑完整 129 场景 E2E(覆盖两代支持的架构):
DSH 版本 · 状态
0.1.5-rc.2 · ✅ E2E 实测通过
0.2.0-rc.2 · ✅ E2E 实测通过
0.2.1-rc.5 · ✅ E2E 实测通过(主力环境)
环境要求
- 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](./docs/architecture.md)。
已知限制
- 含 @ 胶囊的段落按官方纯文本显示(胶囊宽度无法复刻,零错位优先)。热词文本装饰不受影响。
- 块级视觉(标题、引用、列表、表格标记)只上色/加粗/加背景——不改字号、行高、缩进;源文布局保留,行度量永不变化。
- 只要草稿含已闭合代码块,整个输入框切等宽(不是逐行——字面
\n单文本节点的草稿形态让逐行换字体物理不可行)。 - 围栏补全的光标落位等 80ms(Lexical 异步提交);极慢机器上光标可能偶发落位偏后。
- ↓ 跳出仅在已闭合块最后一个内容行触发;未闭合围栏走官方默认行为。
- 「停止生成」按 aria-label 双语枚举匹配;官方改文案时请直接点按钮。
- 仅
webprofile;仅 Chromium 系浏览器。
开发
node test-live.cjs # 206 项单测(纯函数,无需浏览器) node e2e/run-e2e.mjs # 129 场景 × 10 不变量的 E2E 套件(对着运行中的实例测)
E2E runner 要求被测实例已部署当
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:11,最后更新 2026-11-01