dsh-plugin-open-in-app-fix: Fix DSH "Open In" failure to open Electron editor

前言

在 DeepSeek Harness(DSH)里做智能体或本地开发时,会话头部或 Ctrl+Shift+O 的 Open In 菜单是常用入口:把工作区目录交给 VS Code、Cursor、Windsurf 等编辑器继续改代码。若点击后前端弹出「打开失败,请重试」(path.openError / “Could not open. Try again.”),问题往往不在编辑器路径配置,而是 Desktop Host 启动子进程时继承了 ELECTRON_RUN_AS_NODE=1,Electron 类编辑器被当成 Node 进程拉起后立即退出。上游模块打包在 app.asar 里,用户侧难以直接改;社区插件 dsh-plugin-open-in-app-fix 在宿主进程内对特定 spawn 形状做补丁,下面介绍其原理、安装与自检方式。

这是什么

dsh-plugin-open-in-app-fix 由维护者 jcy0chenyuan0 发布,分类为客户端插件,仓库见 GitHub,目录页见 SkillHub。一句话定位:修好 DSH 的 Open In …,使「用 VS Code 打开」等操作不再因环境变量继承而失败;适用 VS Code、Insiders、Cursor、Windsurf 等 Electron 编辑器。DSH 生态强调「一切皆插件」;SkillHub 等社区目录为独立站点,与 DeepSeek / 幻方无官方从属关系。

症状与根因

现象

在 dsh 会话头部(或 Ctrl+Shift+O)的 Open In 菜单里选择 VS Code 等项时,前端弹出 path.openError,文案为「打开失败,请重试」或 “Could not open. Try again.”。

根因(仓库 README 已实测复现)

@deepseek-ai/dsh-host-open-in-app 的 launchDetachedApp 使用 { ...scrubbedParentEnv(), ...options.env } 启动目标程序。scrubbedParentEnv() 会清理凭据形状的名字和 DSH_*,但保留 ELECTRON_RUN_AS_NODE。

运行插件的 Desktop Host 本身是 Electron 的 Node 模式子进程(进程链:DeepSeek Harness.exe(GUI) → 带 --expose-internals … dsh-desktop-host … 的子进程 → 插件在此加载),因此环境里带有 ELECTRON_RUN_AS_NODE=1。VS Code / Cursor / Windsurf 同为 Electron 程序,收到该变量后被当作纯 Node 进程启动,在 launchWatchMs 窗口内非零退出 → runLaunch 判为 failed → 前端报错。

README 中本机对照(Code.exe <dir>,detached + stdio:ignore):

子进程环境 结果
带 ELECTRON_RUN_AS_NODE=1 约 64 ms 后 exit code=1,dsh 判失败
去掉该变量 看护窗口结束时进程仍在运行,dsh 判成功

为什么不能直接在别处修

  • 不能在进程级删除 process.env.ELECTRON_RUN_AS_NODE:dsh-subprocess-local 的 runnerEnvironment() 依赖继承该变量,让 process.execPath(Electron)以 Node 模式跑 runner.js;删掉后 shell / exec 等工具会一起失效。
  • 改不到 open-in-app 模块:其使用 child_process.spawn 的 ESM 快照绑定(猴补丁无效,Node v24 实测),且模块在 app.asar 内。
  • 内部 internals.catalog 测试接缝被打包成单文件常量,外部无法挂载。

插件怎么修

快照函数与实现唯一共享的入口是 ChildProcess.prototype.spawn(options)。本插件只补这一方法,且仅在同时满足以下条件时,从传入环境的副本中去掉 ELECTRON_RUN_AS_NODE(及 README 所述的选择变量处理):

  • detached === true
  • stdio 全为 'ignore'

app.asar 全量扫描表明,该形状在发行树中只有一处(open-in-app 的 GUI 适配器)。subprocess runner、bash 会话、ctx.subprocess 使用结构化 stdio,不受影响,仍继承变量以 Node 模式启动。

其余约定:不改调用方传入的 env 对象本身(使用过滤后的副本);不修改 process.env、不写注册表、不改 app.asar;同进程内幂等;插件 dispose 时还原原方法。

安装与启用

首次安装需在本插件目录生成 cordis.patch.yml(脚本按当前目录生成,已 .gitignore,不写死盘符):

Windows:

.\install.ps1

macOS / Linux:

node install.mjs

随后在 DSH 中安装 bundle(路径替换为本目录的绝对路径):

plugin_manager install_bundle  file:<本目录的绝对路径>

装完后可在 GUI「设置 → 插件」中整体启用或停用。新 bundle 通常在 profile 热重载后即生效;若菜单仍报错,重启 dsh 桌面端。

换机器时:克隆仓库到任意目录,重复上述 install 脚本与 plugin_manager install_bundle 即可;仓库不包含本机绝对路径。

运行环境(README):Windows / macOS / Linux 的 DSH Desktop 均适用;Node 20+(DSH 自带);无第三方依赖。

典型用法与自检

日常用法无需额外配置:安装并启用后,继续使用会话头部或 Ctrl+Shift+O 的 Open In 菜单打开目录即可。

可选一次性自检:在本插件目录创建 marker 文件 run-selftest,内容为要打开的目录路径;插件加载时会用与 dsh 相同的启动方式拉起 VS Code,结果写入 selftest.json 并删除 marker,日常启动不会弹编辑器。

Windows 示例(路径按实际插件安装位置调整):

Set-Content -Path "$env:USERPROFILE\.dsh\plugins\open-in-app-fix\run-selftest" -Value (Get-Location).Path
# 让插件重新加载(重启 dsh 或重新启用本 bundle)后:
Get-Content "$env:USERPROFILE\.dsh\plugins\open-in-app-fix\selftest.json"

probe.outcome 为 launched 表示修补生效;exited / exit code=1 表示补丁未生效,可结合 patched 与 selectorPresentInHostEnv 区分「未加载」与「启动形状未匹配」。

仓库还提供 node test/acceptance.mjs 做补丁前后对照等验收,可在开发或排查时运行。

卸载

plugin_manager remove_bundle dsh-plugin-open-in-app-fix

或在 GUI 插件页移除。移除后 Open In 对 Electron 编辑器的行为回到 dsh 原状(可能再次失败)。

适用场景与注意

适合在 DSH Desktop 中频繁用 Open In 打开 VS Code、Cursor、Windsurf 等工作流的用户。插件在 dsh-desktop-host 进程内运行,权限与当前 dsh 桌面端一致;安装前应阅读 仓库源码 与 MIT 许可证,自行评估是否满足安全与合规要求。

README 指出:真正长期修法应在 dsh 侧,launchDetachedApp 组环境时删除 ELECTRON_RUN_AS_NODE(同仓 PTC 沙箱已有类似过滤);上游修好后本插件可卸载。安装过程若遇 profile 内 pnpm-lock.yaml 目录依赖路径问题,仓库说明已改为 file:../../plugins/…,原件备份为 pnpm-lock.yaml.bak-dsh-fix。

结尾

dsh-plugin-open-in-app-fix 针对 Open In 启动 Electron 编辑器失败这一具体故障,用最小范围的 spawn 补丁去掉 GUI detached 启动时对 ELECTRON_RUN_AS_NODE 的继承,而不破坏 subprocess 工具链。需要详情与 issue 请访问 GitHub 仓库 与 SkillHub 目录页。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye