dsh-open-in-app-fix
yanli-nyan/dsh-open-in-app-fix
修复vscode无法启动,从 open-in-app 包交给被启动编辑器的环境里去掉继承来的 ELECTRON_RUN_AS_NODE 变量,桌面端「用其它应用打开」不再以 HTTP 502 launch-failed 失败;不改动 app.asar。
安装
dsh plugin --profile web add github:yanli-nyan/dsh-open-in-app-fixREADME
应用内打开修复 · dsh-open-in-app-fix
![]()
| 项目 | 内容 |
|---|---|
| 界面显示名 | 应用内打开修复(locale/zh.json) |
| 包名 | @local/dsh-open-in-app-fix |
| 版本 | 1.1.0 |
| 形态 | DSH 宿主(Node 侧) 插件,无浏览器半边 |
| 是否需要皮肤 | 不需要,与皮肤、与工作区树都无关 |
是否改 app.asar | 不改 |
简体中文 · English
这是什么
修复 DSH 桌面端「用其它应用打开 / Open in …」启动编辑器失败的问题。 典型症状:点「Open in Visual Studio Code」弹「打开失败,请重试」,请求返回 HTTP 502:
{ "code": "launch-failed", "message": "failed to launch vscode" }
只影响直接启动可执行文件的项(编辑器、终端);走系统 open 动词的「在资源管理器中显示」不受影响。
为什么
桌面壳为了让打包进 app.asar 的运行时以 Node 解释器运行,是以 ELECTRON_RUN_AS_NODE=1 启动宿主进程的。
该变量留在进程环境里,而 open-in-app 启动子进程时直接展开环境清洗结果:
env: { ...scrubbedParentEnv(), ...options.env }
scrubbedParentEnv(来自 @deepseek-ai/dsh-subprocess)只过滤 /KEY|PASSWORD|SECRET|TOKEN/i 与 DSH_ 前缀,
不处理 ELECTRON_RUN_AS_NODE,于是它原样传给了编辑器。
编辑器(自身也是 Electron 二进制)带着这个变量启动时,会把自己当成 Node 解释器、把目录参数当成脚本来执行,
并在 launchWatchMs(默认 1000ms)内以非零码退出 —— 请求随即落到 502。
怎么做
插件用 Node 的模块钩子 module.registerHooks,把 open-in-app 这一个包发出的那一句
@deepseek-ai/dsh-subprocess 导入,替换成一层包装:
export * from "<subprocess 的 file URL>";
import { scrubbedParentEnv as raw } from "<subprocess 的 file URL>";
export const scrubbedParentEnv = () => {
const environment = raw();
delete environment.ELECTRON_RUN_AS_NODE; // 唯一改动
return environment;
};
要点:
export *转发原包全部导出,只覆盖同名的那一个;raw()仍是官方实现,上游的清洗规则一条都没绕过;- 只拦截
parentURL落在 open-in-app 包目录下的导入,因此宿主自己的子进程/终端启动器 (它们需要这个变量才能以 Node 模式运行)完全不受影响; options.env里显式声明的变量(例如某些 catalog 条目专门要求的ELECTRON_RUN_AS_NODE) 合并在后,仍然保留 —— 继承来的删掉,显式声明的留着。
随包的 cordis.patch.yml 先禁用官方条目:
- id: open-in-app
disabled: true
- insert:
- id: open-in-app-fix
name: '@local/dsh-open-in-app-fix'
config:
probeTimeoutMs: 10000
iconTimeoutMs: 10000
launchWatchMs: 1000
模块钩子只能影响尚未开始加载的模块,所以官方条目必须先被禁用;随后本插件自己导入官方模块,
并原样转发它的 name / inject / Config / apply,功能与官方完全一致。
注意
- 这是顺序敏感的:官方条目必须在钩子注册之前不被导入,因此
disabled: true不能删。 - 若官方包不再导入
@deepseek-ai/dsh-subprocess,包装会变成空转,502 会回归; 升级 DSH 后如果问题复现,请先核对官方包的导入点。 - 本插件从不写
app.asar,所以应用升级不会把它冲掉,卸载也不需要还原文件。
安装
DSH 桌面端 → 左侧栏「插件」→ 安装,填以下任一绝对路径:
<本仓库克隆目录>\dsh-open-in-app-fix # 目录路径,按 link: 装
<本仓库克隆目录>\build\local-dsh-open-in-app-fix-1.1.0.tgz # 打包产物(build/ 不入库)
<下载的 local-dsh-open-in-app-fix-1.1.0.tgz> # 或从 Release 下载后填其绝对路径
两种方式等价:目录装便于本地改完即时生效,tarball 装便于分发固定版本。
装完完全退出并重新启动 DSH。
若此前用过改写 app.asar 的旧方案,建议先还原归档再装本插件,避免同一条链路被修两遍。
验证
- 在工作区点「Open in Visual Studio Code」,编辑器应正常打开该目录;
- DevTools → Network 中该 POST 应返回 200
{ ok: true }而非 502; - 顺带试 Cursor、Windows Terminal、「在资源管理器中显示」交叉确认无回归。
卸载
插件页移除本插件(或删掉 patch 里的 disabled 与 insert)并重启。
官方条目恢复启用,功能回到官方原样。无需还原任何文件。
文件说明
| 文件 | 作用 |
|---|---|
index.js | 全部逻辑:锚点探测 → 注册模块钩子 → 加载并转发官方插件 |
cordis.patch.yml | 禁用官方条目 + 插入本插件(含三项超时配置) |
locale/zh.json、locale/en.json | 界面显示名与说明 |
icon.png | 插件图标(512×512 PNG) |
README.md | 本文件(中文,默认) |
README.en.md | 英文版说明 |
详细说明
本文件是"能装、能用"的简要版。为什么不能靠改 app.asar、模块钩子怎么接管官方插件、
超时与降级路径的取值依据、以及逐条验证记录,都在:
版本
| 版本 | 变更 |
|---|---|
1.1.0 | 加入中文显示名(应用内打开修复)、中文说明与 icon.png 图标;README.md 由英文改为中文;另附英文版 README.en.md |
1.0.0 | 首版:模块钩子方案 |