← 返回列表
需源码安装
DSH 客户端是 DeepSeek HarnessdshWeb GUI 的原生客户端。打包后的应用名为…
暂不能直接安装(需源码编译或环境不满足):仓库 package.json 标记 private,未发布到 npm,需从源码安装。 · 最近上游提交 2026/9/18 · 已提供中文文档
DeepSeek Harness 的跨平台客户端,目前发布 macOS 版本。
综合分
36.4
GitHub 分
36.4
用户评分
—
★ Stars
5
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add fatwang2/dsh-client仓库 package.json 标记 private,未发布到 npm,需从源码安装,改用 GitHub 源安装
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-client(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
仓库 package.json 标记 private,未发布到 npm,需从源码安装
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/17 18:24:18
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
DSH 客户端 DSH 客户端是 DeepSeek Harness(dsh)Web GUI 的原生客户端。打包后的应用名为 DeepSeek Harness。其外壳负责监管一个回环 dsh web 宿主进程,掌管应用生命周期,并将精确锁定的 harness 运行时暂存到打包应用中——无需单独安装 Node.js,也无需终端窗口。 这是一个独立的社区项目,与 DeepSeek 无关联,也未获其背书。 适用于 macOS 的 DeepSeek Harness 架构 src/main.ts Electron 外壳:窗口、应用菜单、安全加固、启动接线 src/host-supervisor.ts dsh web 子进程:启动、就绪 URL 解析、优雅关闭 src/window-lifecycle.ts 关闭即隐藏与退出时序,独立于 Electron src/update-controller.ts electron-updater 状态:静默检查、后台下载、重启提示 scripts/stage-runtime.mjs 将锁定的 dsh 依赖闭包实体化到 runtime-host/ scripts/verify-packaged-runtime.cjs afterPack 守卫:拒绝缺少 Host 产物的包 scripts/release-mac.sh 本地签名 + 公证构建入口(从不发布) scripts/release-mac.mjs 发布预检、打包验证;仅在 CI 中上传 scripts/release-assets.mjs 使 Release“完整”的资产集合,由两个脚本共享 scripts/smoke-host.mjs 发布门禁:启动暂存的 Host 并验证其就绪行 scripts/track-dsh.mjs 将锁定版本与上游最新的 dsh Release 比较;提升锁定版本、应用版本、发布说明 scripts/semver-compare.mjs 供跟踪器使用的 SemVer 优先级比较,在任何 npm ci 之前运行 scripts/verify-inset.mjs 对运行中应用的交通灯内边距几何进行 CDP 检查 scripts/make-icons.swift 从 harness 标志重新生成 build/icon.png .github/workflows/track-dsh.yml 定时:上游有新 dsh → 发布 .github/workflows/release.yml 手动:发布 main 上当前版本 .github/workflows/release-macos.yml 共享的构建、签名、公证、验证、发布任务 runtime/package.json 精确的 @deepseek-ai/dsh 版本锁定(上游不提供兼容性承诺) runtime-host/package-lock.json Host 其余依赖闭包的已提交锁文件 外壳与宿主如何协同工作: 1. 启动时,监管器会启动 dsh web --host 127.0.0.1 --port 0。操作系统会分配一个空闲的回环端口,因此永远不会发生 3080 冲突。 2. harness 会打印其规范的就绪行(dsh web: http://127.0.0.1:/?token=;该 token 随 0.1.5-alpha harness 引入,更早的版本打印裸源)。监管器会增量解析它并严格验证(回环 HTTP、根路径、显式端口、至多一个 token 查询参数),然后将回环 URL——源加 token——交给窗口。 3. 窗口的首次导航会保留该令牌(API 围栏将会话绑定到该令牌,并拒绝未携带令牌的环回请求);此后的导航被锁定到该来源。其他 HTTP(S) 链接在系统浏览器中打开;所有权限请求均被拒绝;渲染器在沙箱中运行,且不集成 Node。 4. 关闭窗口会将其隐藏,而 Host 保持存活;点击 Dock 图标可将其恢复。显式退出会先处置 Host(先发送 SIGTERM,在 harness 的 5 秒排空后发送 SIGKILL),然后才释放 Electron 的退出序列。 5. 打包构建通过 Electron 自带的 Node 运行时(ELECTRON_RUN_AS_NODE=1)运行已暂存的 CLI,因此不会附带第二个 Node 二进制文件。 macOS 交通灯内边距 随附的 harness 前端并不知道无边框的 hiddenInset 外壳,因此外壳会注入一个样式表,在侧边栏列的顶部预留 40px 的条带,用于放置关闭/最小化/缩放按钮,并将全宽顶部条带标记为原生窗口拖拽区域([class="sidebarCol"] 属性选择器,在 css-module 哈希变化时保持稳定)。交互控件被明确排除在拖拽区域之外,以便它们继续接收指针事件。该注入在 loadURL 之前排队,并在 dom-ready 时重新应用;它从不被 await,因为在渲染器提交文档之前执行 insertCSS 否则可能会使启动停滞。 仅对侧边栏添加内边距会使中间列和第三列从交通灯下方开始,因此该样式表还会将它们的标题行下推到侧边栏 logo 所在的行:[data-slot="conversation.session.header"] > header(中间列的会话标题——前端自有的标题/标签页/操作条带)获得 60px 的顶部内边距,而 [data-slot="details"] > > [class="_header"](详情面板的标题行)获得 62px。data-slot 是前端为这些条带声明的稳定接缝,而同一元素上的 css-module 哈希则不是,因此这两条规则都基于该属性和元素类型进行选择,而不是基于类;每条规则的对齐几何在 src/main.ts 中紧邻注入的 CSS 处有注释说明。 scripts/verify-inset.mjs 通过 CDP 检查所应用的几何(使用 --remote-debugging-port= 启动):拖拽区域必须在 40px 高度上横跨整个窗口宽度,并且 logo 行必须从交通灯条带下方开始。 开发 npm install npm run stage # 将固定的 dsh 运行时闭包物化到 runtime-host/ npm run dev # 构建 + 启动;通过应用程序菜单或 Cmd+Q 退出 DSH_MAC_NODE_EXECUTABLE 覆盖开发用的 Node 二进制文件。开发主机共享你常规的 ~/.dsh(凭据、设置、会话)。 测试与类型检查 npm test npm run typecheck 打包 npm run package # 当前平台的未打包应用(dist/) npm run dist # 用于本地验证的未签名 macOS DMG + 更新 ZIP npm run dist:signed # 已签名 + 已公证的 DMG/ZIP + 更新元数据 暂存步骤会针对已提交的 runtime-host/package-lock.json 使用 npm ci 安装 Host 闭包,保留 npm 的扁平化布局(不使用 pnpm 符号链接存储),剥离 bin 符号链接,并且如果 CLI 入口或 Web 前端 dist 缺失,或者 harness 包并非全部来自固定版本,则构建失败。afterPack 钩子会在签名前,在 bundle 内根据固定版本重新验证整个闭包。签名发布流程(scripts/release-mac.mjs)还会额外启动一次真实的已暂存 Host(scripts/smoke-host.mjs),这样如果某个 harness 的就绪行无法被 shell 解析,就会导致发布失败而不是将其发布出去;并且在打包前清空 dist/,以便产物严格按发布版本进行断言和上传。 签名构建完成后,验证已安装的产物: codesign --verify --deep --strict --verbose=2 "dist/mac-arm64/DeepSeek Harness.app" spctl --assess --type execute --verbose=4 "dist/mac-arm64/DeepSeek Harness.app" xcrun stapler validate "dist/mac-arm64/DeepSeek Harness.app" 发布与自动更新 签名发布使用 electron-updater,并接入公开的 fatwang2/dsh-client GitHub Releases feed。electron-builder 会将该仓库嵌入应用程序,并生成 Squirrel.Mac 所消费的 ZIP、blockmap 和 latest-mac.yml。 发布仅由 GitHub Actions 构建和发布。 有一个工作流负责这项工作——.github/workflows/release-macos.yml——并且有两个入口点调用它,因此自动路径和手动路径不会发生偏离: | 入口点 | 触发条件 | 发布内容 | |---|---|---| | .github/workflows/track-dsh.yml | 每四小时一次,或 Run workflow(可选指定确切的 harness 版本) | 最新的上游 @deepseek-ai/dsh,来自它自行写入的 bump 提交;还会重试某个 Release 仍然缺失或不完整的版本 | | .github/workflows/release.yml | 在 main 上 Run workflow* | 已在 main 上的版本——用于客户端侧更改的发布按钮 | 两者都会调用 release-macos.yml,该工作流会在 GitHub macOS arm64(Apple silicon)运行器上构建、签名、公证、验证并发布。由于它们共享同一个工作流级并发组(dsh-release,运行中永不取消),同一时间只有一个发布会触及某个版本标签,并且发布任务会在任何 bump 后重新检查完整性,因此排队的重复运行会跳过昂贵的构建,而不是重新构建一个已经发布的版本。(GitHub 每个组保留一个正在运行加一个待处理的运行;第三个排队的运行会替换待处理的运行,因此一波调度会合并而不是堆积。) 该运行器是 Apple silicon,因此 Releases 和自动更新 feed 目前服务于 Apple silicon 安装。本地 npm run dist:signed 会在宿主架构上驱动相同的 electron-builder 目标;electron-builder 的架构参数(--x64、--arm64)可以指定不同的架构。 自动跟踪上游 .github/workflows/track-dsh.yml 每四小时运行一次,也可从 Actions 标签页按需触发(Run workflow)。它会将 runtime/package.json 中的固定版本与 deepseek-ai/deepseek-harness 中最新的 dsh-v Release 进行比较(取最高版本,包含 alpha;上游将每次发布都标记为预发布,因此 npm 的 latest dist-tag 会滞后)。当上游发布了更新的版本且该版本也已在 npm 上时,该 release 会: 1. 提升固定版本,重新解析 Host 闭包(stage-runtime.mjs --relock),启动该闭包一次以证明 shell 仍能解析其就绪行,提升应用的补丁版本,并写入 .github/release-notes/.md,其中指明所捆绑的 harness; 2. 运行测试和类型检查,然后才以 github-actions[bot] 身份提交到 main 并推送——因此客户端无法启动的 harness 会在工作树中导致运行失败,而不会落到 main 上; 3. 构建、签名、公证、验证并发布。 应用版本有意独立于 harness 版本:harness 发布的是候选版本,而安装在稳定版本上的应用会跳过预发布更新。每次跟踪的升级都是一次补丁版本提升;Release 标题和说明会指明它捆绑的是哪个 harness。 如果构建在其提升提交落地后失败,下一次运行会注意到当前应用版本尚无完整的 Release,并在不再次提升的情况下重试发布。完整意味着该 Release 可被公开使用——已发布、不是草稿、不是预发布——并带有更新源的全部资产:DMG、更新 ZIP、其 .zip.blockmap,以及 latest-mac.yml,后者的 version: 必须指明同一版本。任何一项不满足的 Release 都算作未发布,因此下一次运行会在现有标签上重新构建并修复它(同时清除多余的草稿/预发布标志)。 一次运行仅在 main 上继续(两个 job 都基于该分支的固定版本进行判断,而 workflow_dispatch 没有分支过滤器,因此每个入口点都自行对 github.ref 进行防护)。当显式版本固定该版本而非最新上游 Release 时,早于当前固定版本的版本会被拒绝:显式版本不得降级。两种短暂的上游状态会被处理而不会导致运行失败:上游已打标签但尚未在 npm 上的版本会保持固定版本,并在之后的某个时间点重试;而领先于最新上游 Release 的固定版本会被保留,而不会向后提升。 该工作流需要以下仓库密钥(Settings → Secrets and variables → Actions): | Secret | 内容 | |---|---| | CSC_LINK | Developer ID Application .p12 的 Base64 | | CSC_KEY_PASSWORD | 该 .p12 的密码 | | APPLE_API_KEY_P8 | App Store Connect API 密钥 .p8 的内容 | | APPLE_API_KEY_ID | 该 API 密钥的 Key ID | | APPLE_API_ISSUER | 该 API 密钥的 Issuer ID | 在已登录钥匙串中持有该身份的 Mac 上,导出 从 Keychain Access 导出带私钥的 Developer ID Application 证书为 .p12,然后: gh secret set CSC_LINK --body "$(base64 -i DeveloperID.p12)" gh secret set CSC_KEY_PASSWORD gh secret set APPLE_API_KEY_P8 .md)。 2. Actions → Release current main* → Run workflow。 - dry_run 会构建、签名、公证并验证,但不发布,也不向 main 推送任何内容——一次演练会让仓库保持原样,因此追踪器之后不会拾取该版本。 - harness_version 还会额外先将那个确切的 @deepseek-ai/dsh 固定下来(该路径会自行对应用版本做补丁级提升,因此使用它时不要动 version)。 - 只有在替换一个已完全发布的版本时才需要 allow_republish;没有它,运行会拒绝,这是防止同一版本发布两次的预期保护。重新发布同一版本不会到达已安装的客户端:electron-updater 会比较版本号,因此修复必须以新版本发布。 该运行需要 main 的干净检出,因此先推送版本提升。随后预检会要求分支为 main 且 HEAD == origin/main,之后才会签名、公证、验证更新元数据并创建 Release。提升版本是使发布成为可能的关键:如果你更改了客户端代码但没有提升版本,追踪器仍会在 main 上看到已发布的版本,因而不会发布任何内容——这是保护机制在起作用,而不是失败。(反过来,一个已在 main 上但尚无 Release 的版本,即使你从未按下按钮,也会被追踪器的下一次轮询拾取。) 在维护者的 Mac 上构建 本地运行会构建、签名、公证并验证 CI 将要发布的内容——但 它们从不发布。有两件事保证了这一点:本地入口点 (scripts/release-mac.sh)在交接前会丢弃发布相关的变量,而 scripts/release-mac.mjs 仅在真实的 GitHub Actions runner 上设置了 DSH_RELEASE_UPLOAD=1 时(GITHUB_ACTIONS=true 加上一个 run id)才会 上传。出于同样的原因,npm run package 和 npm run dist 会传入 --publish never。这是一道防护,而非编译器:在一台 已经对发布仓库完成认证的机器上手动导出所有这些变量仍然会发布,因此请将 本地流程视为仅用于构建和验证。 将 .env.release.example 复制到被忽略的 .env.release,配置 Developer ID 身份和 App Store Connect API 密钥,然后运行: sh npm run dist:signed # sign, notarize, verify; artifacts stay in dist/ 为你自己的机器构建的未签名版本(无需凭据)是 npm run dist —— 它会生成未签名的 DMG/ZIP,因此绝不会被 误认为是可分发的发布版本。 已签名的应用会在启动后静默检查,在后台下载,并且 仅在更新就绪后才提示重启。选择重启会首先通过正常的优雅关闭路径 关停捆绑的 Host。(本地构建的 bundle 没有自己的更新源——npm run package 生成的是不带 app-update.yml 的 --dir 应用——因此请安装 Release DMG 以接收更新。) 环境 | 变量 | 作用 | |---|---| | DSH_MAC_OWN_HOME=1 | 将 harness 状态限制在应用的数据目录(~/Library/Application Support/dsh-mac/dsh-home)内,而非共享的 ~/.dsh。 | | DSH_MAC_NODE_EXECUTABLE | 仅限开发:用于运行暂存 CLI 的 Node 兼容二进制文件。 | | DSH_MAC=1 | 导出到 Host 进程环境的标记。 | | DSH_RELEASE_ENV | 本地发布环境文件的可选路径;默认为 .env.release。 | | DSH_RELEASE_TAG | 可选的 Release 标签覆盖;默认为 v。 | | DSH_RELEASE_UPLOAD=1 | 上传到 GitHub Releases。仅由发布工作流设置;即使设置了它,本地机器也会被拒绝。 | | DSH_REQUIRE_NEW_RELEASE=1 | 拒绝发布一个已有完整 Release 的版本(手动发布;也适用于试运行)。 | | SKIP_UPLOAD=1 | 对于原本会发布的运行,显式抑制上传(双重保险;本地运行从不发布)。 | 所有其他环境变量都会传递给 Host(DEEPSEEK_API_KEY、代理等)。 更新 harness harness 是一个快速迭代的候选发布版本,明确不提供兼容性 承诺,而且仅固定 @deepseek-ai/dsh 并不能固定 Host。其约 230 个 同级包通过脱字符范围相互依赖,而 ^0.1.0-rc.6 会匹配 0.1.0-rc.7,因此无锁文件的安装会静默地产生一个 CLI,其 内部依赖来自一个候选发布版本,而 Web 前端来自另一个。 runtime-host/package-lock.json 因此被提交,staging 运行 npm ci, 并且 staging 和 afterPack 钩子都会拒绝一个其 harness 包 并非全部带有固定版本的树。 每当上游发布新版本时,跟踪工作流会自动执行此升级(参见自动跟踪上游)。手动操作时,同样是这三个步骤: sh 1. bump the exact pin in runtime/package.json 2. resolve the closure afresh and rewrite the lockfile npm run stage -- --relock 3. commit runtime/package.json and runtime-host/package-lock.json together 如果没有 --relock,npm ci 会拒绝一个 lockfile 不满足的固定版本,因此版本提升绝不会意外地到达某个包。升级后,请重新验证启动并重新运行 scripts/verify-inset.mjs:harness 前端对红绿灯内嵌样式表所针对的 DOM 不提供任何兼容性承诺。 许可证 MIT。打包后的应用内嵌了 MIT 许可的 @deepseek-ai/dsh 运行时;在分发前,请参阅其仓库的 THIRD_PARTY_NOTICES.md 以了解传递依赖许可证。
同作者(fatwang2)的其他插件
扫码进群