前言¶
DeepSeek Harness(DSH)的对话界面里经常会出现文件链接:Markdown 里的文件引用、@文件 引用、路径标签等。在没有辅助插件时,打开这些文件通常只能用浏览器默认行为或复制路径后在文件管理器里手工定位。DSH 插件市场里已有几个提供右键菜单的插件,但大多只能调用已注册文件类型关联的应用。如果遇到未注册关联的程序(例如 Visual Studio),这些插件就无能为力。
本插件为 DSH 增加「文件右键 → 打开方式」能力。在对话界面右键点击文件,可使用系统默认应用打开、在文件管理器中定位、选择已注册的编辑器或终端,以及通过系统「打开方式」对话框选择未注册的应用。
插件定位¶
名称:dsh-open-any
维护者:xl0223
分类:客户端
GitHub:https://github.com/xl0223/dsh-open-any
许可证:MIT
DSH 版本要求:≥ 0.2.0-rc.1
插件通过在浏览器侧识别文件元素并右键注入菜单,再通过 Host 侧路由调用系统命令,实现跨平台的文件打开能力。
识别范围与行为¶
插件识别以下元素,通过 title 属性提取路径:
- Markdown 文件链接:
button.fileLink - 输入框 / 消息里的
@文件引用:[data-ref-chip="file"] - 路径标签:
[data-path-label] - 其它带
title的元素(兜底)
右键菜单包含以下选项:
-
用 <默认应用> 打开
使用系统默认关联程序打开文件。 -
在文件资源管理器中打开
一级菜单项,在文件管理器中定位该文件(Windows 为「文件资源管理器」,macOS 为「在访达中显示」)。 -
打开方式 ▸
列出本机为该文件类型注册过关联的编辑器 / 终端,带真实图标与「(默认)」标记。 -
其他应用…(系统对话框)
唤起 Windows 原生「打开方式」对话框,可选未注册文件关联的应用(例如 Visual Studio)。这是本插件独有的能力。 -
复制路径
复制文件的绝对路径。
路径处理:相对路径会按当前正在查看的会话的工作目录补全成绝对路径。非文件位置右键仍弹出浏览器原生菜单。
与同类插件的区别¶
DSH 插件市场里已有多个提供右键菜单的插件,本插件不追求功能最全,而是聚焦两点:
-
「其他应用…(系统对话框)」
通过rundll32 shell32.dll,OpenAs_RunDLL唤起系统选择器,可打开未注册关联的应用。只列workspacePathApplications的插件无法覆盖这类程序。 -
不拖垮启动的工程约束
Client 插件在apply阶段不抛异常、不等待服务就绪。DSH 的 web boot 机制会把非active条目视为致命错误,本插件为此采用「服务延迟到事件发生时惰性解析」的设计。
如果需要超链接右键、另存为、复制文件内容、文件树右键等能力,建议使用更全面的现有插件。
安装与启用¶
从 GitHub 安装(推荐)¶
在 DSH 的「设置 → 插件」或插件管理器的添加框里填:
github:xl0223/dsh-open-any
或使用 DSH 自带 CLI(把 <profile> 换成你的 profile 名,例如 desktop):
dsh plugin --profile <profile> add github:xl0223/dsh-open-any
安装完成后需要重启 DSH:client bundle 按文件 mtime 生成 rev 并版本化缓存,不重启不会重载。
本地源码调试¶
dsh plugin --profile <profile> add link:C:\path\to\dsh-open-any
修改 src/ 后必须重新运行 node scripts/build.mjs(DSH 加载的是 lib/);修改 lib/client.js 后刷新页面即可,修改 host 半侧需要重启。
卸载¶
dsh plugin --profile <profile> remove dsh-open-any
或从 profile 的 package.json 里删除 dsh.profile.bundles 与 dependencies 中的 dsh-open-any,然后重启。
兼容性¶
- DSH 版本:0.2.0-rc.2 上完成真机验证(菜单、应用列表、打开、文案)。
- DSH 0.2.1-rc.2:已静态确认模块基座表,未做真机重验。
- 平台:Host 侧使用
rundll32/explorer/open/xdg-open,三平台均有实现,但只在 Windows 11 上实测过。 - Node:构建需要 Node ≥ 20;运行时只用 DSH 自带能力。
开发与验证¶
构建与验证命令(在插件根目录执行):
node scripts/build.mjs # 语法 + 契约校验 → lib/
node --test scripts/verify-client.test.mjs scripts/verify-host.test.mjs # 离线单测
node tools/check-host-contract.mjs # 与真实 app.asar 的模块/路由契约
node tools/probe-open-in-app.mjs # 真机探测:本机会列出哪些应用
一条命令跑全部:npm run check。
验证报告(基于 README 提供的实测结果):
- 平台:Windows 11;DSH
D:\Ai_Agent\DeepSeek Harness(0.2.0-rc.2 真机 / 0.2.1-rc.2 静态)。 - 构建:成功生成
lib/client.js和lib/index.js。 - 离线单测:30 / 30 通过。
- 宿主契约:检查通过,所有 require 与导出名均存在。
- 真机验证:右键文件 → 菜单弹出 → 应用列表来自本机 → 选择应用后文件被打开;「其他应用…」唤起 Windows 原生选择器。
已知限制¶
- 0.2.1-rc.2 未真机重验,仅静态确认模块基座表。
- 「其他应用…」仅 Windows 实现(
OpenAs_RunDLL);macOS / Linux 会返回 501。 - 图片类 Markdown 链接(有缩略图浮层、无
title)不命中。 - 只复制绝对路径,没有相对路径 / 文件名 / 文件内容 / 另存为。
- 不处理超链接、不处理文件树(侧边栏)内的右键。
- 未做
canOpenWorkspacePath预检:文件不在工作区时,菜单仍会弹出、操作会失败并提示。
踩坑记录¶
-
client 插件的
apply绝不能抛异常,也不能等任何服务。
DSH 的 web boot 把非active条目当致命错误。静态inject会让 fiber 永远pending;apply里同步调用ctx.effect(...)+locale.register(...)抛错会让 fiberfailed,导致整个 GUI 打不开。正确姿势是:factory 先挂一个 no-opexports.apply,真实实现包在 try 里;apply只做 DOM/React,服务延迟到事件发生时惰性读取。 -
ctx.inject要一个一个注。
把多个服务一次性交给一个ctx.inject,只要有一个名字对不上就会永远不回调,整条链路静默失效。改成每个服务一条ctx.inject([name], cb)后立刻正常。 -
locale.bind(ns)(key)未命中时会原样返回 key。
必须判断返回值 !== key 再采用,否则裸 key 会显示到菜单里。 -
GUI 页面的 origin 是
dsh-app://app,不是http://127.0.0.1:<port>。
浏览器侧对相对路径的fetch不一定到 host 路由,排查时以 host 半侧写盘的证据为准。 -
Host 侧路径必须先是绝对路径。
它用path.resolve按进程 cwd 解析,相对路径要在浏览器侧按会话 cwd 补全。
适用场景与注意¶
本插件适合需要在 DSH 对话界面中快速打开文件、定位文件位置、或使用未注册关联应用的场景。插件以当前 DSH 进程的权限运行,安装前建议检查源码与许可证。
小结¶
本插件为 DSH 增加了一个实用的右键菜单能力,特别在于支持通过系统对话框打开未注册关联的应用。如果你正在使用 DSH 进行智能体开发或日常对话,并经常需要处理本地文件,这个插件可以作为工具链的一部分。
插件主页与源码:https://github.com/xl0223/dsh-open-any