Releases: BOWLUNA/dsh-multi-instance
Release list
0.5.0 —— 窗格加固的静默失效,与第一次「真起窗口」的测试
0.5.0 —— 窗格加固的静默失效,与第一次「真起窗口」的测试
下载
| 文件 | 大小 | 说明 |
|---|---|---|
DSH.Multi-Instance-Setup-0.5.0.exe |
111.5 MB | 安装包(NSIS):可选安装目录、建快捷方式 |
DSH.Multi-Instance-0.5.0-x64.zip |
152.9 MB | 免安装:解压即用 |
需要 Windows 10 / 11(x64)。软件不捆绑 dsh,也不会在后台偷偷下载任何东西 ——
装完在界面里点「下载实例」,或接你已有的 DSH。
这一版修掉了一个「静默失效」
每个窗格的分区加固,从加进来那天起就没执行过。 这不是新引入的 bug,是这几版一直带着的。
main.js 里注册 will-attach-webview(负责给每个窗格的分区设 UA、装权限处理器)时,
挂在了 type === 'webview' 的内容上。但这个事件是在宿主窗口上触发的 ——
中间那句早退 if (type !== 'webview') return 恰好把唯一的宿主挡在门外,
于是处理器永远注册不上,hardenSession() 一次都没被调用过。
证据(修复前,npm run smoke 抓到的实际请求头)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
dsh-multi-instance/0.4.0 Chrome/144.0.7559.236 Electron/40.10.2 Safari/537.36
这段 UA 本该被 setUserAgent(chromeUA()) 换成一支干净的 Chrome UA,实际没有。
日志里也从来搜不到 webview 挂载 partition= 那一行。
影响:每个窗格的浏览器会话都没做过 UA 与权限加固;被嵌页面能直接从 UA 读到
Electron 与本应用的名字、版本(指纹信息),而「壳子在 DSH 眼里就是一个普通浏览器」
这个前提是落空的。
修复后同一条断言由红转绿,UA 变为 … Chrome/152.0.7977.130 Safari/537.36。
另外加了一条护栏:今后只要出现「窗格报到了却没有挂载记录」,主日志里就会有
[guard] 窗格(实例 xxx)已挂载但没走 will-attach-webview … —— 这类失效不能再沉默。
新增:npm run smoke(窗口级冒烟测试)
这一版的第二件事,是让上面这类 bug 测得到。
此前仓库里的 57 条测试全是纯逻辑(配置读写、地址解析、CLI 参数),
它们能在任何无头环境里跑,代价是窗口里的东西一条都测不到 —— 而本项目的坑恰好大多长在窗口里。
npm run smoke 补的正是这一半:脚本自己在本机起一个「假 DSH」页面,
用一套测试配置起一次真应用,断言点落在**「那个页面确实被请求了」**上 ——
这是端到端证据,不是「配置文件里写了什么」这种间接指标。
- 30 条断言(
--scene=pane|empty|tile三种场景),覆盖:
Electron 版本对齐、userData 落点隔离、渲染层 boot、窗口显示、webview 挂载与加载、
每格独立partition、端到端请求、窗格发出的 UA、截图非空白、致命错误与退出码 - 不需要网络、不需要真的 DSH、不需要任何凭据,也不碰你真实的配置(userData 指向临时目录)
- 能直接验打包产物:
node tools/smoke.js --exe="dist/win-unpacked/DSH Multi-Instance.exe"
——「源码能跑」和「发出去的那个 exe 能跑」是两件事 - CI 新增
smoke (windows)job,失败时把.tmp/smoke传成 artifact 留档
其它修复
一次操作只占一个备份槽。 主进程保存状态时会把 panes / ui / collapsed 分三笔写,
原先每笔都轮转备份 ⇒ 三个备份槽被同一次拖动内部的中间态占满,
「给你留 3 份」实际只剩「回退一次拖动」的粒度。加了 3 秒轮转冷却后,
3 份备份真的对应最近 3 次操作。
依赖与仓库
- electron
40.10.2→44.4.3(Chromium 144 → 152)。这是用npm run smoke三个场景实测过的,
不是「dependabot 说没冲突」那种证据。 actions/setup-nodev4 → v7。CONTRIBUTING/SECURITY/CODE_OF_CONDUCT三份原先只有中文的文档,顶部各加一段英文指引
(明确以中文为准,并指向英文 README)—— 此前 README 中英双语而这三份不是,英文读者只能猜。
没有仓促机翻三份长文档:说清现状比糊一份译文更诚实。
怎么自己复核(不用信上面的字)
git clone https://github.com/BOWLUNA/dsh-multi-instance.git
cd dsh-multi-instance
npm install
npm test # 57 条纯逻辑
npm run smoke # 30 条窗口级,本机起真应用想让冒烟测试打印出它到底验证了什么,加 --keep,现场留在 .tmp/smoke/
(含截图 smoke.png 与主进程完整日志)。
npm 上仍然是 0.0.1 占位包,可用版本还没发上去 —— 请用上面的 Release 产物,或从源码跑。
MIT License · 本项目是独立的第三方外壳,与 DeepSeek 官方无隶属关系。
它不改 ~/.dsh 下的任何凭证文件,也不捆绑、不自动下载 dsh。
0.4.0 —— 配置损坏不再静默丢数据
配置坏了不再静默丢数据,外加一个能自己跑的图片资产护栏。
修了一个会吃掉配置的缺陷(P1)
读不出 config.json 时,旧代码只打一行日志、按空配置继续 —— 而紧接着任何一次写入都会用这份空配置把原文件覆盖掉:没有备份、没有残片,实例列表和窗格排布就此消失。
探针实测(修复前):损坏的残片 32 字节 → 一次 set()(比如改个主题)之后,主文件变成 38 字节的新内容,目录里只有 config.json 一个文件,没有任何东西可以回退。
现在:
- 每次覆盖前,把上一位能解析的内容滚成
config.json.bak-1(旧的往后推,保留 3 份) - 读不出来时,先把手上的残片原样存成
config.json.corrupt-<时间戳>,再从最近的备份回退,并把回退结果写回主文件(自愈) - 两件事都写进
logs/main.log—— 以前它走的是console.error,打包版里根本看不见 - 备份链只收能解析的内容:一次坏盘不会把好备份一路挤掉,让「回退」退到另一个坏文件上
复验(修复后):坏盘 + 无备份 → 残片字节级保留,可手工抢救;坏盘 + 有 bak-1 → 实例列表原样回来。
npm 入口能回答最基础的两个问题
dsh-multi-instance --version # 装成了什么
dsh-multi-instance --help # 全部开关这两条不需要 Electron(参数解析排在「找运行时」之前)—— 装完包的第一个动作不该先撞上「找不到运行时」。之前它们会被当成 Electron 参数透传,什么都不打印。
护栏
tools/check-binary-assets.js+ CI 步骤:读 magic number 复验*.png/*.ico。来历是这个项目真把 README 的图当文本处理坏过(d8eb824)。已用一份 base64 文本伪装的 PNG 验证过它确实会红 —— 那正是那次事故的签名。.gitattributes:显式声明二进制资产。git 的自动检测只在新文件被 add 时生效,挡不住 patch / API 通道。
仓库
- 落地页:https://bowluna.github.io/dsh-multi-instance/(
docs/index.html,单文件、无外部依赖) - 徽章行以 Release 版本为准(npm 徽章移到末位并标注 placeholder —— 之前首页显示的是 npm 上那个
0.0.1占位包) - 关掉空置的 Wiki / Projects 标签;合并后自动删分支;electron 家族依赖每周汇总成一个 Dependabot PR
测试
npm test:36 条 → 54 条(新增 13 条覆盖配置的读写 / 备份轮转 / 损坏回退 / 残片保留,5 条覆盖 CLI 参数解析)。零依赖、纯 Node,不需要图形界面。
下载
| 文件 | 说明 |
|---|---|
DSH Multi-Instance-Setup-0.4.0.exe |
安装包 —— 可选安装目录,建桌面与开始菜单快捷方式 |
DSH Multi-Instance-0.4.0-x64.zip |
免安装压缩包 —— 解压即用,不写注册表 |
需要 Windows 10/11。软件本身不含 dsh —— 装完在界面里点「下载实例」,或者接你已有的 DSH。
⚠️ npm 上现在仍然只有0.0.1(占位空壳)。可用版本还没发上去,在那之前请用上面的产物。
想确认拿到的是不是真包:npm view dsh-multi-instance version现在会返回0.0.1。
实测记录(本轮踩到的另一件事)
打包在解包阶段就会失败,dist/ 里一个产物都没有 —— 起因是工具沙箱注入的批量删除守卫拦下了 electron-builder 解包前对 dist/win-unpacked 的删除。README 里原先那句「收尾清理报删除失败可以忽略,产物已生成」是错的,中英双侧已更正,并新增 npm run clean:dist(挂在 predist 钩子上,用同步 API 提前清目录)绕开它。
完整改动:CHANGELOG.md · 安装与排障:README
0.3.0 —— 固定用户数据落点,补上无头测试
dsh-multi-instance 0.3.0
把 DeepSeek Harness(dsh)的 Web 界面装进一个多窗格桌面客户端:
多开多个实例、每个实例一个窗格、自由排布与缩放、每格独立浏览器会话。
这个版本修掉了一个会丢用户数据的缺陷,并给仓库补上了能无头运行的测试。
下载哪个
| 文件 | 说明 |
|---|---|
DSH.Multi-Instance-Setup-0.3.0.exe |
安装包(NSIS)—— 可选安装目录,建桌面与开始菜单快捷方式 |
DSH.Multi-Instance-0.3.0-x64.zip |
免安装包 —— 解压即用,不写注册表,适合放 U 盘 |
文件名里的点是 GitHub 上传时把空格换掉的(本地产物名里是空格)。
需要 Windows 10/11。软件不含 dsh —— 装完在界面里点「下载实例」,或者接你已有的 DSH。
修了什么(重要)
用户配置会在改名后静默丢失。 Electron 的 app.getPath('userData') 默认等于 <appData>/<应用名>,
而应用名在开发态取 package.json 的 name、在打包态取 productName —— 于是开发态落在
%APPDATA%\dsh-multi-instance\,打包版落在 %APPDATA%\DSH Multi-Instance\。
这个项目改过三次名字,每改一次,旧目录里的实例列表、窗格排布和 Partitions/(持久化的登录态)
就留在原地没人认领。
实测现场:%APPDATA%\dsh-shell\config.json 里有 1 个窗格和 14MB 的 Partitions,
而当时的落点目录里只剩一个 ui 键。
这个版本把落点钉死,并在启动时做一次旧目录迁移:只在当前目录没有窗格时才动手,
取窗格最多的那一份 config.json,连带 Partitions/ 一起接过来。幂等,跑过一次之后不会再动。
如果你装过 0.2.0 或更早:升级后实例会自动接回来,日志里会有一行
[appdata] 已从 <旧目录> 迁移: config.json, Partitions(窗格 N 个)。
新增
npm test:36 条零依赖、纯 Node、不需要图形界面的用例,覆盖落点解析与迁移的全部分支
(含幂等、坏配置、不覆盖已有会话、失败不抛)、实例地址解析、npm 入口的运行时查找。
原先仓库里只有要起真窗口的--selftest*,CI / SSH / 容器里一条都跑不了 —— 上面那个缺陷就是这么漏过去的。- GitHub Actions:push 与 PR 时在 Windows + Linux 上跑测试、语法检查、以及
package.json与CHANGELOG.md的版本一致性检查。 CHANGELOG.md/SECURITY.md/CONTRIBUTING.md/ issue 表单 / PR 模板。tools/social-preview.py:生成 1280×640 的社交预览图(配色直接取style.css的纸色变量)。
文档修正
- 删掉一条实测为假的说法:「构建路径不要含中文」。electron-builder 26.15.3 在含中文的路径下能正常打包 ——
这两个产物就是在原地(路径含中文)打出来的。 - README 中英双侧补齐:目录导航、
npm test一节、落点钉死与自动迁移的说明、
「升级后实例列表空了」的排障条目、相关项目互链、CI 徽章。
校验
npm test→PASS passed=36 failed=0(exit code 0)- 产物:
exe是有效 PE(MZ+PE\0\0签名);zip79 个条目、testzip()无损坏 - 产物内
resources/app.asar的package.jsonversion =0.3.0,
且确实含src/main/appdata.js(APP_DIRNAME常量与迁移函数都在) - 真实数据上跑过迁移:从
%APPDATA%\dsh-shell\迁出config.json+Partitions(1 个窗格),
第二次运行为skip-target-ok
完整变更:CHANGELOG.md