dsh-code-ui
在 DeepSeek Harness(DSH)里的 Cursor 风格 AI 代码编辑器插件:文件树、多标签页编辑、语法高亮、引用/翻译给 AI。
它把 Cursor 那种「边看代码、边跟 AI 对话」的体验搬进 DSH:一个带活动栏、文件树、多标签页编辑器的代码工作区。v1.2.0 起支持两种布局:右侧停靠(code UI 固定占屏幕右侧、与聊天并排,默认布局)或悬浮窗口(可拖拽浮动窗口,内嵌 AI 输入框),插件卡片里可随时切换。
界面一览
右侧停靠布局(默认布局)——对话与 code UI 左右并排,边聊边看代码:
右侧停靠布局:对话与 code UI 左右并排
悬浮窗口布局——可拖拽、可缩放的浮动编辑器窗口,内嵌 AI 输入框:
悬浮窗口布局
两种切换按钮(插件卡片「切换按钮」可选)——点击在 code UI 与 dsh UI(DSH 原生界面)之间切换,与布局任意组合:
📍 所有配置都在:设置 → 插件 → 插件列表 → dsh-code-ui 的配置卡片——编辑器界面(右侧停靠 / 悬浮窗口 / 隐藏)、编辑器主题、语法配色、切换按钮、启用开关、检查更新,切换即时生效并持久化保存。
功能
- 双布局可选:右侧停靠(默认布局,与聊天并排) / 悬浮窗口(可拖拽缩放),插件卡片切换、即时生效
- 切换按钮可选:悬浮模式条(默认,可拖动) / 会话头
⌨ code UI 按钮,与布局任意组合
- 界面模式可持久化:code UI / dsh UI(默认隐藏,不自动占屏,入口按钮随时唤回),所有入口切换均同步记忆
- Cursor 风格工作区:活动栏 + 文件树侧边栏 + 多标签页编辑器 + 状态栏
- 侧栏收起与调宽:« 按钮 / 📁 三态 / 拖到最窄自动收起,» 把手展开,右缘拖拽调宽
- 停靠面板拖宽:左缘手柄实时调整面板宽度,DSH 界面自动跟随
- 语法高亮:highlight.js 11(193 种语言)替换自研 tokenizer——宿主路由懒加载不拖累启动,10 款语法配色可选(自动随明暗 / GitHub / Dracula / Monokai…),加载失败或桌面端自动回退内置轻量高亮
- 文件浏览与编辑:展开目录、打开文件、直接编辑、
Ctrl+S 保存写回磁盘;外部修改自动同步
- 选中代码右键:
- 📋 复制
- 📥 粘贴到备注
- 📝 添加备注
- 🌐 翻译(🌐 chip 直插输入框,交给 AI 翻译)
- 🔗 引用给 AI
- 行内引用 chip:引用/翻译后 chip 直接嵌入输入框句中(
1:文件名:起行-止行,翻译带 🌐 前缀),点击跳转编辑器;@ 菜单可把引用插入句中任意位置;发送时 chip 原位展开为引用行,随消息一次性消耗(chip 清空、【引用/备注】留档可查);允许重复引用(chip 可见、可删)
- 内嵌 AI 输入框(悬浮布局):直接输入、
Ctrl+Enter 发送;发送时不粘贴引用正文,只附一行引用指针,内容由 AI 调用 get_referenced_snippets 工具读取
- 主题四态:跟随 DSH(默认)/ 跟随系统 / 浅色 / 深色,插件卡片切换
- 以此文件夹为根:文件浏览器里可选任意目录作为工作区根
- 根目录按会话隔离:切换对话自动换根,各会话的手动根互不污染;新建对话(未发消息)也能立即定位其工作区
- 标签页右键菜单:关闭 / 关闭其他 / 关闭右侧标签页 / 关闭已保存 / 关闭全部 / 复制路径;关闭未保存文件前确认(保存并关闭 / 不保存 / 取消,保存失败者保留打开)
- 检查更新 / 一键更新:设置 → 插件 → 插件列表 → dsh-code-ui 的配置卡片,支持在线检查 npm 新版本并一键更新;未发布/开发期可填本地
.tgz 路径安装(pnpm 流式进度展示,失败自动归类给出建议,完成后提示重启 DSH 生效)
安装
通过 dsh plugin 一键安装(已声明 dsh.bundle):
dsh plugin --profile web add dsh-code-ui
安装完成后重启 DSH,编辑器默认隐藏(dsh UI,不自动占屏);页面顶部出现可拖动的悬浮模式条(默认切换按钮),点 code UI 即可打开编辑器——默认布局为右侧停靠、默认根目录为当前会话的工作区,想换会话头 ⌨ 按钮或悬浮窗口,到 设置 → 插件 → 插件列表 → dsh-code-ui 的配置卡片里切换。
或手动安装:
cd $DSH_HOME/profiles # Windows: %USERPROFILE%\.dsh\profiles
npm install dsh-code-ui
然后在 cordis.patch.yml 追加:
- insert:
- id: dsh-code-ui
name: 'dsh-code-ui'
使用
- 点顶部悬浮模式条的
code UI 打开编辑器(默认切换按钮;也可在插件卡片换成会话头 ⌨ 按钮),默认布局为右侧停靠
- 在文件树/浏览器里打开文件
- 选中代码右键 → 引用 / 翻译 / 备注 / 复制
- 悬浮布局底部输入框直接发消息(
Ctrl+Enter 发送);停靠布局用 DSH 原生输入条,引用以行内 chip 嵌在输入框句中,正文由 AI 工具读取
- 也可对 AI 说「读取我引用的代码」,AI 会调用
get_referenced_snippets 工具
目录结构
dsh-code-ui/
├── package.json # 包声明(含 dsh.bundle.patch / dsh.client)
├── lib/
│ ├── index.js # Host 端:connection.rpc 文件/引用/备注 RPC + get_referenced_snippets 工具
│ │ # + webServer exact 路由(下发 lib/vendor 静态资产)
│ ├── client.js # Client 端:__ModuleLoader__ + 编辑器 UI(highlight.js 懒加载接线)
│ └── vendor/ # highlight.js 全量包 + 作用域化主题 CSS(脚本生成,勿手改)
├── tools/ # vendor 重建脚本:node tools/vendor-hljs.mjs [版本] [--themes-only]
└── cordis.patch.yml # bundle 插接层
纯 JavaScript 手写实现,无需构建,可直接 npm publish。
实现说明
- 语法高亮:
lib/vendor/ 下为 highlight.js 全量包(core + 193 语言)与作用域化主题 CSS,由 tools/vendor-hljs.mjs 从 CDN 生成;宿主经 webServer 注册两个 exact 路由下发,客户端首次需要高亮时以 <script>/<link> 懒加载(绝不内联进 client.js),失败或 Electron(file://)自动回退内置轻量 tokenizer;重高亮带 ~60ms 防抖与 512KB 大文件降级。
- Host↔Client RPC:Host 通过
connection.rpc.handle("/dsh-code-ui", handler) 注册文件系统/引用/备注端点;Client 通过 connection.rpc.call("/dsh-code-ui", endpoint, payload) 调用。RPC 返回值遵循 DSH 的 RpcResult 协议({ ok: true, value } / { ok: false, error })。
- 模型工具:注册
get_referenced_snippets,让 AI 读取用户标记的代码片段。
- Client UI:
window.__ModuleLoader__.load({ id, factory }) 注册,React 通过 require("react") 获取,slot 通过 ctx.get("slots") 注册(shell.overlay),样式用 --dsw-alias-* 主题变量。
二次开发
lib/index.js:改文件读写、引用/备注存储、或新增 RPC 端点(在 connection.rpc.handle 的 handler 里加 if (endpoint === ...))
lib/client.js:改编辑器 UI 布局、配色(styles 模板串里的 CSS)、或新增右键菜单项
- 引用/备注数据存模块内存(运行期有效,重启清空)
更新日志
约定:每次版本升级在本节顶部追加一行(时间 | 版本 | 修复/新增内容)。
| 时间 | 版本 | 修复 / 新增 |
|---|
| 2026-09-11 | v1.5.2 | 修复:停靠面板拖拽分界线不再折行——编辑区去掉 min-width 下限,面板标题/按钮/状态栏等文本全部 nowrap + 省略号截断,拖到多窄只截断、不把文字竖排成一列;停靠面板左缘拖到宽度 < 80px 时自动切回 dsh UI(还原拖前宽度,下次展开不残留细条) |
| 2026-09-11 | v1.5.0 | 里程碑:引用体系全面升级——行内引用 chip。引用/翻译后标签不再挂在输入框上方,而是以 chip 直接嵌入输入框句中(1:文件名:起行-止行,翻译带 🌐 前缀),点击跳转编辑器、退格即删;@ 菜单可把引用插入句中任意位置;发送时 chip 原位展开为 - 代码引用 / - 翻译引用 文件名:行号(路径) 引用行,正文由 AI 经 get_referenced_snippets 读取。实现:注册宿主 InputTrigger 触发源(candidates/onPick/codec)+ ReferenceChipNode 装饰器直插(shell.insertReference,实时取 conversation.input.shell(sid).snapshot 的 draft/draftRev);chip ref 自包含 JSON(抗刷新/重启)。配套:引用一次性消耗——发送即标记已使用、chip 清空、【引用/备注】留档可查;允许重复引用(chip 可见可删,取消 host 去重);引用编号全链路贯通——标签/消息指针/引用卡/AI 工具输出同号,对 AI 说「引用N」即指对应条目;【引用/备注】条目右键菜单(复制 / 翻译 / 引用给AI);消息区引用卡 + chip 文件图标/点击跳转;提示条 ✕ 手动关闭兜底;移除「引用消耗模式」配置项(固定一次性)与输入条上方 tag 条(被行内 chip 取代)。工程:发送补丁改挂 shell.submit 必经点(原生输入条回车/按钮走 keyboard.submit,原 inputActions 补丁只覆盖插件输入卡);纯 chip 携带的发送同样消耗 |
| 2026-09-09 | v1.4.1 | 修复:编辑器每敲一个字符文本抖动一下。根因:hljs 就绪后,每次击键高亮层经历「tokenizer 顶上 → 60ms 防抖后换 hljs」两次全量 innerHTML 重写,浏览器重写 innerHTML 时 scrollTop/scrollLeft 被重置为 0——凡滚动过(垂直或水平)的文件,每次击键可见文本都会位移。修复:≤32KB 的文件改为同步走 hljs(单帧渲染直接出最终结果,无交换帧、工作量减半),>32KB 保留 60ms 防抖路径;并在每次渲染提交后从 textarea 回同步高亮层与行号滚动位(兜底所有 innerHTML 重写场景)。新增:编辑器状态按会话记忆——切换对话时快照当前会话的标签页/激活项并恢复目标会话的(此前 applyRoot 换根即清空标签与缓冲,切会话打开的文件全消失);滚动位按文件路径记忆、标签恢复挂载即自动回滚;焦点不恢复,由用户自己点击决定;缓冲/脏标记以绝对路径为键全局保留,切走再切回未保存内容与 ● 状态原样还在,原「有脏文件暂不跟随根」守卫随之退役,根始终跟随新会话;文件树展开状态同样按会话记忆——目录展开与已加载子目录随会话快照/恢复(applyRoot 仅在 nodes 里没有该根节点时才重建树,同根换会话不再折叠),侧栏不再切一次对话就全部收起 |
| 2026-09-08 | v1.4.0 | 里程碑:语法高亮升级 highlight.js 11(193 种语言,替换自研 tokenizer)。宿主 webServer exact 路由下发 lib/vendor/ 全量包与主题 CSS,客户端首次高亮时懒加载、不拖累 SPA 启动;Electron(file://)/断网/路由缺失自动回退原 tokenizer 保底可用。插件卡片新增「语法配色」:自动(默认,随编辑器明暗 GitHub ↔ GitHub Dark)+ 10 款固定主题(GitHub / Dracula / Monokai / Nord / VS…),仅染 token 色、编辑器底色仍归「编辑器主题」管理,切换即时生效并持久化。性能:重高亮 ~60ms 防抖 + >512KB 大文件自动降级轻量高亮。tools/vendor-hljs.mjs 重建管线入库(支持 --themes-only、fetch 超时重试、Dracula 取官方源)。兼容性:适配 dsh 0.1.2+ 新版 settings 服务——不再 import 已删除的 installSettingsSection/settingsNamespace 具名导出(具名导出缺失会让宿主启动即退出),照 dshmarket 内联 register/watch 接线(服务 API 新旧一致),旧宿主 0.1.0-rc.7+ 同样可跑。交互优化:文件树选中态改为实心选中色 + 选中文字反白 + 左缘 2px 白色强调条——底色跟随宿主 令牌(与 dshUI「对话/轨迹」页签同源,回退 #4176e6),宿主换肤自动同步;原层级灰在浅色主题下与侧栏底色仅差 5/255,选中几乎隐形。文件树根目录:宿主以 sessionId→root 映射记忆各会话的手动根(「以此文件夹为根」只影响当前会话,不再全局污染),切换会话即解析新会话的 cwd 或其记忆根——修复「新会话打开仍是旧会话地址」(原手动根为宿主级全局变量,且客户端跟随标志不持久化导致刷新后跟随失效且无提示)。未发消息的新会话也能解析根目录:会话创建时所选工作区路径已写入不可变 ,经 服务可查(原仅查 ,agent 要到首条消息后才存在);重启后重开旧对话(agent 尚未恢复)时经 读持久化 header 兜底。空新对话(blank 会话)根因:宿主对 blank 会话隐藏会话头 chrome(hideChrome),插件 InputBridge 所在 slot 不渲染、捕获不到新会话 id——新增常驻 SessionWatch(root 作用域 + 标准 props )监听当前选中会话,blank 会话(宿主侧 agent 在 session/create 时即建、cwd=所选工作区)也能即时换根。标签页:关闭 / 关闭其他 / 关闭右侧标签页 / 关闭已保存 / 关闭全部 + 复制路径(无对象项自动置灰);关闭波及未保存文件时弹确认框(保存并关闭 / 不保存 / 取消,多文件列清单、>5 折叠计数,保存失败者保留打开)——原标签 ✕ 按钮静默丢弃未保存改动,一并接入同一确认流程 |
License
MIT