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-10-20 | v1.6.7 | 修复:DSH 0.2.1 契约适配(对照 dsh-v0.2.0-rc.2..0.2.1-alpha.3 diff 逐项核实)——① settings 迁移:settings.register 在 0.2.x 已删除(旧代码在 0.2.1 上抛 TypeError),改为导出 Config(schemastery,字段条件 .volatile():0.2.x 由 settings 服务自动 describe 并可在 Plugins 页编辑;0.1.5 的 schemastery 3.18.2 无 volatile 方法,自动退化为静态字段走旧 register 路径),写路径 settings.update(ns, patch) 两版一致,变更监听 loader/volatile-update + root 上 settings/document-updated;② 配置卡双槽注册:0.1.5 走 settingsScope+settings.plugin.item(0.2.x 已删除,静默不触发),0.2.x 走 configForms.whileServed(['dsh-code-ui']) + keyed 槽 plugins.bundle.config(key=包名,Plugins 页 bundle 详情配置区;slots.inject 对未声明槽静默等待,双注册互不误伤);③ 主题读取修复:契约方法名是 getTheme()(getSnapshot/snapshot 从来不存在,此前实际一直走 body 属性兜底),0.1.5/0.2.x 方法名一致。兼容面同时核实:rpc.call 封套、gateway SRC 扫描、typert-protocol、dsh.client manifest、peer 检查、webServer 路由在 0.2.1 均未变 |
| 2026-10-13 | v1.6.6 | 修复:选中 zip 等二进制文件页面卡死——双重根因:① 编辑器对任何文件都按文本渲染,zip 经截断读取的 4MB 乱码进 tokenizer/highlight 层(数万 span)瞬间撑爆页面;现对已知二进制扩展名(zip/gz/tar/7z/jar/exe/dll/png/jpg/pdf/woff/ttf/mp3/mp4 等 40+ 种)直接跳过文本预览,打开只显示占位提示与只读备注。② v1.6.5 引入的已发消息着色观察器在大 DOM 上每次变动都全量遍历(文本节点级祖先匹配,无法剪枝),编辑器载入大文件后与聊天区流式输出叠加把主线程拖死;现改元素级剪枝(TreeWalker 对 textarea/pre/code/.cdex-workbench/.cdex-dock 等命中即整棵子树跳过)+ 单轮扫描超 80ms 自动进入 1.5s 冷却让出主线程 |
| 2026-10-13 | v1.6.5 | 优化:已发消息的引用标签着色——chip 序列化进正文的 N:文件名:起-止 / 🌐N:文件名 标签在发出后以蓝色高亮展示(--dsw-alias-state-business-primary,与宿主输入框 chip 同色加粗),用户回看消息时能一眼看到引用了什么。实现:MutationObserver + TreeWalker 纯文本节点 overlay(只 split/wrap,不碰 React 管理结构;React 原位改文本时自愈 unwrap 重扫);整文件引用强制要求扩展名(不误伤 12:30 时间文本),匹配点黏在更长单词内(a2:app.ts:1-2)跳过;跳过输入框/代码块/链接/宿主 chip 及本插件自有 UI 区域 |
| 2026-10-13 | v1.6.4 | 优化:发送后消息保留引用标签文本——chip 序列化从「空串隐身」改为输出编号标签(2:package.json:2-3 / 🌐4:package.json:26-32),编号取发送时刻冻结的 seq;消息里看得见引用了什么,AI 侧仍经宿主 systemPrompt 动态 section(code-ui-references)获知全部引用并调 get_referenced_snippets 读取 |
| 2026-10-13 | v1.6.3 | 优化:引用指针不再出现在消息正文——消息末尾的 [code UI] 已标记 N 段代码引用… 附加块整体移除(用户反馈:希望不展示出来但还让 AI 知道);引用信息改由宿主 systemPrompt 动态 section(order 2950,按 session 头取 批次渲染)注入模型上下文,AI 对用户的观感不可见;客户端 chip serialize 返回空串、consumePendingRefs 每次发送带 调 (空=清批次) |
License
MIT