dsh-asar-framework(@local/dsh-asar-framework)
DSH 桌面版的 asar「壳桥」基座 · 包版本
0.1.12· Cordis 服务asarShell· MIT 适配:DSH Desktop0.2.2-rc.1(Electron44.7.0,Windows x64)它只做一件结构性的事:让 Host 插件在不改外壳协议、不重打包 asar 的前提下,安全地用上主进程里的 托盘、通知与窗口能力;并且把「写 asar」的权力收归一处。
为什么需要它
DSH 桌面版的主进程代码打包在 resources/app.asar 的 lib/main.js 里;Host 插件运行在
ELECTRON_RUN_AS_NODE=1 的子进程中,结构上够不到 Electron 的 Tray / Menu /
Notification。asar 是只读归档,改动任一文件的长度都会让目录头与所有 offset 失效,因此能安全
等长改写的只有托盘那一格 1,253 字节。
如果每个需要托盘/通知的插件都自己打一次补丁,必然出现三个后果:写入者互相覆盖、备份各存一份、 升级后没人说得清 asar 当前是什么状态。所以把「写 asar」收归一处:
- 唯一写入者:其他插件不碰安装目录,只通过 Cordis 服务
asarShell下单;能改 asar 的路径 只有本基座(离线安装器,或运行期的等长 region 修复)。 - 冲突降级为状态判断:谁打的补丁、是否本框架、是否外来,都成为可分类、可拒绝、可还原的状态。
- 显式且可回滚:
--dry-run看计划、--apply写入、--restore回到 stock;没有后台自动改档。
它做什么 / 不做什么
| 做 | 不做 |
|---|---|
| 等长补丁:把 1,253 B 托盘 region 替换为「委托外置桥」的实现,长度/offset/目录头不变 | 不重打包 asar、不新增注入点、不新增 require 路径 |
装/换桥:resources/app.asar.unpacked/dsh/tray-bridge.js,原子替换(升级能力可以只换桥) |
不自动更新、不后台重打;升级必须人工确认并重启 |
提供 asarShell 服务与文件通道(通知、窗口请求/结果、诊断) |
不 provide tray、不写 menu.json(托盘贡献仍归旧插件) |
| 兼容门禁:检测、隔离、用户决定、审计、运行期巡检、外来来源识别、等长修复 | 不是安全沙箱:只防协作型插件互相踩踏,不防同权限恶意改写 |
升级工具链:锚点发现 baseline(--discover)、只读 inspect-foreign |
不跨版本沿用 baseline、不从 patched asar 采集 |
它怎么工作(一图)
插件(Host 进程) ──ctx.get('asarShell')──► 基座 Host 半身
│ 追加 notify.jsonl / window-requests.jsonl
▼
<DSH_HOME>/dsh-asar-framework/(唯一耦合面)
│ 桥轮询
Electron 主进程 ──tray-bridge.js──► Tray / Menu / Notification / BrowserWindow
▲
└─ asar 里的 DesktopTray 首次调用时 require 外置桥(安装器等长改写)
主进程不认识插件,只认识「一行 JSON」;插件也不认识主进程,只认识 asarShell。中间的文件通道
就是唯一耦合面:可审计、可回放、可单独替换桥。代价是轮询延迟(250–700 ms),对通知与托盘足够。
能力速览
notification:可用。asarShell.forPlugin(owner).notification.show()→ Host 写notify.jsonl→ 主进程桥弹出原生通知 → 点击回传events.jsonl。window:v0.2 起可用(list / primary / show / focus)。请求与结果走两条 JSONL,2 s 超时、 最多 16 个在途;setTitleSuffix目前固定返回WINDOW_UNSUPPORTED。- compat gate:v0.2.2 增加每 60 s 快速巡检(size / mtime / region 哈希)、外来来源启发式
识别、
POST /compat/repair等长修复(需重启)、POST /compat/forget撤销记住的选择。 tray:保留名,asarShell.capabilities只有notification与window;lib/tray/**是已迁移的领域库,尚未接线。- 完整矩阵(入口 / 消费者 / 状态 / 关键限制)见 TECHDOC 能力矩阵。
快速开始
前置条件:Windows x64;DSH Desktop(本项目适配 0.2.2-rc.1);维护/安装脚本需要
Node.js 20+(已验证 Node.js 24)。可选:dsh CLI 用于命令行安装。
安装分两条独立链,不要混为一谈:
| 链 | 改什么 | 是否改安装目录 |
|---|---|---|
| A. Cordis bundle | profile 的依赖与 bundle 列表 | 否 |
| B. asar 补丁 + 桥 | <安装根目录>\resources\app.asar(.unpacked) 与状态目录 |
是(显式 --apply / --restore) |
只装 A 不会让通知/窗口生效:Host 服务会启动,但主进程里没有桥。B 链必须完全退出 DSH 桌面版后写入,写入后重启。
A. 安装 bundle
方式一:插件页安装(推荐,人类入口)
- 打开 DSH 插件页 →「安装插件」;
- 安装源填仓库地址
https://github.com/DX12xyz/dsh-asar-framework,或 git 简写github:DX12xyz/dsh-asar-framework; - 等待安装完成,按提示重启 DSH(Host 半身生效;client 半身刷新页面即可)。
方式二:命令行从 git 源安装
dsh plugin --profile desktop add github:DX12xyz/dsh-asar-framework
方式三:本地目录安装(改代码 / 离线可用)
git clone https://github.com/DX12xyz/dsh-asar-framework.git
dsh plugin --profile desktop add "file:<仓库目录>"
方式四:从 GitHub Releases 下载 tgz 安装
在仓库的 Releases 页下载预先打包好的 local-dsh-asar-framework-<版本>.tgz,然后:
dsh plugin --profile desktop add "file:<下载的 tgz 路径>"
(维护者发版时会把 pnpm pack / npm pack 产出的 tgz 作为 Release 附件上传。)
安装完成后重启 DSH。AI 也可用 plugin_manager 的 install_bundle 完成同一件事:
target 填上述仓库地址、本地目录或 tgz 文件即可。
B. 打 asar 补丁并安装外置桥
先设置 DSH 的安装根目录(包含 resources\app.asar 的目录),避免在命令里写死本机路径:
$env:DSH_DESKTOP_INSTALL_ROOT = "<你的 DSH 安装根目录>"
安装 bundle 后首次启动时,插件会检测 B 链是否已就绪(安装记录 + 外置桥);未就绪会弹窗提示:
- 点「扫描并检测」自动寻找 DSH 安装根目录(也可点输入框旁的「浏览…」调系统
IFileDialog(资源管理器风格,内部 UI 跟随系统语言)选文件夹;取消不会回退旧式对话框)(依次检查安装记录、环境变量、当前进程位置、常见安装名与盘符;只有找到resources\app.asar才会填入); - 检测通过后可点「一键安装」:Host 以 Electron 的 Node 模式子进程调用本仓库的
scripts/install.mjs --apply(含备份、等长补丁、装桥、写记录),完成后:- 已安装
dsh-power:显示绿点提示并给「重启 DSH / 稍后重启」,重启走 dsh-power; - 未安装
dsh-power:只显示橙点文字「你需要手动重启」,不提供退出按钮(DSH 主进程没有对外 quit IPC,强制结束不可靠且有丢回合风险);
- 已安装
- 也可以手动在仓库根目录执行:
node scripts/install.mjs --status --install-root "$env:DSH_DESKTOP_INSTALL_ROOT" # 只读:现状与安装记录
node scripts/install.mjs --dry-run --install-root "$env:DSH_DESKTOP_INSTALL_ROOT" # 只读:分类 + 写入计划
# 完全退出 DSH 桌面版(托盘 → Quit;只关窗口不算)
node scripts/install.mjs --apply --install-root "$env:DSH_DESKTOP_INSTALL_ROOT" # 写:备份 region、打补丁、装桥、写记录
# 重启 DSH,按 INSTALL.md 的验收清单检查
node scripts/install.mjs --restore --install-root "$env:DSH_DESKTOP_INSTALL_ROOT" # 回滚:写回 stock region、删桥与记录
--install-root也可由DSH_DESKTOP_INSTALL_ROOT提供;写操作仍建议显式传参;- 退出码:
0成功/无操作;2校验失败/拒绝/外来补丁;3用法错误; - 备份、验收、错误码、
--adopt、--discover与--inspect-foreign的完整 runbook 见 INSTALL.md 与 docs/UPGRADE.md。
常见问题:桌面版重启后「无法使用 / Web authentication failed」
极少数情况下,DSH 桌面版在多次快速重启后会因为 Electron 会话 cookie 失效而启动失败(日志
desktop welcome: Web authentication failed),与本插件的 asar 补丁无关。恢复步骤:
- 完全退出 DSH 桌面版(托盘 → Quit);
- 备份并删除
%APPDATA%\@deepseek-ai\dsh-desktop\Network\Cookies; - 重新启动 DSH 桌面版(会重建 cookie)。
安全边界
一句话:它提供的是「秩序保护」,不是「安全沙箱」。 它能防协作型插件互相覆盖(owner 隔离、 单写入者、状态机),不能防恶意代码——插件与本基座同权限运行,桥文件本身可以被同权限进程替换。 威胁模型见 docs/SECURITY.md。
联动与兼容性
| 对象 | 关系 | 本包行为 | 对方缺失 / 不兼容时 |
|---|---|---|---|
dsh-power |
可选联动(推荐) | 安装成功后读取 GET /api/dsh-restart/status;检测到即显示绿点并提供「重启 DSH」,通过 POST /api/dsh-restart/request {source:'ui', mode:'safe'} 交给它执行 |
只显示橙点文字「你需要手动重启」,不提供退出按钮;不自动重启、不伪造退出能力 |
| 其他 asar 注入者 | 冲突检测 | compat gate 启动全量 + 60 s 巡检;发现外来字节 → 隔离、提示来源、可等长修复自己的 region。不会自动出现在消费者登记(除非显式 registerConsumer({mode:'legacy-asar'})) |
对方占用 region → 拒绝写入;region 之外的改动只能提示,不能自动修复 |
| 其他 DSH 桌面版本 | 版本绑定 | baseline 绑定 0.2.2-rc.1(Electron 44.7.0 / win-x64);--discover 可采集新版本 |
跨版本不沿用 baseline;版本/哈希不符 → 隔离并自禁用 |
| DSH Web | 不支持 | 只安装 bundle(无 Electron 桥、无 asar 补丁) | 通知 / 窗口能力不可用;页面仅显示兼容性提示 |
卸载与回滚(两阶段,应用内完成)
- 重启前:插件设置页点红色「卸载 / 回滚…」→ 弹窗列出当前仍启用的依赖插件(
standard建议先关闭;legacy-asar仅提示)→ 有启用依赖时需勾选确认 → 开始回退:- 持久化暂停运行期巡检;
- 运行
install.mjs --restore把 asar 写回 stock、删除外置桥与安装记录; - 写
uninstall-flow.json,提示「关闭/卸载插件后重启 DSH」。
- 重启后:Host 读到
uninstall-flow.json会保持巡检关闭;页面弹窗给出:- 可删除状态目录
<DSH_HOME>\dsh-asar-framework(运行中也可删除,运行中的 Host/桥会重建部分诊断文件); - 关闭或官方卸载本插件,然后重启;
- 反悔时点「取消卸载并重新安装」清掉 flow,重新走安装引导即可。
- 可删除状态目录
依赖发现是双路:插件调用
asarShell.registerConsumer(...)(显式)或调用forPlugin()(自动登记为standard)。传统 asar 注入插件不经过服务,只能靠 compat gate 的哈希/巡检发现,不会出现在消费者列表里;它如想被列出,需显式registerConsumer({ mode: 'legacy-asar' })。反悔路径:点「取消卸载并重新安装」会清除 flow 并恢复巡检;实测运行中回退对已加载消费者无影响,删状态目录后 Host/桥会重建部分诊断文件(建议退出/禁用插件后再彻底删除)。
文档索引
| 文档 | 内容 |
|---|---|
| TECHDOC.md | 架构、进程模型、等长补丁、region 不变量、baseline v2、安装状态机、API、文件通道、插件结构、能力矩阵、测试矩阵 |
| INSTALL.md | 逐步安装、验收、回滚、错误码 |
| docs/UPGRADE.md | DSH 升级后的检测、重采 baseline、重打与验收 |
| docs/SECURITY.md | 威胁模型与边界 |
| VERIFICATION.md | 可复现证据(仓库内,不随包发布) |
| CONTRACT.md | 冻结契约(冲突时以它为准) |
| HISTVER.md | 版本历史与关键决策 |
| THIRD_PARTY_NOTICES.md | 第三方与互操作声明 |
当前状态与已知限制
状态(2026-11-08):
- 测试 474/474 通过(unit 281 / integration 69 / native 95)。
- 桥
bridge/dist/tray-bridge.js=77aeb842…(74,406 B);patchedapp.asar=1C0EF4DF…2D13。 - 真机:DSH Desktop
0.2.2-rc.1/ Electron44.7.0/ win-x64;重启后自检 14/14;运行期巡检 两次实测通过。
限制:
- 只支持 Windows x64;只有 1 个 region(1,253 B)、1 个桥文件;离线只有一个 asar 写入者。
- 外来来源识别是启发式:由差异字节附近的 ASCII 串与已安装包名推断,可能为空或认错。
- 自动修复只覆盖 region 本身;region 之外的改动仍判为
foreign-outside-region。修复不自动重启。 - 改 asar 的改动必须重启桌面版才生效;升级后需重新核对 baseline。
许可
MIT,版权归 DX12_XYZ。见 LICENSE 与 THIRD_PARTY_NOTICES.md。
No comments yet. Be the first to write one.