Back to home@open-dsh-plugins

dsh-open-in-app

dsh web-UI plugin: open the current session's workspace folder with an installed app (Finder, Terminal, VS Code, Ghostty, Zed, ...) — icons included

Stars
1
Language
JavaScript
Created
Aug 20, 2026
Updated
Aug 24, 2026
GitHub repo

Introduction

dsh-open-in-app

English | 中文

面向 DeepSeek Harness(dsh)Web UI 的一个插件:在聊天窗口右上角提供一个按钮,用已安装的应用打开当前会话的工作区文件夹。菜单按终端模拟器流行 IDE/编辑器白名单整理,分组为“终端应用”和“编辑器与 IDE”。

仓库:github.com/open-dsh-plugins/dsh-open-in-app

截图

open-in-app 控件位于会话头部工具行(聊天窗口右上角),“Session log”按钮旁边。文件夹按钮一键打开工作区——使用你上次为该工作区选择的应用;下拉箭头打开选择菜单,显示最近使用的应用、系统默认文件夹处理器,以及主机上白名单内的终端和编辑器——每一项都带有应用图标:

open-in-app 选择菜单:最近使用、系统默认、终端应用与编辑器与 IDE

功能

  • 在会话头部工具行(聊天窗口右上角)新增一个 Codex 风格的拆分控件,样式与**“Session log”头部按钮一致的胶囊**(32px 高、1px 边框、18px 圆角、悬停填充),两段之间用细线分隔:
    • 文件夹按钮一键打开工作区——使用你上次为该工作区选择的应用(按 cwd 记录在 localStorage 中,按钮上显示其图标),否则回退到默认编辑器(优先级最高的已安装编辑器——VS Code → Cursor → Windsurf → Zed → IntelliJ IDEA → …——然后是系统默认);
    • 下拉箭头打开菜单,包含置顶的**“最近使用”条目、一个“系统默认应用”条目(内置 host.openPath 行为;macOS 上是 Finder),以及主机上已安装的白名单终端和编辑器,每一项都带有应用图标(从应用包中以 32px 读取,以 data: URL 传递;无法解析图标的仅显示名称)。“系统默认应用”行显示默认文件夹处理器的真实图标**(macOS 是 Finder,Windows 是资源管理器,Linux 是 xdg-mime 默认文件管理器),无法解析时回退为文件夹图标。
  • 从菜单选择应用即可用该应用打开当前工作区文件夹:
平台应用发现打开命令图标
macOS/Applications/System/Applications(+ Utilities)、~/Applicationsopen -a "<app>" <path>通过 sips 将 bundle .icns → 32px PNG;无 icns 的 bundle 用 qlmanage 回退
Windows%ProgramFiles%%ProgramFiles(x86)%%LOCALAPPDATA%\Programs(顶层 *.execmd /c start "" <exe> <path>通过 PowerShell [System.Drawing.Icon]::ExtractAssociatedIcon 提取内嵌 exe 图标
Linux/usr/share/applications/usr/local/share/applications~/.local/share/applications*.desktopgtk-launch <id> <path>(回退到 xdg-openfreedesktop Icon= 值:绝对路径、hicolor 主题(128→16)、可缩放 svg、pixmaps

白名单

匹配对应用名(macOS 的 .app 基名、Windows 的 .exe 基名、Linux 的 desktop Name)不区分大小写。只有已安装且匹配的应用会出现在菜单中。

终端应用 — Terminal、iTerm2、Ghostty、Warp、Alacritty、kitty、WezTerm、Hyper、Tabby、Rio、Contour、Foot、Tilix、Terminator、Konsole、GNOME Terminal、xterm、mintty、Windows Terminal、PowerShell、Cmder、ConEmu。

编辑器与 IDE — Visual Studio Code、Cursor、Windsurf、Zed、Xcode、Android Studio、IntelliJ IDEA、PyCharm、WebStorm、GoLand、CLion、PhpStorm、RubyMine、Rider、DataGrip、DataSpell、RustRover、Fleet、Aqua、Visual Studio、Eclipse、NetBeans、Sublime Text、Nova、BBEdit、TextMate、CodeRunner、MacVim、Neovide、Emacs、Lite XL、HBuilderX。

要增删条目,编辑 lib/apps.js 中的 WHITELIST 数组——每个条目为 { id, category, match, exact? },其中 id 是规范显示名(也是原生打开命令必须能找到的名称),match 别名做子串匹配,exact 别名做全名匹配(用于诸如 code 这类会误匹配 CodeRunner 的短名称)。Windows JetBrains 启动器(idea64pycharm64 等)与 Code.exe 已通过别名覆盖。

架构

  • 宿主端lib/index.js):一个 Cordis 插件,注册一个 Typert Remote 服务 openInApp(通过 Typert Gateway 的 source-mode 回退发现——无需生成 TYPERT manifest):
    • openInApp/listApps{ apps, defaultIcon? }:白名单内已安装应用(含展示图标)以及默认文件夹处理器的图标
    • openInApp/openWith(path, appId) → 用指定应用打开文件夹
    • openInApp/openDefault(path) → 用系统默认方式打开文件夹
    • openInApp/openDefaultEditor(path) → 用默认编辑器打开文件夹(见 lib/apps.js 中的 EDITOR_PRIORITY
  • 图标lib/icons.js):为每个应用以及系统默认文件夹处理器(Finder / Explorer / xdg-mime 默认)解析一个 data:image/* 图标,按平台尽力而为(见上表),按源路径 + mtime 缓存,使重复打开菜单开销很低;失败时缓存为“无”,绝不报错。在 macOS 上,与应用同名的 icns 优先于文件类型 icns(Zed.app 中的 Zed.icns 优先于 Document.icns)。枚举的 source 路径作为不可枚举属性(lib/apps.js)携带,因此 JSON 传输永远不会看到它。
  • 客户端lib/client.js):一个 dsh.client web 模块,通过 ctx.remote.$mount(...) 挂载 Remote 端点,并注册 conversation.session.header.utilities 条目 open-in-app。挂载运行在声明了 remote 的嵌套插件 fiber 中:api-gateway 将每个命名空间注册为点分隔的 cordis 服务(remote.openInApp),一个既挂载又注入自身命名空间的 fiber 会导致加载器死锁。因此消费方通过文档化的非严格 store 访问(ctx.reflect.get("remote.openInApp", false))读取该命名空间。
  • Bundlecordis.patch.yml):一行加载器记录激活宿主端;profile 工具将其作为 profile bundle 引入。

安装

安装已发布到 npm 的包(需该包已发布到 npm registry):

dsh plugin --profile web add dsh-open-in-app

或在包含本仓库本地克隆的目录下执行:

git clone https://github.com/open-dsh-plugins/dsh-open-in-app.git
cd dsh-open-in-app
dsh plugin --profile web add .

然后重启 web 应用(dsh web)——加载器与客户端模块图在启动时组合,新增插件没有热重载。重启后,文件夹按钮会出现在会话标题旁,菜单会显示已安装的应用。

安全说明

  • Remote 端点不在特权方法列表中,因此它们与其余 /api 面处于同一浏览器信任边界之后(仅限 loopback / 已配置的可信主机)。
  • 打开路径会在宿主机上派生原生进程。文件夹路径来自会话自身的 cwd,即该 agent 正在操作的目录。
  • 图标解析仅读取枚举的应用路径(标准应用根目录)以及 freedesktop 图标主题目录;缓冲区上限为 256 KB,原生转换(sipsqlmanage、PowerShell)带有可选的 abort 信号。
  • 命令失败(open 退出码、应用缺失)会以菜单中的错误行呈现,而不是抛异常。

开发

  • lib/apps.jslib/icons.js 是纯 Node(无 dsh 导入)——可独立测试(node -e 'import("./lib/icons.js").then(m => m.listAppsWithIcons()).then(console.log)')。
  • 客户端 bundle 必须保持自包含:它只依赖平台种子词(reactreact/jsx-runtime@deepseek-ai/dsh-client-ui-primitives)。
  • 无需重建:没有构建步骤——lib/ 原样发布。