DSH Desktop Beta 通道深度解析:Electron 桌面壳、三种呈现模式与插件服务契约

  • 人工智能
  • AI 应用
  • AI Agent
  • 桌面应用
  • 插件系统
  • DeepSeek
  • dsh-plugin

【免费下载链接】deepseek-harness-desktop

为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。

项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness-desktop
点击查看 免费下载

DSH Desktop Beta(dsh-plugin-desktop-beta)是 DeepSeek Harness(DSH)插件生态的桌面端 Beta 通道实现:它把「桌面本身」编排为一个 Cordis 插件,在 Electron 中承载官方 Web 载体,同时与稳定版 npm 包、命令、应用身份完全隔离。本文以该 Beta 通道为骨架,完整讲解其架构分层、settings.yaml 模式配置、兼容/扩展/增强三种窗口呈现、desktopProfiles 与 desktopPnpm 等插件服务契约,以及从源码构建到 Windows NSIS 安装包的完整打包路径,帮助读者理解并上手这套「万物皆插件」的桌面方案。

Beta 通道与稳定版的共存关系

dsh-plugin-desktop-beta 运行 DSH Desktop 的 Beta 通道,同时保持作为普通 Cordis 组合的一部分。安装后的应用名为 DSH Desktop Beta,包内只提供 dsh-plugin-desktop-beta 可执行文件和 dsh-desktop-beta 别名命令,因此不会与稳定版 npm 包或命令冲突(注册的 npm 包名 dsh-plugin-desktop-beta 是可靠的 npx 入口,见 package.json 的 bin 与 exports 声明)。

稳定版 dsh-plugin-desktop 与本 Beta 包可以在同一台机器上同时安装。两者使用彼此独立的:

  • 应用名称与系统身份(Beta 的 appId 为 ai.deepseek.dsh.desktop.beta、productName 为 DSH Desktop Beta);
  • 快捷方式、单实例锁;
  • Electron 用户数据目录(因此 Beta 的日志、诊断归档独立于稳定版)。

但两者有意共用同一个 DSH_HOME(默认 ~/.dsh),使配置文件、设置、插件和会话记录在两条通道间共享。需要注意:同时安装受支持,同时可靠运行不受支持——两个应用可能争抢共享的 Profile 文件、端口与依赖状态。自动更新始终停留在 Beta 通道;托盘提供显式的「安装稳定版」动作,将稳定版与 Beta 并排安装。

从 package.json 可以看到 Beta 通道固定的依赖基线:@deepseek-ai/dsh@0.1.6-alpha.1 全家桶(dsh-base、dsh-web-app、dsh-settings、dsh-subprocess 等),pnpm@11.8.0,electron@43.3.0(peer 依赖),以及 dshmarket@1.38.1、dsh-community-market@0.1.0-dev.0 等生态包;仓库 patches 目录下对应的 dsh@0.1.6-alpha.1.patch 等补丁文件印证了这一固定运行时基线。

架构:最小启动器 + Host Cordis 组合

启动器与原生运行时

Electron 可执行文件只是最小化的引导代码,职责集中在四点(见 README.md 的 Architecture 一节):

  1. 获取单实例锁;
  2. 解析选中的 DSH Profile;
  3. 提供原生运行时能力;
  4. 在 Electron 主进程中启动 Host Cordis 根。

desktop-shell Host 插件通过 Cordis effects 拥有 BrowserWindow、导航策略、设置命名空间,以及「关闭即隐藏、退出才销毁」的生命周期;原生运行时拥有物理托盘,而 desktop-shell、desktop-profiles、desktop-terminal、desktop-updates 通过其有序条目注册表贡献各自作用域内的命令。

共享 Web 载体:无 preload 桥、无 Electron 专有 API

三种呈现模式全部复用现有的 Web 载体:Profile 挂载普通的 dsh-base 与 dsh-web-app 组合包。默认情况下 Host 把 HTTP/WebSocket 表面绑定到 127.0.0.1 的临时端口;经显式确认的 LAN 设置才会绑定所有网卡,而 Electron 仍然在沙箱化渲染进程中加载同源回环页面。渲染进程里不存在 Electron 自有的插件名册、preload 桥或原始 Electron API——这一边界是理解整个架构的关键。

从 desktop-settings-contract.ts 可以看到,桌面与渲染进程的交互全部收敛为私有同源 HTTP 端点(/api/desktop/settings、/api/desktop/profiles/select、/api/desktop/restart、/api/desktop/developer/devtools 等),且错误响应明确「绝不包含原生路径或原始原因」(DesktopSettingsErrorResponse)。

桌面包的三种面孔

桌面包同时具有 Host 与 Web Client 两面:

  • Client 面在每种模式下校验 Host 下发的模式、平台与按能力门控的材质标记;
  • Compatibility 模式把未改动的官方呈现放在独立 Desktop 帧之下;
  • Extended 模式用自己的根布局与侧栏表面替换官方根布局,同时继续承载官方侧栏、会话与详情 occupant;
  • Enhanced 模式保留独立的根注册与原有的紧凑内嵌标题几何。

第三方 Web Client 在任何模式下都沿用普通 DSH 模块图。

Profile 选择、检查点恢复与解析钩子

  • 托盘 Profile 选择器列出既有 Profile 以及按需提供的 desktop、web 默认值。可选 Profile 直接按 dsh-base → dsh-web-app 顺序组合;无头、损坏或已内嵌桌面的 Profile 保持可见但禁用。
  • desktop 是唯一由启动器管理的 Profile:其安装归属前缀会被修复,第三方 bundle 顺序保持不变;其他 Profile 的 manifest、用户补丁与依赖均不被改动。启动器只在**当前代(generation)**的 dsh-web-app 之后插入自己的桌面层,且绝不把该层持久化进选中的 bundle 列表。
  • Profile 选择是 Electron 用户数据下的桌面自有状态,而非所选 Profile 内部的字段。一次被接受的切换会持久化确切的活跃 Profile,并通过一次有序重启生效。启动失败时不会悄悄替换为「最后已知可用」Profile,也不会自动改写配置。
  • 每次健康启动都会把活跃 Profile 的声明式包与补丁文件、共享 Harness-home 的 settings.yaml 和 cordis.patch.yml 写入三个轮换检查点之一;恢复页要求用户精确选择某个槽位;凭据、.env、会话、存储、缓存与生成的依赖状态永不进入检查点。
  • 裸 Cordis 插件导入从持久化 Profile 解析:一个窄化的 Node resolve 钩子只作用于 @deepseek-ai/cordis-plugin-loader 发起的导入,使 Profile 本地第三方包与「已修复的启动器回退」在打包 Electron 不暴露 Node 内部 ESM loader 时走同一条解析路径。

登录 shell PATH 恢复与私有 pnpm 环境

打包的 macOS/Linux 启动会在 Profile 准备与 Cordis 启动之前,以交互式登录模式运行配置的账户 shell 并恢复其导出的 PATH——修复 Finder、LaunchServices 等图形启动器常见的极简 PATH。恢复只从固定允许列表补齐缺失的 locale、工具链、包管理器与虚拟环境导出;PATH 一律采用 shell 值;仅支持绝对路径的 zsh、bash、fish。捕获起点是 @deepseek-ai/dsh-subprocess 的 scrubbedParentEnv(),捕获名还要通过 SENSITIVE_ENV_PATTERN 与 DSH_ENV_PREFIX 检查,因此凭据、DSH_* 值、代理与 SSH-agent 设置、仅从 shell rc 文件学到的启动钩子不会被导入 Electron。

随后启动器把仅含固定捆绑 pnpm 命令的私有命令目录前置到 Electron 主进程 PATH,使 Host 与第三方插件(包括通过普通 DSH 子进程提供方)无需系统 Node.js 即可发现该包管理器。实现细节见 desktop-runtime-environment.ts:生成的 pnpm/node shim 通过 ELECTRON_RUN_AS_NODE 复用 Electron 可执行文件,Windows 端额外处理控制台代码页(chcp 65001)以避免 OEM 代码页下非 ASCII 路径解码错误;生成目录采用内容寻址(sha256 + UUID)并保持不可变,旧目录只从 PATH 摘除而保留(因为可能仍有子进程在引用)。

模式设置与重启边界

DSH_HOME 下 settings.yaml 文档中的 dsh-desktop 字段是唯一事实来源(Profile manifest 中不存在并行的模式值):

dsh-desktop:
  mode: compatibility # compatibility, extended, or advanced
  macosMaterial: transparent # off or transparent
  windowsMaterial: acrylic # off, acrylic, or mica when supported
  • 启动器在组合代之前读取的正是活跃 @deepseek-ai/dsh-settings-file 行解析的同一份文件;Host 通过标准设置服务注册 dsh-desktop 命名空间。
  • 用户可从托盘切换模式,也可手工编辑 settings.yaml。托盘更新已注册的 dsh-desktop 命名空间;手工编辑则改动设置提供方观察到的同一文件。
  • 一次已提交的变更请求一次有序重启:当前 Cordis 树先 dispose,Electron 仅在零代码关闭成功后才重新拉起。应用绝不会在存活渲染代中热替换根槽位、原生窗口材质或 Loader 行。
  • Linux 只支持 compatibility 模式:其托盘模式命令被禁用,自定义窗口值会被拒绝而非静默回退。

需要指出:配置值 advanced 对应 README 中单独成节的 Enhanced mode 呈现(desktopWindow.mode 的类型即 'compatibility' | 'extended' | 'advanced',见 plugin-services.md)。

三种呈现模式详解

Compatibility 模式(默认)

dsh-desktop.mode 默认为 compatibility。macOS/Windows 上它在官方 Web 表面之上创建独立的 36 CSS-pixel Desktop 帧(常量 DESKTOP_FRAME_HEIGHT = 36,见 window-chrome.ts),包含原生红绿灯或标题按钮;居中身份标识、模式药丸、拖拽区与图标动作只属于该帧,完整官方页面从帧下方开始且不参与其布局与安全区计算。Linux 保持普通原生帧回退。

桌面 Client 模块只校验模式与平台标记、注册独立帧覆盖层与固定启动器动作,不替换官方呈现:它不提供或替换 layout 服务、不注册 root/sidebar occupant、不改变会话表面,因此普通 desktop 与 web Profile 的官方行保持原样;上游对话框仍为内容覆盖层,并被约束在 Desktop 帧之下。

该模式还有一些值得注意的实现细节:

  • Loader 行在 Profile 激活期间注册原生窗口值;启动器在 app-boot 落定并审计完整 Profile 后才创建窗口,因此首个渲染 manifest 就包含活跃官方、桌面与第三方 Client 插件,插件内部无需 Loader 级等待。
  • Windows 上启动器固定浏览目录选择后端并保留应用内目录面板,给面板打上一个同源系统文件夹图标补丁,路由调用 Electron 的 dialog.showOpenDialog;普通浏览器与远程启动不会获得该桌面桥。
  • 此 alpha 运行时迁移不带桌面自有的 Workspace 文件夹拖放行为与聊天附件拖拽隔离补丁,相关交互在对照 alpha Client UI 重新评估前请使用普通 Workspace 选择流程。

Windows PowerShell 在每种呈现模式下都保留上游 pwsh-sandbox 行为与 Windows ACL 限制。启动器代仅把该 Host 提供方替换为本包内的 dsh-plugin-desktop-beta/windows-pwsh-sandbox 子路径:适配器通过私有 trampoline 以 Node 模式启动打包的 Electron 可执行文件来精确复刻上游 ACL-runner argv,在校验上游 runner 后移除 Node 模式变量,并确保受限 PowerShell 进程继承隐藏控制台而非在受限令牌下自行创建。控制台分配失败走既有签名 runner 失败路径;ACL 策略与后续失败处理全部委托上游 runner。部署根还保留了组合 STARTF_USESHOWWINDOW 与 STARTF_USESTDHANDLES/SW_HIDE 的 Yarn 补丁,不使用与上游不兼容的 CREATE_NO_WINDOW/CREATE_NEW_CONSOLE;直接 danger-full-access PowerShell、macOS 与 Linux 执行不受影响,Windows 限制失败时没有自动的无限制回退。

Extended 模式

Extended 模式禁用官方上游 ui-layout 根,安装桌面自有根布局,由其拥有侧栏、会话、详情、覆盖层与调整大小几何,同时继续渲染官方侧栏、会话与详情槽位 occupant。固定 36 CSS-pixel 命令栏位于该桌面根之上;命令栏与桌面侧栏表面揭示一层非层叠材质,形成连续倒 L 形玻璃面;会话表面位于 L 内,带 10-pixel 圆角内角,分隔线沿曲线走(EXTENDED_INNER_CORNER_RADIUS = 10)。

  • 居中产品标题与模式药丸独立于动作组;第一方动作使用紧凑图标,macOS 置于右侧(红绿灯对侧),Windows 置于左侧(原生标题按钮对侧)。它们打开 DSH 终端、普通/恢复模式重启菜单、开发者菜单(重载渲染器、切换分离式 DevTools)。这些精确动作跨私有同源启动器边界,页面不暴露任何原始 Electron 或任意命令接口。
  • 命令栏在上游覆盖层打开时仍可见、可拖拽;macOS 红绿灯与 Windows 标题按钮保留原生命中区域;桌面第一方图标显式退出拖拽并保持可点击。Web Client 插件不能在 compatibility/extended 模式下贡献命令栏动作。
  • DOM 层面命令栏声明为 Desktop 帧、位移后的上游根为其内容视口;shell.overlay 层成为固定插件表面的包含块,直接 portal 到 body 的对话框获得相同内容偏移,因此两条路径都被约束在 36-pixel 帧下方。
  • 自定义窗口材质独立于模式:macOS 提供 Off/Transparent;Windows 提供 Off/原生 Acrylic;Mica 仅出现在 Windows 11 build 22621 或更新,Windows 10 使用原生 Acrylic 而非 CSS 模仿;持久化的不支持 Mica 偏好会被能力门控降级为 Acrylic。切换模式或材质执行一次有序重启。

Enhanced(advanced)模式

Enhanced 模式是 macOS/Windows 的显式组合桌面呈现。读取完所有用户补丁后,启动器禁用官方 ui-layout Loader 行、保持 ui-sidebar 与 ui-conversation 行启用,并把所选模式应用到 desktop-shell。

  • 桌面 Client 在所有呈现模式下提供不可变的 desktopWindow 原生几何服务(见下文契约)。Enhanced 模式有自己的 Cordis effects、layout 服务与 root 槽注册,不安装独立的 compat/extended 帧;其根为未改动的上游侧栏、会话、详情与覆盖层贡献声明座位。官方侧栏仍是 sidebar occupant,继续声明工作区浏览器、设置外壳与附加页脚动作座位——保留其组件行为、折叠动画与第三方扩展点,桌面包只拥有紧凑内嵌标题几何与原生材质。
  • 增强主题 presenter 把活跃上游主题快照投射到文档(配色方案、解析后的 token 值、暗色模式标记、theme-color 元数据),订阅普通主题变更,代销毁时仅移除自身投射状态。
  • Enhanced 代中 Electron 适配器在 Host 启动后读取 ui-theme.preference,把内置 light/dark/system 值镜像到 Electron 原生外观后再建窗;已提交的偏好变更在窗口激活时更新原生材质,销毁时恢复此前外观。仅 Client 的第三方主题 id 不会改变该 Host 偏好。
  • 桌面侧栏表面把上游侧栏填充 token 限定为透明,使官方侧栏与会话列表淡出并透出原生材质,而组件样式不被改动。
  • 几何细节(常量均可从 window-chrome.ts 验证):macOS 红绿灯位于 x=16, y=16(ADVANCED_MACOS_TRAFFIC_LIGHT_TOP = 16)、紧凑 20 CSS-pixel 内容内边距(ADVANCED_MACOS_CONTENT_INSET = 20)、32 CSS-pixel 原生拖拽区(ADVANCED_MACOS_DRAG_REGION_HEIGHT = 32);90 CSS-pixel 折叠列在紧凑内边距之下居中官方 56-pixel 轨道;可选原生 sidebar vibrancy。Windows 官方侧栏保持兼容几何:折叠 56、展开默认 280、沿用上游过渡;增强窗口保留 32 CSS-pixel 内嵌标题行与原生覆盖控制(ADVANCED_WINDOWS_TITLEBAR_HEIGHT = 32),独立于 36-pixel compat/extended 帧。Linux 拒绝 enhanced 模式而非静默回退到与持久化设置不同的呈现。

开发与验证

Beta 包由仓库根部的 Yarn workspace 管理;同级 deepseek-harness/ checkout 是独立的上游 pnpm 工程,不属于该 Yarn workspace。在仓库根目录安装并验证:

yarn install
yarn check

yarn check 会验证生产图中每个必需的第一方 peer 都由桌面部署根声明;无头 Loader 冒烟激活启动器自有的桌面行与 Profile 本地第三方行,然后启动已发布的 Web Profile 并检查其回环根与 Client manifest;单元与类型测试覆盖两种 Profile 组合、重启围栏、Client 环境校验、桌面布局状态与平台原生窗口选项。更细的验证命令(对应 package.json 的 scripts)还包括:

yarn workspace dsh-plugin-desktop-beta typecheck
yarn workspace dsh-plugin-desktop-beta test
yarn workspace dsh-plugin-desktop-beta build

图形会话可用时显式启动应用(dev 会先构建,无需单独手工构建):

yarn dev

无头安全的启动器表面可以不导入、不启动 Electron 直接演练:

node lib/bin.js --help
node lib/bin.js --version

插件工作流:dsh plugin 命令与桌面服务契约

用普通 DSH 命令管理任意 Profile

dsh plugin --profile desktop add third-party-plugin
dsh plugin --profile desktop remove third-party-plugin
dsh plugin --profile desktop update

应用默认以 desktop Profile 启动;从托盘 Profile 子菜单选择其他 Web 能力 Profile 会重启应用。生成的 DSH 终端把裸命令默认绑定到当前活跃 Profile,因此以下短形式直接修改该 Profile:

dsh plugin add third-party-plugin
dsh plugin remove third-party-plugin
dsh plugin update

显式 --profile <name> 依然具有最高优先级,适合在选中某 Profile 前先准备好它。

关于 dshmarket:dshmarket@1.2.3 未被预装、也不是 DSH Desktop 的依赖,它通过私有子进程代码解析 Profile 并启动 dsh plugin,既不读取 desktopProfiles 也不用 desktopPnpm;而且该版本源码与 npm tarball 缺少完整 MIT 许可证文本与版权声明,无法通过捆绑再分发门禁。用户自行安装第三方包与桌面将其嵌入应用归档/安装器是两回事(Beta 包当前依赖 dshmarket@1.38.1)。

桌面公开服务:desktopProfiles / desktopPnpm / desktopWindow

插件作者应以 plugin-services.md 中的受支持契约为准,用类型导入从对应契约路径引入:

import type {
  DesktopCurrentProfile,
  DesktopProfiles,
} from 'dsh-plugin-desktop-beta/profile-service'
import type {
  DesktopPnpm,
  DesktopPnpmHandle,
  DesktopPnpmOutcome,
} from 'dsh-plugin-desktop-beta/pnpm'

Host 服务 desktopProfiles:代作用域、不可变 current(含 name 与绝对 dir)、只读 list()、以及 select(name)——后者是「先持久化、后重启」的切换,不原地改动存活代。实现见 profile-service.ts:prepareSelection 串行化切换,持久化成功即成为 committed 目标,不同并发目标在重启前被拒绝;持久化失败释放选择槽,重启失败保留已提交目标以便重试不覆盖状态;服务销毁后经由保留引用调用会抛错,下一代应重新读取 current 而非全局缓存旧服务。

Host 服务 desktopPnpm:提供 run(argv, signal?)(以活跃 Profile 目录为 cwd 直接执行打包的 pnpm JavaScript 入口)、runPlugin(...) 与 runExternalMarketPluginInstall(...) 两个窄兼容适配器(走打包的 dsh plugin --profile <active>)。实现见 pnpm.ts:每次操作进程内仅在最终包管理器边界追加恰好一个 --config.minimumReleaseAge=0(withDesktopPnpmPolicy),绝不改写用户 pnpm 配置;子进程环境显式注入 NODE、ELECTRON_RUN_AS_NODE=1、DSH_HOME、CI=true、npm_config_runtime=electron、npm_config_target、npm_config_disturl 等 Electron 背书值;run() 返回实时 stdout/stderr 流、done promise(在整棵进程树退出后落定)与 cancel();每代同时最多一个操作,忙时同步抛错。桌面刻意不给该接口添加重试、快照或回滚——所有恢复交给三个健康启动检查点。

Client 服务 desktopWindow:浏览器侧不可变几何事实,见 window-service.ts 与契约文档。类型为:

interface DesktopWindowService {
  readonly mode: 'compatibility' | 'extended' | 'advanced'
  readonly platform: 'darwin' | 'win32' | 'linux'
  readonly material: 'off' | 'transparent' | 'mica'
  readonly micaSupported: boolean
  readonly availableMaterials: readonly ('off' | 'transparent' | 'mica')[]
  readonly safeAreaInsets: { readonly top: number; readonly right: number; readonly bottom: number; readonly left: number }
  readonly dragRegion: { readonly height: number; readonly leftInset: number; readonly rightInset: number }
}
  • 所有值在一个渲染代内固定不变,单位为 CSS 像素;material 是能力门控后的生效值而非持久化偏好;availableMaterials 在 macOS 为 off/transparent、Windows 10 为 off、Windows 11 build 22621+ 为 off/mica。
  • compat/extended 模式在 macOS/Windows 上报告相同 36-pixel 顶部预留与拖拽带,macOS 左侧排除 80 像素(MACOS_TRAFFIC_LIGHT_SAFE_WIDTH = 80)、Windows 右侧排除 138 像素(WINDOWS_CAPTION_CONTROLS_WIDTH = 138);advanced 模式为独立紧凑几何(macOS 20 像素内容内边距 + 32 像素拖拽带 + 左侧 80 排除;Windows 32 像素内容内边距与拖拽带 + 右侧 138 排除)。Linux compatibility 保持普通原生帧,报告零内边距与零高度拖拽区。
  • safeAreaInsets 描述桌面从何处开始完整上游内容表面,dragRegion 单独描述原生标题命中区,两者高度不必相等;拖拽带内的交互元素必须应用 -webkit-app-region: no-drag(桌面已对标准按钮、链接、输入、菜单、选项卡、开关与对话框施加该排除)。该服务只报告几何,不暴露窗口变更、焦点、Electron 或 IPC 能力,且普通浏览器启动中不存在。

注入模式示例

桌面专用插件(必需注入):把两个服务都声明为必需依赖,Cordis 会等待提供方就绪,服务消失时卸载 effects:

import type { Context } from '@deepseek-ai/cordis'
import type {} from 'dsh-plugin-desktop-beta/profile-service'
import type { DesktopPnpmHandle } from 'dsh-plugin-desktop-beta/pnpm'

export const name = 'example-desktop-plugin-manager'
export const inject = ['desktopProfiles', 'desktopPnpm']

declare function registerInstallAction(
  callback: (target: string) => Promise<void>,
): () => void
export function apply(ctx: Context): void {
  ctx.logger.info(`active Desktop profile: ${ctx.desktopProfiles.current.name}`)
  ctx.effect(() => {
    let active: DesktopPnpmHandle | undefined
    const disposeAction = registerInstallAction(async (target) => {
      const signal = AbortSignal.timeout(5 * 60_000)
      const operation = ctx.desktopPnpm.run(['add', '--save-exact', `${target}@1.0.0`], signal)
      active = operation
      operation.stdout.setEncoding('utf8')
      operation.stderr.setEncoding('utf8')
      operation.stdout.on('data', chunk => ctx.logger.info(String(chunk).trimEnd()))
      operation.stderr.on('data', chunk => ctx.logger.warn(String(chunk).trimEnd()))
      try {
        const outcome = await operation.done
        if (outcome.exitCode !== 0) {
          throw new Error(`plugin install failed: exit=${String(outcome.exitCode)} signal=${String(outcome.signal)}`)
        }
      } finally {
        if (active === operation) active = undefined
      }
    })
    return async () => {
      disposeAction()
      const operation = active
      operation?.cancel()
      await operation?.done.catch(() => {})
    }
  }, 'example: package-manager user action')
}

生产环境请在调用包管理器前按插件信任策略校验 target;退出码为 0 并不替代领域特定的安装后校验。

跨环境插件(可选桌面适配 + 普通 DSH 回退):desktopProfiles 在 Loader 条目挂载前注册,其存在即是桌面环境判别符;不要把桌面服务放进顶层必需 inject,用嵌套 ctx.inject() 等待 desktopPnpm:

export const inject = ['webServer', 'loader']
export function apply(ctx: Context, config: { profile?: string }): void {
  const profiles = ctx.get('desktopProfiles')
  if (profiles === undefined) {
    const profile = config.profile ?? 'web'
    ctx.effect(() => mountManager(ctx, ordinaryDshAdapter(profile)), 'example: ordinary DSH plugin manager')
    return
  }
  ctx.inject(['desktopPnpm'], (desktopCtx) => {
    desktopCtx.effect(() => mountManager(desktopCtx, {
      profile: profiles.current.name,
      profileDir: profiles.current.dir,
      runPnpm: (argv, signal) => desktopCtx.desktopPnpm.run(argv, signal),
    }), 'example: Desktop plugin manager')
  })
}

规则:desktopProfiles 存在时绝不回退到猜测的 web Profile;也不用 ctx.baseUrl、设置、Loader 清单或启动器内部 cmdlineArgs 代替 desktopProfiles.current。类型导入在编译后会被擦除,跨环境包可把 dsh-plugin-desktop-beta 留作 devDependency 或可选 peer,无需运行时导入。

失败与销毁清单(作者必读)

  1. 只在显式用户/管理员动作下启动包变更;
  2. 把 desktopProfiles.current 当一次性快照,不要在重启后保留服务引用;
  3. 优先用 run(argv, signal?) 传显式 pnpm argv,只有兼容性需要 bundle 对账时才用插件适配器;
  4. pnpm 完成后由调用方对账 Profile bundles 并校验领域状态;
  5. 为用户可见截止时间提供 AbortSignal,并保留 handle 以显式取消;
  6. 排空 stdout/stderr,但限制状态端点使用的内存历史;
  7. await done,分别处理 reject、非零 exitCode 与终止性 signal;
  8. 呈现代级 busy 错误,不并发启动 Profile 变更;
  9. 从所属 Cordis effect 的 disposer 取消活跃工作并等待完成;
  10. 把 desktopProfiles.select() 视为重启边界,不要假设旧代中的目标已生效。

支持面边界:desktopProfiles/desktopPnpm/desktopWindow 是唯一受支持的第三方能力(分别经 profile-service、pnpm、client 契约模块导出);desktopRuntime、desktopPnpmBootstrap、DesktopProfileServiceBootstrap 均为桌面内部/启动器私有能力,第三方插件不得注入或依赖。仓库自带的双文件测试夹具 tests/fixtures/desktop-host-services-smoke-plugin 声明 inject = ['desktopProfiles', 'desktopPnpm'],只探针不执行,可通过 yarn workspace dsh-plugin-desktop-beta build + yarn workspace dsh-plugin-desktop-beta verify:profile 运行。

命令行启动

包安装两个等价的 Beta 专属命令:dsh-desktop-beta 与 dsh-plugin-desktop-beta。无参数调用时两者都启动打包的 Electron 启动器(lib/main.js)。

  • 全局安装 —— npm install -g dsh-plugin-desktop-beta 自动安装 electron peer,之后直接 dsh-desktop-beta 即针对共享默认 DSH home 启动。
  • Profile 内安装 —— dsh plugin --profile <name> add dsh-plugin-desktop-beta 后命令位于该 Profile 的 node_modules/.bin;pnpm 不会自动安装 electron peer,需要手动 dsh plugin --profile <name> add electron。原生构建审批(node-pty、koffi、electron 等)遵循 pnpm 常规 allowBuilds 规则。
  • Electron 缺失 —— 命令打印一段简短安装指南,而不是抛模块错误。

用普通 dsh 调用(无启动器 desktopRuntime 服务)启动一个组合了桌面 shell 的 Profile 时,会打印提示要求改用 dsh-desktop-beta 或打包应用启动,此时 shell 不注册任何东西。

第三方 Host 插件只需普通的 dsh.bundle 补丁;带浏览器 UI 的插件发布普通 dsh.client 元数据(platform: "web")与导出的 ./client 构件即可,上游 Web Client 模块图在每种模式下都能发现它——Electron 不需要独立 Client 构建或桌面专属注册 API。Enhanced 模式下的贡献必须针对该显式组合中存在的服务与槽位,而不是假设官方 layout 或 sidebar occupant 拥有它们。

桌面操作

原生通知

桌面窗口失焦时,直接用户轮次到达 completed 触发原生完成通知;error 与 max-tokens 结尾触发需注意通知;完成/失败的后台任务走同一原生注意力路径;中止、阻塞、打断、被杀、插件发起、仅续写、不匹配与子代理活动保持静默。点击通知显示并聚焦窗口;macOS/Linux 递增应用徽标、Windows 闪烁任务栏按钮。实时 dsh-desktop-notifications 设置命名空间提供四个独立开关(notifyOnTurnCompletion、notifyOnTurnFailure、notifyOnJobCompletion、notifyOnJobFailure),全部默认启用。通知文本刻意保持通用,绝不包含提示词、响应、错误、任务标签、命令、路径、会话 ID、模型/提供方名称、工具数据或输出。

Beta 更新检查与安装

打包的 macOS/Windows 应用在启动 60 秒后查询 https://www.dshdesktop.cn/api/desktop/version,每次完成检查后每 6 小时再查一次。每次无缓存请求有 15 秒截止,随安装版本发送 X-DSH-Desktop-Channel: beta,并与托盘 Check for Updates… 共享同一在途操作。Beta 只接受响应中显式标记 channel: "beta" 的规范 -beta.N SemVer,绝不静默消费 Stable。后台失败与非更新版本保持静默;手动检查总是打开原生结果对话框。Install Stable Edition 单独查询 stable 通道,允许更低目标版本,并把稳定版与 Beta 并排安装。开发、未打包与 Linux 启动不下载安装器。

选择 Download 先复核广告版本未变,再打开原生保存对话框(默认 Downloads 目录,可改绝对路径与文件名;取消则不发起下载)。下载跟随服务重定向、最多流式写入 1 GiB、记录安装器位置供升级交接,并在暴露前拒绝不完整的 DMG 或 Windows PE。macOS 打开 DMG 并提示用户替换 Applications 中的应用后重开;Windows 在 NSIS 安装器就绪后再询问,Restart and Install 启动安装器并在当前进程退出前请求有序 Cordis 拆除;升级后的应用启动后询问删除或保留已记录安装器。发布操作者必须先把两个平台产物发布齐备,且版本/下载服务要为 X-DSH-Desktop-Channel: beta 选择 Beta、在下载响应中回显 beta 与请求的 X-DSH-Desktop-Target-Version,缺失/不可用/不匹配/非法值均不产生桌面提示。

DSH 终端与重启

macOS/Windows 上 Open DSH Terminal 打开以活跃 Profile 为根的系统终端;设置头部把重启菜单(Restart Desktop、Restart in Recovery Mode)放在该动作旁,每次重启路径都先确认再有序关闭 Cordis 并重启 Electron。终端欢迎文本标识应用版本、活跃 Profile、Profile 目录与 DSH home,随后列出配置与插件管理命令。终端内裸 dsh、dsh --dump-config 与无 Profile 选择的插件子命令默认指向活跃 Profile;显式 --profile 与上游 web 别名保持原义。桌面在用户数据目录下生成每 Profile 私有的 dsh、pnpm、node shim,设置 DSH_HOME、以活跃 Profile 为工作目录、只把 shim 目录前置到该终端的 PATH——因此之后切换 Profile 不会改变已打开终端里的命令,也不编辑全局环境或 shell 启动文件。Windows 依序选择 PowerShell 7、Windows PowerShell 或 Command Prompt,并在新 Windows Terminal 窗口打开;wt.exe 不可用时由私有 cmd start broker 创建可见控制台;同步启动失败与 broker 非零退出走桌面对话框。Linux 不组合终端命令。

对话框、恢复与安全

桌面确认/警告/错误/结果统一使用 shadcn 支撑的 DesktopDialogWindow:每个对话框都是独立沙箱化模态 BrowserWindow(有活跃桌面窗口时以其为父窗口),不是官方 Web 页内的组件或 portal;父级纯动作对话框无标题控件故不渲染空帧;独立对话框带原生红绿灯/标题按钮时使用共享的空 36-pixel 工具帧;Escape 或可用窗口关闭映射到有界取消动作,只有一次性本地结果到达主进程。文件打开/保存选择器保持原生(选择系统路径而非呈现桌面操作)。

恢复模式同样使用带空 36-pixel 帧的独立桌面窗口,其 shadcn 页面先解释恢复原因,再分 Plugin management、Rollback、Switch Profile、Diagnostics 四个页签;恢复变更与每次重启请求都打开 DesktopDialogWindow 确认,而不在恢复页内放模态框。

日志与诊断

  • 健康启动后,主进程看门狗每 5 秒检查可见应用内容;连续两次空页观察或未应答探针触发有界自动恢复(即使渲染器未退出)。无响应渲染器被终止并重载进新进程;可见恢复还要求视口内有实质内容,仅插件激活不足。隐藏/最小化窗口、导航与恢复阶段暂停检查;每探针 10 秒截止,丢弃陈旧导航结果与长挂起延迟;探针检查 DOM 可见性而非截图像素,不诊断纯 GPU 显示故障。
  • 健康启动后的意外接口进程退出(含 OOM)静默重载现有窗口,不重启 Host、不弹提示、不显示隐藏窗口。恢复需同时满足页面加载与 Client Loader 健康报告;无响应恢复尝试 30 秒超时;最多 3 次自动尝试(无初始延迟,随后 1 秒、3 秒),恢复后的 Client 保持健康 1 分钟才重置重试预算。反复失败暂停自动恢复并打开系统原生回退提示:Try recovery again 授权另一个有界周期,Not now 让后台服务继续运行;可从托盘 Open DSH Desktop 回到提示,或 Export Diagnostics… 排查。重载可能短暂打断显示并丢失未发送输入;该恢复不修复底层崩溃或内存增长;启动失败沿用既有恢复流程,有意的渲染器终止与应用关闭不触发自动恢复。
  • Beta 日志为 UTF-8,位于独立 Electron 用户数据目录:Windows %APPDATA%\DSH Desktop Beta\logs,macOS ~/Library/Application Support/DSH Desktop Beta/logs。完整日志 dsh-YYYY-MM-DD.log,警告与错误另写 dsh-YYYY-MM-DD.error.log;10 MiB 轮转、启动时删除 7 天前文件、目录上限 200 MiB;dsh-desktop.logLevel 控制详细度,默认 info。
  • macOS/Windows 托盘 Export Diagnostics… 在相邻 diagnostics 目录生成 ZIP 并在文件管理器中展示。导出在主线程外运行,收集近期自有日志与本地 Crashpad .dmp(共享 50 MiB 证据上限),含 crash-evidence/active-run.json 标记(若存在)、system-info.txt,并保留最近 3 个 ZIP。创建前确认对话框说明隐私边界;已识别的凭据会被打码,但日志仍可能包含本地路径、工作区 ID、会话 ID、提示词、工具输出或第三方插件消息,崩溃转储可能含进程内存片段——分享前请先审阅。

原生生命周期

关闭窗口只是隐藏它,Host Cordis 树继续运行。托盘可重开窗口、选择活跃 Profile、打开隔离 DSH 终端、检查稳定版、经标准设置命名空间改模式或请求显式退出。Profile 与模式变更都会在 Electron 重启前先 dispose 当前 Cordis 树;原生退出、SIGINT、SIGTERM 同样先请求销毁,5 秒截止或重复请求强制最终退出。导航与重定向停留在精确回环源上;外部 HTTP、HTTPS 与 mail 链接交给操作系统打开,渲染器使用 contextIsolation、Chromium 沙箱且无 Node 集成。

打包

Stable 与 Beta 在 Windows/macOS/Linux 上均禁用 ASAR;打包 Electron 冒烟通过本地文件系统后端验证捆绑的 Cordis skills。

  • yarn package:dir 生成当前宿主平台的未打包目录。打包运行时门禁拒绝缺少桌面更新/终端模块、DSH CLI bootstrap、捆绑 pnpm 入口或物理部署包的目录。Electron Builder 把根 manifest、桌面运行时与完整依赖树放进 resources/app/(macOS 为 Contents/Resources/app/);Host Profile 启动与 CLI bootstrap 都使用这棵物理树,使 Profile 回退符号链接永不指向虚拟 ASAR 目录。
  • 图标:build/app-icon.png 保持为未经修改的 iOS Default 源图与 Windows/Linux 应用图标;构建运行 scripts/generate-mac-app-icon.mjs 把该图在透明 1024×1024 画布上居中到 824×824;macOS 打包与 Dock 都使用生成的 build/app-icon-mac.png。build/tray-icon.svg 是品牌蓝托盘源:构建派生 macOS 模板图(系统自动着色)与固定品牌蓝 Windows/Linux 托盘图。yarn dist:mac(正式签名发行,产物写 dsh-plugin-desktop-beta/dist/mac-release/)等命令的定义见 package.json。

WSL Linux 无头检查

WSL2 适合在 Windows 工作站上做 Linux 无头构建、类型检查与单元测试。WSL 内请使用 Linux 版 Node.js,而不是 WSL 经由挂载的 Windows PATH 继承到的 Windows Node.js/Corepack shim;用 nvm 时每个 shell 先 source ~/.nvm/nvm.sh 再跑 Corepack 命令:

source ~/.nvm/nvm.sh
git submodule update --init --recursive
corepack yarn install --immutable
corepack yarn workspace dsh-plugin-desktop-beta typecheck
corepack yarn workspace dsh-plugin-desktop-beta test
corepack yarn build

从 /mnt/<drive> 运行命令有效但比放在 WSL 原生 ext4 文件系统慢。WSL 不能替代真实 Linux 桌面会话用于托盘、窗口管理器、.desktop 集成或已安装包冒烟测试。

本地 Windows x64 安装包

使用带 Git 与 x64 Node 22.23.2(与 CI 相同)的原生 Windows x64 机器;打包命令接受 Node 22.19+ 与 24.x(其官方发行包含 Corepack)。在全新 v2 checkout 的 PowerShell 中执行:

git submodule update --init --recursive
corepack.cmd yarn install --immutable
corepack.cmd yarn dist:win

无需 Python 与 Visual Studio C++ Build Tools:Windows 命令使用 node-pty 捆绑的 x64 Node-API 二进制而非让 Electron Builder 从源码重建,打包运行时门禁拒绝缺少这些二进制的安装器暂存树。dist:win 拒绝非 Windows 非 x64 宿主,运行 Windows 安全门禁(构建、全部 TypeScript 编译器面、打包与原生 shell 聚焦测试、运行时闭包验证器),再构建 assisted NSIS 安装器并验证两个生成 PE 文件;完整跨平台套件归 CI 所有(部分 POSIX 执行测试不是 Windows 程序)。安装器支持每用户或提升的全用户安装、更改安装目录、创建开始菜单与桌面快捷方式,卸载时保留 DSH 用户数据。README 文档示例版本产物为 dsh-plugin-desktop-beta\dist\DSH-Desktop-Beta-2.0.5-beta.2-x64-Setup.exe,未打包应用在 dsh-plugin-desktop-beta\dist\win-unpacked\DSH Desktop Beta.exe(实际产物版本号以当前 package.json 的 version 为准)。本地命令刻意剥离 Windows 证书变量并设 signExecutable=false:产物可安装但无 Authenticode 发布者,Windows 可能显示 Unknown publisher 或 SmartScreen 警告;签名发行、证书验证、安装器升级/卸载测试与原生 UI/沙箱冒烟是独立发布门禁。

Windows x64 便携 ZIP

原生 Windows x64 机器上执行 corepack.cmd yarn dist:win-portable,产物为 dsh-plugin-desktop-beta\dist\DSH-Desktop-Beta-<version>-x64-Portable.zip(README 示例版本为 2.0.5-beta.2)。解压到任意可写目录即可运行 DSH Desktop Beta.exe,无需安装器、管理员权限、开始菜单注册或卸载步骤;应用仍在 Beta Windows 用户数据目录保留 Profile、日志与缓存,因此是便携分发而非自包含数据沙箱。便携归档不交给 NSIS 更新器,新版本发布时必须手动替换;本地构建未签名,可能触发 Unknown publisher/SmartScreen 警告。

macOS DMG 冒烟

yarn dist:mac-smoke 在原生 macOS 宿主构建一枚未签名 universal DMG,Intel 与 Apple Silicon 均可原生运行。命令拒绝非 macOS 宿主并先跑完整产品门禁(仓库布局与社区契约检查、Market 构建与检查、Desktop 构建、全部 TypeScript 编译器面、完整单元测试套件、运行时闭包验证、CLI/Loader/Profile 无头冒烟与许可证审计,含 macOS runner 上各受支持 shell 的真实登录 shell 测试),随后无签名材料打包、挂载 DMG 并验证属性列表、可执行位、x86_64 与 arm64 双切片及 Contents/Resources/app/ 运行时条目。它镜像 dist:win 的机密纪律:剥离全部 Electron Builder 签名与公证变量、设 CSC_IDENTITY_AUTO_DISCOVERY=false、禁用公证、绝不发布。产物无 Developer ID 签名,Gatekeeper 会在其他机器上拦截——它存在的意义是让打包回归在 CI 里先失败;签名并公证的 universal 发行仍是凭据 macOS 机器上的 yarn dist:mac。

模型体验

无。 桌面包只改变应用组合与原生呈现,不添加模型可见的指令、工具、事件或请求字段;KV Cache 效应同样为无——模型请求仍由同一个 DSH Host 与 Client 特性插件组装。

已知限制与延期工作

  • 增删 Profile bundle 需要重启 DSH Desktop(启动器不监视 Profile manifest);托盘选择其他 Profile 会自动完成该重启。
  • 切换 compatibility/extended/advanced 模式或改材质总是重启应用:存活代从不热替换 Loader 行、槽位归属或原生材质。
  • Linux 无 extended/enhanced 模式,继续使用 compatibility 呈现。
  • macOS/Windows 托盘终端暴露私有 dsh/pnpm/node shim;Host 运行时另外把捆绑 pnpm 暴露在当前 Electron 进程 PATH 上做环境兼容,并提供受管的 desktopPnpm 服务;这些命令都不进系统 PATH,Linux 目前无桌面终端命令。
  • Windows 上环境 pnpm 与生命周期 Node helper 是 .cmd shim。desktopPnpm.run() 通过启动精确打包 pnpm 入口避免 shell 查找,而上游 dsh plugin、PowerShell 与 Command Prompt 可经命令解释器解析环境 shim。第三方插件若用 spawn('pnpm', { shell: false })、或生命周期脚本直接以 shell: false 执行其 .cmd npm_node_execpath,仍不可移植——应改用服务或 shell 感知的启动路径。
  • dshmarket@1.2.3 仍是可选用户安装包而非捆绑市场;预装被推迟到经审计的发行版消费可选桌面服务、保留普通 DSH 回退并包含再分发所需完整许可证声明之后。
  • 更新交接只校验下载容器、不校验发布者身份:macOS 仍需用户从打开的 DMG 替换应用;Windows 运行下载的 NSIS 安装器但本地 dist:win 产物未签名。签名产物、Authenticode/发布者验证、SmartScreen 信誉与原生升级测试仍是发布门禁。
  • 共享载体是 HTTP/WebSocket 而非 Electron IPC:默认回环、支持显式确认的全网卡 LAN 绑定;替换载体需要上游 DSH 的传输扩展点,超出本独立包范围。
  • Beta 厂商化官方 DSH 0.1.6-alpha.1 运行时(由固定发行源码构建);桌面构建消费这些打包接口而不链接源码 checkout。上游把历史会话迁移到 V3(含遗留 PTC 事件与 code 预设引用)并保留原日志;桌面不再创建预设别名;V3 会话无法被旧运行时读取。extended/enhanced 模式承载带文档预览、分栏与全屏的右侧 Sidebar,并经键控 main 槽独立于 Session 选择支持全局插件面板。
  • package:dir 是未打包冒烟产物;dist:win 增加未签名 NSIS 测试安装器但不建立 Authenticode 身份或 SmartScreen 信誉。安装与升级行为、原生通知与终端、Windows ACL 沙箱与原生材质外观仍是目标平台验证边界。

结语

dsh-plugin-desktop-beta 展示了一条「桌面即插件」的实现路径:Electron 只做最小启动器,原生能力以 Cordis 服务与私有同源端点暴露,呈现层在兼容/扩展/增强三种模式间由 settings.yaml 一处配置驱动,插件作者仅需遵循 desktopProfiles、desktopPnpm、desktopWindow 三个公开契约即可融入。Beta 与稳定版共用 DSH_HOME 却彼此隔离身份与更新通道,适合在真实工作流中先行验证新特性。深入阅读可从 plugin-services.md 开始,再对照 pnpm.ts、profile-service.ts、window-service.ts 与 window-chrome.ts 理解底层实现。

  • 人工智能
  • AI 应用
  • AI Agent
  • 桌面应用
  • 插件系统
  • DeepSeek
  • dsh-plugin

【免费下载链接】deepseek-harness-desktop

为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。

项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness-desktop
点击查看 免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值