跳过主要内容
Y

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-fix

README

应用内打开修复 · 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 的旧方案,建议先还原归档再装本插件,避免同一条链路被修两遍。

验证

  1. 在工作区点「Open in Visual Studio Code」,编辑器应正常打开该目录;
  2. DevTools → Network 中该 POST 应返回 200 { ok: true } 而非 502;
  3. 顺带试 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首版:模块钩子方案

相关插件