dsh-settings-order
已验证dsh-settings-order · v0.2.6 · MIT · Web 界面
Free ordering for the DeepSeek Harness Web Settings navigation: drag, Alt+Arrow or the footer's ↑/↓ controls reorder the Settings dialog's left column, persisted in the host profile configuration. 设置左列自由排序:拖动 / Alt+↑↓ / ↑↓ 按钮,写入宿主 profile,跨浏览器生效。
安装
dsh plugin add dsh-settings-order 用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。
源码
标签
作者
说明文档
dsh-settings-order
让 DeepSeek Harness Web 的「设置」左列可以自由排序。
拖动某一行、按 Alt+↑/Alt+↓,或用页脚的 ↑/↓ 按钮移动当前页——顺序存在宿主,
重启后仍在,凡是能访问宿主设置的浏览器都跟着变。
设置
↑ ↓ 恢复默认
归档会话 ← 从最底下拖上来的
通用设置
模型
插件
插件市场
…

为什么需要它
设置面板的左列由 settings.section 列表槽渲染,而 SlotCore 会把这些条目
按 priority 再按各插件自己登记的 order 排序。也就是说每一行的位置是各插件
在打包时定死的:设置外壳既没有拖拽、也没有排序开关或偏好项,用户空间里没有任何
官方途径能改。
本插件不碰槽注册表(不重复注册、不覆盖 order、不去改别的包的 order 字段),
只是把已经渲染出来的行重新排列,并记住结果。
能力
| 拖拽 | 抓住任意一行拖到目标位置(有插入指示线) |
| 键盘 | 聚焦某行后按 Alt+↑ / Alt+↓ |
| 页脚按钮 | ↑ / ↓ 把当前正在看的那个设置页上移/下移一位——手机上唯一的可行路径(手机浏览器没有鼠标拖拽也没有 Alt 键) |
| 恢复默认 | 顺序一旦与内置顺序不同,页脚出现「恢复默认」 |
| 宿主持久 | DSH 0.1.7-rc.1(及兼容的稳定版)将列表写入当前 profile 的 cordis.patch.yml,位于 settings-order 条目的 config.order;所有能访问该宿主的浏览器共用 |
| 浏览器本地兜底 | 连不上宿主设置的浏览器(部分远端场景)退化为自己的 localStorage,并在页脚注明 |
| 失效可见 | 未来 DSH 若改了标记结构,插件什么都不做,并在页脚显示「无法识别设置项」,不会静默失效 |
| 非破坏性 | 第三方页(archived-sessions、market、cost-meter…)与内置页一样可排;后来新增的页留在外壳给它的位置;已不存在的 id 自动忽略 |
其他一切都不动:不改会话/工作区顺序,不碰别的插件的 DOM,不注册槽,不产生模型可见输入,不发网络请求。
安装
要求:装了 DSH 并带 Web GUI,且有一个可安装的 profile(下面统一用 web)。
SettingsForms 的 schema-derived volatile Config API 已对照 0.1.7-rc.1 的源码和类型,
以及 DSH Desktop 0.2.0-rc.2 内置的那套 harness 检查;
仍提供旧版 settings.register() API 的宿主也保留兼容路径。安装时不需要构建——客户端 bundle
是随包发布的成品。
# 从 npm 安装(已发布的版本,最快的路径)
dsh plugin --profile web add dsh-settings-order
# 钉住某个版本
dsh plugin --profile web add [email protected]
# 从 GitHub 安装(跟随 main)
dsh plugin --profile web add github:jackovibe/dsh-settings-order
# 想钉住某个 GitHub 发布版
dsh plugin --profile web add github:jackovibe/dsh-settings-order#v0.2.6
# 或从本地目录 / 打包产物安装
npm pack
dsh plugin --profile web add .\dsh-settings-order-0.2.6.tgz
dsh plugin add 会同时登记依赖并把它追加进 dsh.profile.bundles,挂载就靠这个:
包里自带 bundle patch,所以不要再在 profile 的 cordis.patch.yml 里写第二条
insert(重复 loader id 会导致启动失败)。
然后重启 dsh web:宿主半通过插件 Config schema 暴露可编辑字段,而 profile 的客户端 bundle
是启动时快照后下发的,只刷新页面不够。打开设置——左列底部会出现 ↑ / ↓ 与一行
提示,改过顺序后还会出现「恢复默认」。
DSH Desktop(桌面版)
桌面版自带一套 harness(0.2.0-rc.2 把全部 @deepseek-ai/dsh-* 都锁在该版本)和它自己的
desktop profile,所以要装进那个 profile,并且要用桌面版自带的 CLI——npm 装的 dsh
启动的是另一套 harness,连读桌面 profile 都会被拒
(error: profile "desktop" is managed exclusively by the Electron application):
& "D:\DSH Desktop\resources\runtime\cli\bin\dsh.cmd" `
plugin --profile desktop add [email protected]
路径按你的桌面版安装位置调整。这条命令走桌面版自带的 pnpm,这点重要:桌面 profile 的
lockfile 归应用自己写。装完必须重启桌面应用——宿主半在启动时注册、客户端 bundle 也是
启动快照下发的,重启后左列底部才会出现页脚。之后改顺序会落到
~/.dsh/profiles/desktop/cordis.patch.yml 的 settings-order.config.order,与 Web profile 一致。
更新
dsh plugin --profile web up dsh-settings-order # 重新解析依赖
如果新版本改了客户端半(lib/client.js)就需要重启 dsh web;只改文档的版本不用。
用法
- 打开 设置。
- 想怎么排就怎么排:拖动某一行,或点选某个设置页后按页脚的
↑/↓(也可以在聚焦行上按Alt+↑/Alt+↓)。 - 顺序立即保存;一旦与内置顺序不同,页脚出现「恢复默认」。用过一次后那行提示会自动收起。
存储
在 DSH 0.1.7-rc.1 的 schema-derived settings API 下,顺序写入当前 profile 的
cordis.patch.yml,作为 loader 条目的配置:
- id: settings-order
config:
order:
- general
- archived-sessions
- plugins
具体文件是当前 profile patch(可通过 settings.documentPath 查看),不是已移除的
~/.dsh/settings.yaml。浏览器半通过设置域的 configForms 服务访问它
(ctx.configForms.get('settings-order'),DSH 0.1.7 引入);更旧的宿主回退到 legacy
settingsScope 命名空间 settings-order,由其 settings provider 保存 order。
浏览器本地兜底(localStorage):dsh.settings-order.nav(有序 id 列表)、
dsh.settings-order.hint-seen(提示是否已收起)。
实现要点
- 按 CSS Module 后缀定位行:
[class*="_navList"]、[class*="_navCell"]、[class*="_navLabel"]。哈希前缀(VOzbGW_…)会随构建变化,后缀不会。 - 行身份 = React key:外壳用
settings.section条目 id 作为每行按钮的 key, 所以 fiber 的key就是宿主里存的那个 id;fiber 读不到时退回用行的文字标签。 - 重排 = 移动既有节点:在同一个父节点内按目标顺序
appendChild,不重建节点, React 仍持有所有权;MutationObserver在外壳重渲染列表时重新套用已保存的顺序。 - 内置顺序(供「恢复默认」)实时读
ctx.slots.entries('settings.section'), SlotCore 保证它按priority再按order排序。 - 乐观写入:本地顺序先落地并保持到宿主回显,慢往返也不会闪回。
npm test 把上述每一项(选择器、行 key、槽排序)都对着本机已安装的 DSH 钉住:
将来升级若破坏这些前提,是测试失败,而不是用户的设置面板坏掉。
验证
npm run check # 下发的 bundle 与源码一致
npm test # 静态不变量 + 已安装宿主的契约
npm run e2e:dom # 把浏览器半注入实时 GUI 做交互验证
npm run e2e # 对已安装插件验证:宿主持久、恢复默认、拖拽、刷新重放
e2e/preinstall-dom-check.mjs 在插件未安装时就能跑:把构建好的浏览器半注入正在运行的
GUI,用两种 ctx 各跑一次 apply()——一次没有 settings scope(远端/浏览器本地路径),一次对着
打桩的宿主 scope——并断言行身份、Alt+↓、原生 HTML5 拖拽、持久化、页脚 ↑/↓ 与「恢复默认」,
以及整页刷新后会重放已存顺序。e2e/settings-order-e2e.mjs 针对已安装的插件运行,开跑前
先快照宿主里的顺序、跑完恢复原样。
两个脚本用的 GUI 地址来自 DSH_E2E_URL,否则取 ~/.dsh/dsh-web.log 里最新的 token 地址;
settings/workspace 文档来自 DSH_E2E_HOME,否则用 ~/.dsh。需要 playwright-core 和可达的
dsh web。
用隔离的 home 验证
建议使用拥有独立 profile patch 的临时实例:设置会写入当前 profile 的
cordis.patch.yml。隔离 home/profile 可避免测试触碰真实配置。当前仓库的 e2e
脚本针对已安装插件与实时 GUI;没有隔离环境时,不要对用户 profile 运行。
$home2 = Join-Path (Get-Location) '.scratch-home' # 放在仓库里,已被 git 忽略
New-Item -ItemType Directory $home2 -Force | Out-Null
New-Item -ItemType Junction "$home2\profiles" "$env:USERPROFILE\.dsh\profiles" # 复用已装好的 profile
$env:DSH_HOME = $home2
dsh web --no-open --port 3099 # 会打印它自己的 token 地址
# 另开一个 shell:
$env:DSH_E2E_URL = 'http://127.0.0.1:3099/?token=…'
$env:DSH_E2E_HOME = $home2
node e2e/settings-order-e2e.mjs 3099
全新的 home 会弹首次使用的浮层(内测声明、侧栏提示),脚本会自动关掉它们——只按
「保持现状」那一类按钮,绝不点会改布局的项。shots/ 被 git 忽略(整窗截图带真实会话标题),
只有 docs/settings-order.png 这张只截对话框一侧的图会进仓库。
卸载
dsh plugin --profile web remove dsh-settings-order
# 并从 dsh.profile.bundles 里删掉 "dsh-settings-order",然后重启 dsh web
scripts/rollback.ps1 会一次做完这两步并借助守护脚本重启。
兼容性
插件目标的两套 harness 都实测过:
| Harness | 验证方式 | 结果 |
|---|---|---|
| DSH Desktop 0.2.0-rc.2 | 插件自己的 profile,GUI | 页脚正常出现,拖动顺序落盘到 ~/.dsh/profiles/desktop/cordis.patch.yml 的 settings-order.config.order |
| DSH Web 0.2.0-rc.2 | web profile 从 0.1.7-rc.1 升上来 |
插件出现在启动载荷里、客户端 bundle 正常下发,启动无 incompatible / failed to apply / register is not a function |
| DSH 0.1.7-rc.1 | 对照已安装的源码与类型核对 | 宿主侧 SettingsForms + volatile Config;浏览器侧 configForms.get(entryId) 带 set/unset 与 loading | ready | unavailable 快照 |
设置外壳标记与 slot 契约另由宿主契约测试覆盖;仓库 CI 不跑浏览器 DOM 层的 npm run e2e:dom
(需要 playwright-core 与配套 chromium)。找不到 DSH 安装时 npm test 会跳过宿主契约部分;
把 DSH_CORE_ROOT 指向 @deepseek-ai scope 目录即可校验指定构建。
关于 peer 范围:DSH 的安装审计(
dsh-app-boot的evaluatePluginCompatibility)只检查@deepseek-ai/dsh*前缀的 peer,并按includePrerelease: true比对。因此判断某个版本能否装入 时请用同一口径,不要用默认 semver 推断。
开发
node scripts/build-client.mjs # src/client-src.js → lib/client.js
node scripts/build-client.mjs --check # bundle 过期则失败
node --test # 契约 + 不变量
目录:lib/index.js(宿主半:Config schema)、src/client-src.js(浏览器半,纯脚本)、
lib/client.js(下发的 bundle)、cordis.patch.yml(bundle patch)、
e2e/、test/、scripts/、docs/。
隐私
shots/ 被刻意 git 忽略:那里是实时 GUI 的整窗截图,带真实会话标题。README 里这张是
只截设置对话框的裁剪图。