English | 中文
桌面应用是完整 dsh Web 应用外的一层 Electron 壳。Electron RunAsNode 子进程启动共享 profile runner,Electron 立即从 dsh-app://app/ 加载打包内的 Web 入口。共享加载页等待 Host 启动注入,然后在同一文档中启动客户端。Electron 将应用 HTTP 请求转发给已认证的 Web Host;WebSocket 流连接到该 Host,仅为归属的应用窗口附加凭据。Node IPC 承载启动注入、就绪与关闭。Desktop 默认使用端口 19387,与 Web 的 3080 分开;可通过 webserver.config.port patch 覆盖。
设计师原稿位于 resources/icon.png 和 resources/icon.svg;平台适配保留鲸鱼与渐变,分别位于 resources/icon-windows.* 和 resources/icon-macos.*。将各平台 SVG 导出为透明的 1024×1024 PNG。electron-builder 为 Windows 应用、安装程序和卸载程序生成多尺寸 ICO(Windows 图标要求)。安装页面在两种主题下使用匹配的图案;卸载程序的欢迎和完成页共用 installer/assets/uninstaller-sidebar.png,准备阶段将其转换为 164×314 BMP。
macOS PNG 使用带留白的圆角底板,供传统 ICNS 打包使用,包含最高 1024 像素的表示。它是扁平图标,并非 Icon Composer 文档。Apple 的应用图标指南要求向 Icon Composer 提供未遮罩的图层;这些输入需要在 macOS 上单独导出,不能复用已做圆角的 ICNS 图案。发布前须在支持的 macOS 版本中验收 Finder 和 Dock 的显示效果。
当前 Windows Python 产物包含未签名的原生扩展。本机验证中,Smart App Control 阻止了 _decimal、pyexpat、_lzma 和 _uuid;该主机上的 XML 和 LZMA 操作失败。numpy/pandas 冒烟检查通过,不代表所有扩展都兼容。
Desktop 携带独立的 Python、Node.js 和 pnpm 分发包,并在 Python 的 site-packages 中预装 numpy 和 pandas。load_workspace_dependencies 工具首次使用时,将该产物离线安装到 $DSH_HOME/dsh-runtimes/dsh-primary-runtime(通常为 ~/.dsh/dsh-runtimes/dsh-primary-runtime),并返回解释器、pnpm 脚本和库目录的绝对路径。pnpm 脚本通过返回的 Node 可执行文件运行。返回的 Node 库目录为随包交付的库预留,不是 pnpm 的全局安装目录。
该产物随 Desktop 版本发布。runtime.json 记录 Desktop 版本、目标平台和组件版本;匹配的安装会被复用,版本不同时在完整暂存副本完成后替换目录。添加到该目录的 Python 包在同一版本内保留,升级时随应用基线一起替换。目录替换失败时保留之前的安装;解释器仍在运行时,Windows 可能拒绝替换。
该工具不修改 PATH、环境变量或用户包管理器配置。pnpm 的全局包、命令入口和 store 保留自身默认值及用户设置,包括环境不支持全局安装时的原生错误。不提供独立依赖更新器。第一方 Runtime 决策记录这些选择。
Node 准备内置解释器和 Python 库,无需系统 Python 或 pip。下载锁固定解释器压缩包及目标平台 wheel 的 URL 和哈希;pnpm 使用 Desktop 构建依赖锁。支持的库 wheel 直接解压到 site-packages;需要其他安装目录的 wheel 会被拒绝,不生成包的命令行包装器。本机目标检查在清理暂存目录后以及 macOS 签名后执行内置解释器及 numpy/pandas 运算。独立 Node 可执行文件获得 V8 所需的 JIT 权限。跨目标执行和签名安装需要对应的发布主机。dev:desktop 和 start:desktop 都会在启动 Electron 前准备 .desktop-build/targets/<target>/runtime/primary-runtime;首次准备可能需要下载锁定的依赖。
| 决策 | 原因 | 直接结果 |
|---|---|---|
| 发布身份 | 桌面壳 API、Web 客户端、后端与插件依赖图作为一个组合完成验证;独立版本会产生未经验证的组合,并让更新可用性含糊不清。 | Electron 与 @deepseek-ai/dsh 始终使用同一精确版本。即使桌面壳代码不变,升级 dsh 也必须发布新 Desktop 版本。 |
| 运行时 | 应用必须能够在没有系统 Node.js 或 pnpm 的机器上运行。 | dsh 通过设置 ELECTRON_RUN_AS_NODE=1 和 --expose-internals 的 Electron 运行,所有包操作都使用内置 pnpm。包管理器配置和 Host 环境遵循用户设置。包脚本通过 node shell 启动器转发给 Electron。 |
| 包来源 | 即使离线,启动时安装核心依赖也会增加开销。 | app.asar/dsh 携带完整生产依赖树;profile 只安装外部插件。 |
| 共享模块 | Host API 可能依赖模块身份。 | 共享 profile runner 在 Desktop profile 内补全安装包与 bundle 缺失的依赖;pnpm 管理的包优先。 |
| 状态归属 | 共享可执行依赖图会让 CLI(命令行界面)与 Desktop 相互改变 dsh、Cordis、插件或原生模块版本,而两个桌面进程还可能争用同一个 profile。 | Electron 在访问任何 profile 前获取进程生命周期单实例锁,并独占 $DSH_HOME/profiles/desktop 及其包管理器状态。CLI 与 Desktop 共享 $DSH_HOME 下受支持的产品数据,但绝不共享可执行包、插件激活、锁文件或 node_modules。 |
| 传输 | 复用 Web 服务与认证,让应用行为由同一份实现负责。 | Electron 直接加载 Host 的认证 HTTP URL;子进程 IPC 承载生命周期消息,本地壳协议提供启动和管理页面。 |
| 插件变更 | 包安装和 Host 启动可能失败。 | Desktop 停止 Host 后直接修改当前 profile。失败保留部分修改供用户修复,不自动回滚 profile。 |
| 更新 | 桌面壳与 dsh 独立更新会重新产生版本分裂,而桌面壳未变化的数据块不应强制完整传输。 | Electron 壳、匹配的 dsh 运行时与 pnpm 组成一个已签名更新单元。平台更新产物可以复用未变化的数据块,但运行时版本选择绝不脱离 Desktop 发布。 |
薄壳决策负责共享 Web 行为与 Desktop 适配。Electron 打包与更新决策负责发布身份、签名及更新验收。
Electron 拥有 $DSH_HOME/profiles/desktop。其 dependencies 包含 pnpm 安装的包;dsh.profile.bundles 包含内置 bundle,后接已启用插件。签名应用从 resources/app.asar/dsh 提供 dsh、私有 Desktop Host 及其生产依赖。打包应用选择 runtime profile 解析,不创建包链接;开发 profile 使用文件系统链接。宿主与插件在同一个 Electron Node 模式进程中执行;Desktop 不启用 --preserve-symlinks。CLI 不能启动或修改此 profile。
本地启动页面展示启动状态及可用恢复操作。产品渲染进程使用 Web 应用的 HTTP API。独立插件窗口接收结构化的列表、安装、移除、更新和检查更新操作;两个渲染进程都不会获得文件系统、原始 Electron IPC、shell 或任意 pnpm 参数访问权。
产品 UI 保留 Web 操作,包括通过共享认证 HTTP 路由执行的“打开方式…”。Desktop 使用 Web 的自动目录选择机制,并以共享 Web 模板的 bundle 列表和 patch 重载策略初始化新 profile。
Electron 根据应用 locale 选择类型化的英文或中文桌面壳文案,并以英文作为 fallback。菜单、原生对话框、启动页与插件管理渲染进程使用同一 locale 数据;仓库的 Client UI i18n gate 会检查这些桌面源文件。
Electron 原生“编辑”菜单为当前聚焦窗口提供撤销、重做、剪切、复制、粘贴和全选命令及平台快捷键。右键点击可编辑输入区域会打开不带快捷键标注的这些命令,其可用状态由 Chromium 提供;选中的只读文本提供“复制”命令。
签名资源中的 resources/app.asar/dsh/desktop-runtime.json 绑定 shell 版本、Electron 的 Node 版本、平台、架构、共享包版本和最终文件清单。启动读取元数据,并检查共享包记录。发布 schema、shell 版本、目标兼容性和文件完整性在打包时验证。首次启动不会把核心包复制到 profile 存储或通过 pnpm 安装核心包。
dsh.bundle.patch 的包作为 bundle 启用;普通依赖安装后不自动启用。Desktop 不扫描插件依赖图,也不在 Host 启动前验证 patch 文件。自定义 profile 元数据和 bundle 顺序会保留。已安装元数据不可读时,仍能列出、禁用和删除依赖;无法读取已安装版本时,列表使用依赖规格。CLI 与 Desktop 共用已安装依赖清单及 bundle 列表协调逻辑。bundle 声明遵循与启动一致的安装目录优先解析顺序。CLI 操作自动启用已安装 bundle;Desktop 更新后保留通过 UI 禁用的 bundle 状态。两条路径都不要求已安装元数据可读才能列出或移除依赖。
加载页不依赖 Host。错误页提供重启和重装指导。运行时资源支持 profile 恢复时,即可禁用插件和重置 Desktop,包括开发模式;早期初始化失败只提供重启。应用菜单仍提供插件管理器入口。插件修改不自动回滚。
Host 错误诊断仅保留 stderr 输出的最后 64 Ki 个字符。更早的输出会被丢弃,避免长期运行的 Host 使壳的诊断缓冲区无限增长。
重置删除 $DSH_HOME/profiles/desktop 中除所持事务锁外的所有条目,然后初始化内置 profile。它删除 Desktop 配置和已安装第三方包,不保留备份。共享任务、设置和 Harness-home .env 保持不变。壳资源和 preload 失败时使用独立文档显示可用恢复操作和诊断;其控件不依赖 preload。
包事务独占 $DSH_HOME/profiles/desktop/lock 直到 pnpm 进程退出。pnpm 运行前,共享模块补全 helper 仅移除其拥有的链接,并保留 pnpm 管理的目录;Host 在启动时重新创建所需链接。重置保留 profile 目录与锁,直到初始化和 Host 启动结束。链接清理保留目标目录。原生构建遵循 pnpm 配置的构建策略;发布准备负责独立的构建时许可列表。
dev:desktop 会构建当前 Host、客户端 bundle、Web 前端和 Electron 壳,把已构建的 CLI 包、私有 Desktop Host 包及其 workspace 依赖投影为一次性桌面 npm 项目,然后直接启动 Electron;这条路径不从 npm 解析 dsh:
pnpm run dev:desktop
开发 Harness 状态默认写入 apps/desktop/.desktop-build/development/home,一次性 npm 项目位于 apps/desktop/.desktop-build/development/project,Electron 浏览器数据则位于 apps/desktop/.desktop-build/development/electron-user-data。因此,会话、设置、凭据、包链接和浏览器数据都不会进入用户正常使用的 Harness home;显式 DSH_HOME 只会替换开发 Harness home。Renderer DevTools 默认自动打开,Main、Renderer 和 dsh Host 调试端口依次为 9229、9222 和 9230。DSH_DESKTOP_MAIN_INSPECT_PORT、DSH_DESKTOP_RENDERER_DEBUG_PORT 与 DSH_DESKTOP_HOST_INSPECT_PORT 可以替换这些端口,DSH_DESKTOP_OPEN_DEVTOOLS=0 则保持 Renderer 调试窗口关闭。
显式构建完成后,start:desktop 会重新生成一次性项目,并跳过构建直接启动已有产物:
pnpm run start:desktop
Workspace 开发使用 Electron RunAsNode 运行当前 CLI 与私有 Desktop Host 包,插件管理和恢复使用 $DSH_HOME/profiles/desktop,与一次性工作区运行时分离。开发与打包 profile 都使用正常的 bundle 解析,包括链接包。需要验证 Electron RunAsNode、内置 pnpm、内置 dsh 资源、插件安装和修复时,应运行未封装安装器的应用目录。
打包、上传以及手动 macOS 签名检查使用 apps/desktop/.env.windows 或 .env.macos,由目标平台选择。复制对应的 Windows 模板 或 macOS 模板,填写本机配置;Git 忽略这两个本地文件,安装产物也不包含它们。发布字段只从目标文件读取,不回退到系统或 shell 中的同名变量;PATH、代理和构建工具环境仍保留。文件使用 UTF-8,支持 BOM;相对证书、SignTool、Apple API Key 和钥匙串路径以 apps/desktop 为基准,变量值不做 shell 展开,包含 # 或空格的密码需要引号。CI 同样在运行前生成目标文件。
每条打包命令在构建与下载前检查应用 ID、更新地址和该模式需要的签名配置。macOS 检查身份、Team ID、一套完整公证凭据以及引用的 API Key 和钥匙串文件;Windows 检查公开代码签名证书、SignTool 文件、容器名称和 PIN 格式。仅准备 Windows 资源或显式未签名打包不要求签名凭据。配置检查不验证 PIN 是否正确、Token 是否登录、钥匙串是否解锁或 Apple 是否接受凭据;实际签名与公证负责这些检查。单独运行相同检查:
pnpm --dir apps/desktop run check:package
无需提前执行 prepare:desktop:
pnpm run package:desktop
发布自动化使用固定目标命令,确保运行时准备、dsh 准备与 electron-builder 接收相同的平台和架构:
pnpm run package:desktop:mac:arm64
pnpm run package:desktop:mac:x64
pnpm run package:desktop:win:x64
macOS arm64 命令要求 Apple Silicon。macOS x64 命令可以在 Intel macOS 或带 Rosetta 的 Apple Silicon 上运行。Windows x64 命令要求 Windows x64。Linux 不是受支持的 Desktop 发布目标。
每个目标都在 apps/desktop/.desktop-build/targets/<target>/ 下持有自己的打包输入、已准备运行时、包集合、dsh 依赖树、pnpm 准备状态、未打包应用、更新元数据和最终产物。Electron 归档缓存继续由 .desktop-build/downloads 共享,因为每个归档文件名都包含版本、平台和架构,并且在解包前经过验证。目标构建绝不读取其他目标的可变准备状态。
生产包首先经过 npm 发布规则和依赖安装。桌面文件规则随后在签名和完整性封存之前过滤不可变的 resources/app.asar/dsh/node_modules 副本。它排除 TypeScript 声明、明确属于 JavaScript/CSS/TypeScript 的 source map、TypeScript 构建缓存、Domino 测试目录、指定的原生编译产物,以及其他平台的 node-pty 预构建文件。它保留运行时 JavaScript、原生模块及其 DLL/EXE 辅助程序、WASM、未知资源、许可证和声明。规则不会修改 npm tarball、内置包管理器或用户安装的插件文件。
打包应用运行编译后的 JavaScript 和预生成的 Typert 元数据,不编译 TypeScript 插件。源码级调试导航和编辑器声明仍可从开发包中获取。复制规则测试覆盖排除项和保留资源;prepare:dsh 在 Host smoke 和最终清单验证之前,使用 Electron RunAsNode 执行产物 smoke。
Windows 发布验收还需在 Desktop 构建后手动运行原生清理和替换检查。将 $Electron 设为已准备的 Electron 可执行文件,将 $Makensis、$SevenZip 和 $PluginDir 分别设为锁定版本构建器的 NSIS 编译器、7-Zip 可执行文件和 x86-unicode NSIS 插件目录。从仓库根目录运行以下命令。它验证 Electron junction 清理、目录替换与回滚和两种文件占用替换方式;不属于单元测试通道。
pwsh -NoProfile -File apps/desktop/scripts/smoke-windows.ps1 -Electron $Electron -Makensis $Makensis -SevenZip $SevenZip -PluginDir $PluginDir
Windows 安装器先将新版本解压到安装目录旁边,再退出旧应用并通过同卷目录改名完成替换。同路径升级在替换成功前保留旧目录;解压失败时旧版不变,替换失败时尝试恢复旧目录。安装器在启动前清理旧版备份。强制结束安装器或断电可能留下 .new-* 或 .old-* 目录;不同安装位置或安装范围迁移仍使用 electron-builder 的旧卸载器流程。
DSH_DESKTOP_AUTO_UPDATE_ENV 同时选择打包时写入的更新 URL 与后续 COS 上传目标,可取 test 或 production;未设置时使用 test。测试打包必须通过 DOWNLOAD_TEST_ORIGIN 提供 HTTPS origin,生产 origin 仍为 https://download.deepseek.com。上传还必须通过 DOWNLOAD_TEST_COS_BUCKET 或 DOWNLOAD_PROD_COS_BUCKET 提供所选环境的 COS bucket。目标路径为 _/harness/desktop/stable/<target>/,其中 target 为 mac-arm64、mac-x64 或 win-x64。
更新目标与上传凭据都与所选环境对应:
| 环境 | 公开 origin | COS bucket | COS 凭据 |
|---|---|---|---|
test 或未设置 |
DOWNLOAD_TEST_ORIGIN |
DOWNLOAD_TEST_COS_BUCKET |
DOWNLOAD_TEST_COS_SECRET_ID、DOWNLOAD_TEST_COS_SECRET_KEY |
production |
https://download.deepseek.com |
DOWNLOAD_PROD_COS_BUCKET |
DOWNLOAD_PROD_COS_SECRET_ID、DOWNLOAD_PROD_COS_SECRET_KEY |
在目标 .env 中配置更新地址与所选 COS bucket、SecretId、SecretKey,再打包并上传同一个目标:
pnpm run package:desktop:mac:arm64
pnpm run upload:mac:arm64
生产发布需在打包前在目标 .env 中设置 DSH_DESKTOP_AUTO_UPDATE_ENV=production,再在执行 upload:mac:arm64、upload:mac:x64 或 upload:win:x64 前提供 DOWNLOAD_PROD_COS_BUCKET 与生产凭据对。打包不要求 COS bucket 或凭据。它会明确禁止 electron-builder 发布,从其子进程中删除全部四个 COS 凭据字段,并且只有在 electron-builder 以及全部签名或公证钩子成功后才写入目标完成记录。上传会先要求该记录与所选环境、目标、公开 URL 和当前 dsh 版本一致,再要求根 dsh 版本、Desktop 版本、频道元数据版本、产物名称、大小与 SHA-512 全部一致,之后才读取所选 COS 凭据对。它只上传该目标不可变且带版本的产物,最后以 no-cache 上传根据版本得出的频道元数据,并且不会删除历史对象。稳定版本使用 latest-mac.yml 或 latest.yml;alpha 等预发布版本则使用 alpha-mac.yml 或 alpha.yml,与 electron-builder 生成的文件名一致。
macOS 配置使用必填发布环境,不会接受钥匙串中最先发现的证书。空值、格式错误的 Team ID、包含 electron-builder 不支持的 Developer ID Application: 前缀的签名身份,以及不完整的公证凭据都会被拒绝。macOS 打包要求已配置的身份及其私钥可用。运行时准备会把该身份、安全时间戳与 hardened runtime 应用到每个内嵌 Mach-O 文件;应用签名完成后,深度严格检查会拒绝其他叶证书 Authority 或 Team ID,验证通过才生成发布产物。macOS 固定目标安装包命令为已签名应用创建独立副本,并发执行两条产物流。一路先公证 App 并钉票,再生成 ZIP 及其更新元数据。另一路把已签名 App 副本封装进签名 DMG,再公证 DMG、钉票并验证;其中的 App 不单独附加票据。只有两路均成功结束,产物才会移入最终目录并写入发布完成记录。仅生成目录的命令同样需要公证凭据,并等待 Apple 公证和 App 钉票完成。并行公证决策负责副本隔离与容器票据语义。私钥可以来自登录钥匙串或 electron-builder 的标准 CSC_LINK 输入;环境中的 CSC_NAME 与证书发现顺序都不能选择发布所有者。公证凭据也可以使用 electron-builder 支持的完整 Apple ID 或钥匙串 profile 方式。手动执行 pnpm --dir apps/desktop run verify:mac-signature -- <path-to-app> 重复应用检查时,也必须提供两个 macOS 身份变量。
macOS 签名遍历真实文件,不跟随 Framework 的软链接别名。PAK 资源保留全部随附语言,由外层 Framework 或应用签名记录完整性,不逐个签名。发布策略负责依赖补丁和验证要求。
可通过公司代理加速向 Apple 公证服务上传。代理配置参见公司内部文档。
在 Windows x64 上,使用完整的未签名打包命令进行本地安装测试:
pnpm run package:desktop:win:x64:unsigned
该命令要求设置 DSH_DESKTOP_APP_ID 并具备常规构建依赖,包括编译原生模块所需的 Python 和 Visual C++ 构建工具。Python 不在 PATH 中时,将 PYTHON 设置为其可执行文件路径。命令将安装包写入 .desktop-build/targets/win-x64/unsigned-artifacts/,省略自动更新配置,清除签名凭据,且不生成发布完成记录。它不需要 EV 凭据或更新源地址。签名打包和上传命令仍遵循正式发布要求。
Windows 安装程序使用原生 NSIS 页面,提供亮暗配色、系统阴影、可编辑的安装目录,以及默认勾选立即启动的完成页。安装仅面向当前用户。点击安装或按 Enter 均校验当前路径;新安装位置必须为空,非空位置必须是已登记的安装目录。受影响安装路径中的程序运行时显示系统提示,并保持应用运行;其他目录中的同名应用不阻止安装。静默更新最多等待受影响应用退出十秒,若仍在运行则以退出码 2 结束。
主题在启动时跟随 Windows;可用 /THEME=light、/THEME=dark 和 /THEME=auto 显式选择配色。窗口在品牌控件准备完成后显示。进度读取锁定版本的 7-Zip 解压器百分比;目录替换、注册和清理仍使用有界估算。加权百分比不代表剩余时间。NSIS 报告成功后,进度条用 600 毫秒补满并短暂显示 100%,再显示完成页;切换目标时长为 750 毫秒。完成页保留窗口位置。点击完成后,安装程序先隐藏窗口,再启动已安装的可执行文件;启动失败会恢复页面以供重试。目录替换和失败恢复遵循上文描述的安装流程。首次启动的配置档案准备仍属于独立的 Desktop 操作。
Windows 打包使用 Visual C++ Build Tools 和 Windows SDK 编译 x86 Win32/GDI+ 辅助库;签名构建通过已配置的 Windows 签名器对该库签名。准备钩子在所有平台上均由 electron-builder 继续负责收集生产依赖。安装界面决策记录 NSIS 接入方式和发布验证要求。
在有交互式桌面的 Windows x64 上,从仓库根目录运行 pnpm --dir apps/desktop run test:installer,可将小型原生测试载荷接入正式安装配置并执行验证。每次运行使用独立产品身份,依次验证仅英文和仅中文的安装器变体,并根据实际显示的欢迎页按钮选择测试文案。两个变体均安装到私有目录并在测试后卸载;截图和结果保留在 .desktop-build/installer-tests/ 下。检查包含末尾带分隔符的已登记路径升级,以及磁盘根目录拒绝。可选的 --signed 标志使用下文的 Windows EV 配置,在嵌入前对测试程序和辅助库签名;它不会启用更新源。
本项目使用的 SafeNet Token 出现 SignTool Error: No private key is available. 时,说明 PIN(密码)错误。立即停止所有签名尝试,等待用户处理 PIN 后再继续。PIN 输错达到五次会锁定 Token。遇到该错误后,不得重试打包或签名探针。签名器串行执行 Token 操作,首次失败后拒绝所有排队任务。
Windows 打包将 7-Zip 过滤器固定为 BCJ,以兼容内置的 NSIS 解码器。这样可以保留 x64 安装包中由依赖携带的 ARM64 二进制文件;自动 ARM64 过滤会生成该解码器无法解压的条目。
NSIS 在安装阶段清理临时解压目录,完成后才显示完成页或自动启动应用。已安装的生产依赖保持为普通文件;启动时不会再次解压。安装仍会写入完整的应用目录树。
在 .env.windows 中填写 DSH_DESKTOP_WINDOWS_CER_FILE(公开 EV 叶证书)、DSH_DESKTOP_WINDOWS_SIGNTOOL(SafeNet 兼容的 SignTool)、DSH_DESKTOP_WINDOWS_KEY_CONTAINER(匹配的私钥容器)和 DSH_DESKTOP_WINDOWS_TOKEN_PIN(Token Password)。私钥仍保留在 USB Token;不要把证书或本地凭据文件提交到 Git。
pnpm run package:desktop:win:x64
打包前插入并解锁 Token。electron-builder 钩子把每个产物交给采用 CRLF 的 scripts/windows-sign.cmd;该 CMD 只调用一次已配置的 SignTool,并指定 /f、SafeNet /kc "[{{PIN}}]=容器"、/csp "eToken Base Cryptographic Provider"、SHA-256 文件摘要和 DigiCert SHA-256 RFC 3161 时间戳。钩子不会改用 electron-builder 内置的 SignTool,也不会重试失败的签名请求。SignTool、证书、容器、PIN、Token 或签名不可用时,Windows 发布打包会失败,不会生成未签名产物。
PIN 不能包含 ]、引号或换行,因为这些字符用于分隔 SafeNet /kc 值或对应的 CMD 参数。CMD 会禁用延迟展开,因此包含 ! 的 PIN 可以原样到达 SafeNet。打包流程不会把任何 DSH_DESKTOP_WINDOWS_* 字段传给构建与 运行时准备子进程;它只向 electron-builder 提供四个配置输入,在其他字段已经清理的环境中只向签名 CMD 提供经过校验的签名字段,在 SignTool 启动前清除这些字段,并遮盖 SignTool 诊断。SafeNet 仍要求 PIN 出现在 SignTool 进程命令行中。本地 .env.windows 明文保存 PIN,应限制文件访问权限;CI 使用临时文件并在任务结束后删除。不要提交或分享文件内容,也不要把凭据写入日志。配置检查不会消耗 Token 的 PIN 尝试次数;签名仍在首次失败后停止整批任务。
使用对应的 :dir 命令可以生成可直接运行的应用目录,而不是安装包,例如:
pnpm run package:desktop:dir
pnpm run package:desktop:mac:arm64:dir
需要检查或诊断为宿主目标准备的资源而不调用 electron-builder 时,可以让同一流水线在准备完成后停止:
pnpm run prepare:desktop
这条诊断命令是另一种停止位置,并非两条命令构建流程的前半段。之后执行 package:desktop* 时仍会重新完成正式构建与准备,避免使用陈旧的 dsh 包、运行时文件或 dsh 内容。
每条打包命令都会构建仓库,打包以 dsh 和私有 Desktop Host 为根的第一方生产依赖闭包,并准备目标专用的 Electron 分发包与 pnpm CLI。prepare:dsh 在构建时安装一次生产依赖图,准备物化包供 electron-builder 归档到 app.asar/dsh,移除包管理器元数据,并生成包含共享包版本和最终文件哈希的 desktop-runtime.json。在 macOS 上,它先签名并验证原生文件,再生成清单;electron-builder 不对已签名的此目录重复进行嵌套签名。资源映射明确包含默认根目录过滤器会忽略的 dsh/node_modules;准备完成的运行时清单在原生签名后检查。原生可执行文件及库解包到 ASAR 旁;Python、独立 Node 和 pnpm 保留在外部 runtime 资源中。签名安装包、公证、已安装应用升级和各目标原生模块的验收需要发布环境。
未压缩产物包含 Electron、物化后的 dsh 生产依赖树、pnpm,以及壳应用。安装包大小与文件系统占用不同;发布验收需要测量两者,以及 profile 插件存储和首次启动耗时。此布局用更多应用内文件换取消除用户机器上的核心包安装过程。
打包应用会在主窗口打开十秒后检查目标专用的发布流;本地化的 检查更新… 菜单项会手动触发同一检查。发现可用版本时,应用打开一个原生确认弹窗。用户确认后,应用等待正在进行的检查完成,下载并验证已签名的 Desktop 发布、停止 dsh 子进程,并把安装与重启交给 electron-updater。下次启动在显示本地加载页的同时校准版本绑定的运行时。
签名打包为 DSH_DESKTOP_AUTO_UPDATE_ENV 选择的部署生成 generic-provider 频道元数据。NSIS 差分包与 macOS ZIP 目标让 electron-updater 可以复用未变化的数据块;供手动安装的 DMG 经过公证,但不生成 blockmap,因为它不是 macOS updater 的载荷。运行时与桌面壳仍属于同一个签名 Desktop 发布。macOS 签名与公证凭据使用 electron-builder 的标准环境变量;Windows EV 签名使用上文所述的公开证书、已验证 SignTool、SafeNet 容器和 runner PIN。必填 Desktop 发布环境选择构建所验证的应用身份与平台签名身份。
未打包的 Electron 进程使用应用目录下的 .desktop-build/development/project 作为开发项目。DSH_DESKTOP_PNPM_ENTRY 和 DSH_DESKTOP_DSH_DIR 用于选择明确的运行时资源。打包应用会忽略这些变量,从 process.resourcesPath 解析签名资源,并使用受管 Desktop profile。
$DSH_HOME 下的会话、设置、凭据、工作区和存储,但可执行包、插件激活和锁文件彼此隔离。