open-dsh-plugins/dsh-open-in-app ↗★ 0
dsh-open-in-app
Open the current workspace folder with an installed application (Finder, Terminal, VS Code, Ghostty, Zed, ...) from the session header of the dsh web UI
AI 분석
核心用途是在 Web UI 中快速调用本地应用打开当前工作区。适合频繁需要在网页聊天与本地编辑器/终端之间切换的 DSH 用户。
설치
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:open-dsh-plugins/dsh-open-in-appdsh-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”按钮旁边。文件夹按钮一键打开工作区——使用你上次为该工作区选择的应用;下拉箭头打开选择菜单,显示最近使用的应用、系统默认文件夹处理器,以及主机上白名单内的终端和编辑器——每一项都带有应用图标:

功能
- 在会话头部工具行(聊天窗口右上角)新增一个 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)、~/Applications | `open -a "" | |
| ` | 通过 sips 将 bundle .icns → 32px PNG;无 icns 的 bundle 用 qlmanage 回退 | ||
| Windows | %ProgramFiles%、%ProgramFiles(x86)%、%LOCALAPPDATA%\Programs(顶层 *.exe) | `cmd /c start "" | |
| ` | 通过 PowerShell [System.Drawing.Icon]::ExtractAssociatedIcon 提取内嵌 exe 图标 | ||
| Linux | /usr/share/applications、/usr/local/share/applications、~/.local/share/applications(*.desktop) | `gtk-launch | |
(回退到 xdg-open`) | freedesktop 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 启动器(idea64、pycharm64 等)与 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.clientweb 模块,通过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))读取该命名空间。 - Bundle(
cordis.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,原生转换(
sips、qlmanage、PowerShell)带有可选的 abort 信号。 - 命令失败(
open退出码、应用缺失)会以菜单中的错误行呈现,而不是抛异常。
开发
lib/apps.js与lib/icons.js是纯 Node(无 dsh 导入)——可独立测试(node -e 'import("./lib/icons.js").then(m => m.listAppsWithIcons()).then(console.log)')。- 客户端 bundle 必须保持自包含:它只依赖平台种子词(
react、react/jsx-runtime、@deepseek-ai/dsh-client-ui-primitives)。 - 无需重建:没有构建步骤——
lib/原样发布。