Skip to content

dsh-composer-live

Verified

dsh-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 实时渲染与输入体验增强。

English · 简体中文

License: MIT DSH Tests

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)(白名单协议)、![图片](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,web profile——本插件面向 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 双语枚举匹配;官方改文案时请直接点按钮。
  • 仅 web profile;仅 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 前身,现已停止维护。

许可证

MIT