fangwen9527/dsh-composer-ux ↗★ 4
dsh-composer-ux
DSH Web 输入体验增强插件:可配置发送/换行键位 + 自定义输入框右键菜单 + 面板尺寸记忆 + 快捷指令(分类 / 跨分类移动 / 关·每次·仅首次三种插入模式 / 存 ~/.dsh/quick-prompts.json)+ 提示词优化(0.11.1 起工具行有独立「优化」按钮、带秒表与斜杠命令保护、写回前比对草稿) + OpenCode 会话请求头 + Windows 默认终端切换(把模型的 PowerShell 工具换成 Git Bash)+ 官方持久终端六件套(terminal_open/read/send/signal/close/list,常驻挂载 + 缺包自检退化,见 cordis.patch.yml)+ 统计行缓存命中三位小数 + 输入框下方极简金额胶囊(点开看本会话费用与峰谷状态)+ 设置页「金额」栏:按模型改高峰/空闲单价(留空即官方价)、法定节假日(0.11.0 起自动获取国务院办公厅安排,手填则整份覆盖)、峰谷切换提醒、DeepSeek 账号余额、一键同步官方价与第三方价目(models.dev)、非 DeepSeek 模型定价;价格带生效时间的历史档,每笔用量按发生时刻的价目结算;设置页另有「计价说明」一块(刊例价快照 / 价格档 / 峰谷判定 / 非 DeepSeek 口径) + 设置页抬头一键重启 DSH(助手进程 + 等端口 + 隐藏控制台) + 工作区目录选择(设置页开关,默认关;开了之后桌面应用里弹系统文件夹框、任意盘符点选;手机/远端浏览器仍用官方应用内浏览对话框) 适合需要自定义发送键、快捷提示词、提示词优化及终端切换的重度用户。
설치
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:fangwen9527/dsh-composer-uxdsh-composer-ux
English summary — A DeepSeek Harness Web plugin that upgrades the composer (chat input) experience: configurable send / newline keys, a native-style 7-item right-click context menu, a resizable & scrollable settings panel with persisted size, a global on/off switch, a quick-command panel (built-in prompts, click-to-insert, per-item "always append on send"), a prompt optimizer that runs a separate model call before you send, automatic
x-opencode-sessionrequest-header injection so OpenCode (Go) routes work inside DSH, and — on Windows — a default-terminal switch that replaces the model's PowerShell tool with Git Bash (git-anchored discovery, WSL excluded, per-session tool-surface trim, official-identical sandbox/approval/timeout semantics), a composer stats-line upgrade that renders the built-in cache-hit percentage with three decimals (keeping upstream's "never round a partial hit up to 100%" rule), a cost capsule whose peak/off-peak prices you can edit per model in settings (empty field = official list price; peak/off-peak is decided by each usage event's own timestamp, not by when you look at the panel), with Chinese public holidays fetched automatically (State-Council schedule viaholiday-cn, GitHub raw + jsDelivr mirror, built-in table as offline fallback; your own date list always wins), plus a one-click "restart DSH" button in the settings-card header (market-proven self-restart: detached node helper, port-release wait, hidden-console relaunch, same-origin fence, boot-id reload). Install withdsh plugin --profile add dsh-composer-ux(npm) — the builtlib/ships in the package and in this repository, so there is no build step and no build authorization. License: MIT.
看哪一份随你:小白版(三步上手 + 常见问题,讲人话)README.simple.md · 英文版 README.en.md · 本页(中文全版,最详细)。
DeepSeek Harness Web 输入体验增强插件:

上图即 0.5.0 的设置页(六栏都开着)。注意标题行只有卡级开关与从属控件 —— 右键菜单那 7 个条目开关已按实测反馈搬进卡内的「自定义」档(见第 0 条)。
- 两层开关:总开关 + 每栏开关。设置页顶部「启用输入增强」是总开关(默认开),它是一道总闸;八张折叠卡里前七张的标题行右端各有一个卡级开关,决定「这一栏要不要生效」(第 8 张「金额」没有开关 —— 金额胶囊常驻显示)。两处都满足才生效(
enabled && 该栏开关)。前六栏默认关;第 7 栏「统计行」默认开(它是唯一例外,理由见下条)。- 兼容性:同一个产物同时支持 DSH 0.1.6 与 0.1.7。两代的设置服务形状不同(
settingsScope.bind→configForms.get、宿主settings.register被删除、事件名换代),代码按能力探测分支,不维护两份产物。 - ⚠️ 升级 DSH 到 0.1.7 之前先备份
~/.dsh/settings.yaml:0.1.7 的官方升级会把它改名成settings.yaml.imported并逐节导入 profile patch(一次性、不可逆),而本插件这一段在旧版上导不进去(那时还没有 Config 字段表),旧值只会留在那个.imported文件里。 - 老用户不会被升级弄坏:卡级开关的默认值不是硬编码的
false,而是按「设置文档里有没有『你在用』的痕迹」迁移 —— 碰过的栏保持开着、没碰过的才是关;全新安装(空白文档)才是六栏全关。「快捷指令」那一栏多一条文件判据(0.3.0 起条目存在quick-prompts.json,设置文档里看不出来)。 - 例外:0.7.0 的「统计行」是唯一默认开的栏(它不参与上面那套"碰过才开"的迁移)。那五栏都已经发布过,一律默认关会在升级那一刻把用户正在用的东西当场关掉;而「统计行」是新能力,没有痕迹可依,用户要的是"装完立刻看得到效果"。
node test/check-sections.mjs把它单独列一行说明。 - 升级前可以先看一眼:
node test/check-sections.mjs拿你真实的设置文档跑一遍迁移,打印七栏会变成什么(只读,不写任何文件)。文件名按版本试:0.1.7 把settings.yaml改名成了settings.yaml.imported,两个都读。 - 关掉一栏 = 这一块完全不介入,且栏内的值全部保留(打开即原样恢复):键位关 → 输入框按 DSH 原生键位;右键菜单关 → 本插件不介入;快捷指令关 → 输入框那枚按钮消失;设置面板关 → 不拖大小;OpenCode 请求头关 → 停止注入并撤销已写入的头;默认终端关 → 保持 PowerShell。
- 「OpenCode 请求头」那一栏没有额外的开关:原来的「附加请求头」本来就是「这一栏要不要生效」,直接搬到了标题行。
- 兼容性:同一个产物同时支持 DSH 0.1.6 与 0.1.7。两代的设置服务形状不同(
- 设置 → 输入体验(设置页新增条目)
- 版式对齐社区插件
@linxin666/dsh-web-all的「Web 插件」页:顶部常显「中文名 + 内嵌英文包名dsh-composer-ux的一行描述 + 总开关」;其下八个栏目为可折叠卡片 —— 标题行左侧是「标题 + 一句动态概览 + 展开箭头」,右侧是这一栏的开关与从属控件(设置面板的缩放开关、默认终端的三档都在这里),长说明与其余控件在展开后的内容区;默认全部折叠、不记忆展开状态,可同时展开多个。标题行只放卡级开关与从属控件:右键菜单那 7 个条目开关按用户后来的反馈搬回了卡内(它们只对「自定义」档有意义,见下一条)。 - 键位:分别配置「发送键」「换行键」——常用预设(Enter / Ctrl+Enter / Alt+Enter / Shift+Enter)+ 点击「自定义…」后直接按任意组合键录制(Esc 取消,Backspace 清除),支持清空为「无」;发送与换行不能设为相同按键;可一键恢复默认。
- 右键菜单:三档「菜单来源」(官方不介入 / 浏览器菜单 / 自定义菜单,见下「右键菜单」一节);卡内只显示当前选中那一档的说明(点官方看官方的、点浏览器看浏览器的、点自定义看自定义的;自定义档还带 Chrome / Edge 与 Firefox 的剪贴板授权说明);那 7 个条目(撤销 / 重做 / 剪切 / 复制 / 粘贴 / 删除 / 全选)只在「自定义」档显示、逐个开关(旁边一个「全部开启」)。这三件事有真渲染测试盯着(
node test/settings-render.mjs:把设置页渲染成 HTML,断言三档正文互斥、那 7 行只在自定义档、标题行没有第二个入口)。 - 快捷指令:分类增删改 / 条目增删改与上下移 / 跨分类移动 / 每条一个插入模式(关 · 每次 · 仅首次)/ 优化强度三档(详见下节)。
- 设置面板:边缘调整大小一个开关(标题行);尺寸预设与拖拽说明在展开区。导航列滚动由 DSH 官方的设置页自带(0.1.7 起
.navList就有overflow-y: auto),所以 0.6.0 把「导航滚动」那个开关整项删掉了 —— 留着就是重复实现。 - OpenCode 请求头:给 OpenCode 的模型请求自动附加
x-opencode-session(详见下节)。 - 默认终端:Windows 上把模型用的终端工具从 PowerShell 换成 Git Bash(三档在标题行;详见下节)。
- 统计行:输入框下方那行「缓存命中 xx%」按三位小数显示(0.7.0 新增,唯一默认开的栏,只有一个开关;详见下节)。
- 金额:输入框下方一颗极简金额胶囊(本会话费用估算,按 DeepSeek 官方刊例价;点开看三分项明细)。0.24.0 起把子代理(含孙代理)花的钱也并进来 —— 那个数字是「本会话 + 子代理」的合计。这一栏没有卡级开关(胶囊常驻显示),卡内是按模型改高峰/空闲两档单价的编辑器(0.9.1 新增;留空=沿用官方价,可自加任意模型名;详见下节)。
- 重启 DSH:卡片抬头右端(GitHub 链接左边)那枚按钮,两步确认后原地重启(详见「维护:重启 DSH」)。
- 版式对齐社区插件
- 快捷指令按钮:输入框工具行里、「展开」按钮左侧的胶囊按钮,点开是常备提示词清单 + 「优化提示词」。
- 键位生效(仅主聊天输入框):默认值 = 现状(Enter 发送、Shift+Enter 换行、Ctrl+Enter 加速提交),改动即时生效并持久保存。
0.23.0 新增:第九栏「自启动」
- 开关跟着"你在哪个运行时里开"走:网页版里打开就注册网页版(当前 profile、当前启动命令),
桌面应用里打开就注册桌面应用;两个运行时各用自己那一条启动项(
dsh-composer-ux:autostart:)。 - 登录后启动:只写
HKCU\...\Run,不需要管理员;关掉开关就是删掉自己那一条。 - 网页版最小化到任务栏:用生成的 .vbs +
wscript拉起,中间不闪控制台。 - 状态以注册表为准(不写 settings 字段):你手删了条目,界面就显示关;条目在但值对不上会明确提示。
- 卡里另有「立即试一次」,验证它在你这台机器上确实有效。非 Windows 平台如实说不支持。
0.22.0 新增(安全 / 自检 / CLI)
- 解释层「内置 Bash」按会话权限门控:完全权限直跑;其它模式必须过
ctx.sandbox.confine, 约束不是full就拒绝执行;拿不到权限模式或没有沙箱服务 ⇒ 不发这个工具。 - 「OpenCode 请求头」不再写你的配置:改成挂官方
internal/config事件做运行期可逆覆盖, 0.21.x 及以前写进去的残留由迁移表一次性清掉(只删值与记账一致的,你自己写的同名头不动)。 - 自检:设置页多了「自检」卡(也可
GET /composer-ux/doctor),一行一句人话摊平 设置字段是否都在宿主 schema、九栏开关、终端服务与 bash 探测、请求头覆盖、快捷指令本、 通知凭据、解释层档位、运行环境。 - CLI:
npx dsh-composer-ux status|doctor|install|uninstall(安装卸载一律委托官方 CLI)。 - 长命令走文件:解释层的 bash 工具支持
command与script_path二选一, 多行/长脚本落文件再传路径,免得在工具调用 JSON 里做多层转义。 - 市场清单:
package.json的icon(宿主会读)+dsh-plugin.json(权限及理由披露)。
安装
# 安装
dsh plugin --profile web add dsh-composer-ux
# 更新到最新版
dsh plugin --profile web update dsh-composer-ux
npm 包:dsh-composer-ux —— 预构建产物,安装期不在本地执行任何代码,也不需要 pnpm 的构建授权。(--profile web 换成你自己的 profile 名即可。)
其它安装方式(GitHub 源码 / 锁定 commit / 本地目录)
# 从 GitHub 安装(等价;lib/ 构建产物已提交,没有 prepare 脚本,因此不需要 pnpm 的构建授权)
dsh plugin --profile web add github:fangwen9527/dsh-composer-ux
# 锁定 commit 安装(更安全:后续推送无法悄悄改变实际运行的内容)
dsh plugin --profile web add github:fangwen9527/dsh-composer-ux#
# 本地目录 / 源码开发(等价于 link;改完 src/ 先跑 node build.mjs)
dsh plugin --profile web add
本插件按官方「打包与安装插件」规范打包为可安装组合包(bundle):package.json 声明 dsh.bundle.patch → ./cordis.patch.yml,该层以包名插入插件行 dsh-composer-ux,装进 profile 后由 pnpm/Node 从 node_modules 解析到 lib/index.js。
装完按 DSH 提示重启一次(Host 半的插件代码只在进程启动时 import),客户端半刷新页面即生效。
发现渠道:仓库已打官方发现用的 dsh-plugin topic(另带 deepseek-harness / cordis / dsh / opencode 等关键词);社区目录(mydsh.dev、dshbase.com、dsplugin.app)按该 topic 自动同步收录。仓库里的 cordis.patch.yml 就是随包发布的组合层文件,dsh.bundle.patch 指向它即可。
从 DSH 源码检出直接 --patch 挂载的本地开发方式见下文「加载」一节。
键位规则
- 目标限定在 DSH Web 主聊天输入框(
[data-composer-input]);其他输入框不受影响。 - IME 安全:中文/日文输入法组合期间(
isComposing/keyCode 229)一律放行,绝不误发、误换行。 - 发送/换行通过回放官方按键管线实现(发送 = 普通 Enter,换行 = Shift+Enter),因此所有官方保护均保留:忙时排队 / 油门(steer)、连发防重、空草稿不发送、
/@触发器菜单打开时 Enter 仍优先选择菜单项。 - 未绑定的 Enter 系按键(如把「发送」清空后按 Enter)不会触发任何动作;Ctrl+Enter / ⌘+Enter 未被绑定时保留官方「加速提交」行为(绑定为空闲草稿的队列推进等)。
- 单个字母/数字键不允许裸绑定(会与打字冲突);纯修饰键不会触发录制。
- 部分 Ctrl/Meta 组合被浏览器占用(如 Ctrl+L、Ctrl+W、Ctrl+J),录制时无法在页面捕获——建议使用 Alt/Shift 组合或 Enter 系键位。
右键菜单
设置 → 输入体验 → 右键菜单 里是三选一的菜单来源(只影响右键,不影响键位与其它功能):
- 官方(默认):本插件完全不介入,DSH 与其它插件自己的右键处理原样生效。DSH 官方输入框本身没有右键菜单,所以通常看到的就是浏览器的菜单。
- 浏览器:固定使用浏览器自带的菜单(样子随浏览器而变),并在本插件这一层挡住其它插件的菜单;好处是粘贴免授权、零配置。
- 自定义:使用本插件固定样式的菜单(未选中文本时「剪切 / 复制 / 删除」置灰)。这一档的「粘贴」要读剪贴板,浏览器会先要一次授权,三家处理不同:
| 浏览器 | 首次/之后 | 改或撤销授权 | 免掉弹窗的办法 |
|---|---|---|---|
| Chrome / Edge | 弹出后点「允许」即记住这个站点,之后不再问 | 地址栏最左的网站图标 → 网站设置(Edge 叫「此站点的权限」)→ 剪贴板;或 chrome://settings/content/clipboard(Edge 是 edge://settings/content/clipboard) | 不需要:允许一次即可 |
| Firefox | 每次点「粘贴」都会弹一个只有「粘贴(P)」一项的小窗(约 1 秒后才可点),点它才完成 | 无(没有站点授权面板) | 关不掉:这是 Firefox 的安全机制,网页不允许静默读剪贴板。不想多这一步就按 Ctrl+V,或把「菜单来源」切成「浏览器 / 官方」档 |
0.4.0 实测更正:早先文档里教过「改
about:config里某个剪贴板首选项就不弹窗」——那是错的,那个弹窗与任何首选项都无关(用户在 Firefox 上照做后弹窗照旧)。依据:MDN Clipboard API 的安全说明(读到不允许的内容时,浏览器弹的临时菜单里只有一个 Paste 项、约 1 秒后才可点)、caniuse(只有带clipboardRead权限的扩展不显示粘贴提示)。能免掉它的设置都属于「允许任何网站静默读剪贴板」那一类,本插件不教、也不建议改。
chrome:///edge://这些地址不能做成网页里的链接(浏览器禁止页面跳转到内部协议),只能手输或复制粘贴到地址栏。被拒绝授权或无响应时,菜单里会提示「请用 Ctrl+V 粘贴」。
自定义档的细节:
- 样式与系统编辑器菜单一致(深色圆角、三分组、快捷键右对齐);被关闭的条目不显示(分隔线自动合并);只在这档下才显示那 7 个条目开关与「全部开启」。
- 撤销 / 重做 / 剪切 / 复制 / 删除 / 全选 走标准编辑命令;粘贴 读取剪贴板后在光标处插入纯文本——这是浏览器的安全限制。
- 菜单打开时点击外部、Esc、滚动或窗口变化都会关闭。
- 该档
preventDefault掉浏览器菜单,并和「浏览器」档一样挡住同一层里其它插件的捕获监听(否则两边会各弹一个菜单)。
快捷指令与提示词优化
输入框工具行里、「展开」按钮的左侧有一个同款胶囊按钮「快捷指令」(槽位 conversation.input.right,order 89 起因(用户原话):「现在它提示词优化是悬浮的特别是我点叉关闭之后居然恢复不了」。
- ✕ 改成「收起」:结果不再被删,只是标记成"先别显示";面板切回「快捷指令」那半,切换按钮写 「上次的结果在这儿」,点它就能再展开(按钮 tooltip 明确写「结果留着」)。
- 新增「丢弃」(结果框标题行里、✕ 左边,样式弱化):点两次才真丢(第一次换成「点第二次丢弃」, 4 秒后自己复位),丢掉时才清状态 + 删磁盘那份。
- 收起状态跨重启记住(用户选的 A):状态信封加了一个可选的
hidden,不升版本号 —— 没收起时不写这个字段,文件形状与 0.13.0/0.13.1 完全一致,降级回旧版也认得;老文件没有该字段 = 没收起。 - 新跑一轮(✨ / 重新优化)会自动把框显示出来,不会被收起状态挡住。
- 结果框不再画成一张独立卡片(去掉自己的背景与圆角边框,只留一条细分隔线)—— 这就是用户说的"悬浮"观感:它现在看起来是面板里的一段,而不是浮在上面的小窗。
实机(0.13.1,2026-09-30 重启后当场核过)
① 中部是「快捷指令」那半(默认):分类标签 + 条目列表 + 底部计数;标题行始终有「快捷指令 + 普通/高级/极端 + ✨ 优化提示词」,
中间的切换按钮是 ▸ 优化提示词,右侧写明另一半的状态(这里写的是「上次的结果在这儿」):

② 点切换按钮 → 换成「优化提示词」那半(列表收起,▾ + 「点此回到快捷指令」):结果框里是条目流水、可编辑成品与记账行,
底部那排「插入输入框 / 重新优化 / 复制」完整可见 —— 这正是 0.13.1 修的 bug:以前结果框一长,这排按钮会被面板裁掉:

③ 面板已经到了自己的高度上限(约 60vh),按钮依然在:成品输入框右侧出现自己的滚动条,内容区滚而按钮不动 —— 这就是"两半互斥 + 结果框拆成可滚区 + 钉底按钮行"的现场效果:

说明:面板里那份结果是用户自己跑的一次优化(
go/deepseek-flash,用时 9.7 秒,7 条补全),不是我为了截图新花的调用; 截图时也没有改动它(没点「插入输入框」、没点 ✕,只切换了两半、开关了面板)。 0.11.1 曾试过在工具行加一枚独立的「✨ 优化」按钮(点一下 = 开面板 + 立刻开跑),用户看到实机后明确否掉 —— 「我让你集合到快捷指令里的提示词优化按钮里」,于是 0.12.0 删掉它,回到单一入口。
- 秒表:面板主按钮与结果框都显示已等待秒数,结束时报「用时 x.x 秒」。边界如实说:阶段只能到"等待模型响应" —— 更细的进度由逐条流水本身给出(它就是"它在干活"的证据)。
- 斜杠命令保护:
/goal 帮我写周报只把命令后面的正文送去模型,插入时把/goal原样拼回;只有命令没有正文时直接提示、不发请求。/path/to/file这类路径不会被误判成命令(判据SLASH_COMMAND_RE,两端共用)。 - 推理强度钳最低档:按路由真实暴露的档位(
llm.resolveModelInfo)选最省那一档 —— 推理模型不指定档位时会先空转很久;查不到档位表就什么都不传(绝不乱造适配器不认的值)。 - 客户端断连即中止:关页面/切走会话时
res.on('close')立即 abort 这次模型调用,不再白烧额度(用res而非req:req的 close 在请求体读完就触发)。 - 0.6.0 起它不再"自由改写":模型只产出条目,每条
rewrite/requirement/quality必须附一段在你原话里逐字存在的引文;宿主逐条做字面比对,对不上就只丢那一条并记账。rewrite按引文位置回填,没被覆盖的原话原样保留,其余条目按节追加在末尾。于是"替你发明一条你没说过的需求"在结构上做不到。 - 三档的差别是依据预算:普通 = 只做语言层修复;高级 = 可以补"能指回原话某一句"的必要要求;极端 = 再加分阶段计划与预案。成品有篇幅预算(普通档 1.4 倍),超了就按固定顺序丢可选的节,并把"省略了几条"写进成品(绝不静默截断)。
- 状态行会如实交代这一轮的结果:
N 条补全 · 丢弃 M 条 · 重试过一次 · 自定义提示词;模型没按条目契约输出时走整段照收的兜底并标注未校验依据(保证改造不会让原本能用的优化变成失败),输出像条目信封但半截坏掉时直接失败、绝不把坏 JSON 写进输入框。
实机(0.12.0)
工具行只有一枚「⚡ 快捷指令」(优化从面板进,见下面第 2 张): 0.11.1 曾在工具行并排加过一枚独立的「✨ 优化」按钮,用户看到实机后否掉 —— 它撤了, 秒表读数与忙碌态都在面板主按钮上,信息一点没少。

逐条流式:点开面板 → 点「✨ 优化提示词」→ 条目一条一条出现, 只显示已经闭合、且通过逐字校验的条目(没通过的不会伪装成通过); 框顶是秒表读数与「取消」,跑的时候按钮是压暗的:

完成态:优化完成 · 用时 17.5 秒。每条下面挂着它引用的那句原话,
成品可以直接在框里改,点「插入输入框」才写回你的输入框:

写回之后:输入框里就是成品(Ctrl+Z 可还原),可以接着改或直接发:

设置页那一栏新增「携带会话上下文」(默认开,用来消歧义;上下文不算引文依据):

上面这 5 张是 0.12.0 发布前在真机上截的(同一份产