🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

桌面外壳 fellow99/dsh-desktop

DeepSeek Harness
fellow9913 天前有提交已提供中文文档扫描:含敏感能力

用桌面窗口运行官方 Web 界面,支持三大平台

29.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/28 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add fellow99/dsh-desktop
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · dev
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 13 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件
查看扫描证据(共 61 处,展示前 25 条)
  • 读取本地文件
    src/main/host.ts:79
    for (const file of readdirSync(DSH_CLI_LIB)) {
  • 读取本地文件
    src/main/host.ts:84
    const content = readFileSync(fullPath, 'utf8');
  • 读取本地文件
    src/main/host.ts:89
    candidates.push({ path: fullPath, mtime: statSync(fullPath).mtimeMs });
  • 读取本地文件
    src/main/host.ts:116
    if (!existsSync(srcPkg)) return;
  • 写入本地文件
    src/main/host.ts:117
    mkdirSync(dest, { recursive: true });
  • 读取本地文件
    src/main/host.ts:120
    if (!existsSync(destPkg)) {
  • 读取本地文件
    src/main/host.ts:127
    const seed = JSON.parse(readFileSync(srcPkg, 'utf8')) as {
  • 写入本地文件
    src/main/host.ts:156
    if (changed) writeFileSync(destPkg, JSON.stringify(cur, null, 2) + '\n');
  • 写入本地文件
    src/main/host.ts:207
    mkdirSync(dest, { recursive: true });
  • 删除本地文件递归
    src/main/host.ts:288
    rmSync(dest, { recursive: true, force: true });
  • 写入本地文件
    src/main/host.ts:289
    mkdirSync(dest, { recursive: true });
  • 写入本地文件
    src/main/host.ts:298
    mkdirSync(destNm, { recursive: true });
  • 写入本地文件
    src/main/host.ts:321
    mkdirSync(join(home, 'profiles', 'node_modules'), { recursive: true });
  • 删除本地文件
    src/main/host.ts:372
    try { unlinkSync(p); } catch (err) {
  • 删除本地文件
    src/main/host.ts:375
    try { rmdirSync(p); } catch { }
  • 读取本地文件
    src/main/runtime.ts:75
    if (!existsSync(file)) return false;
  • 读取本地文件
    src/main/runtime.ts:77
    accessSync(file, constants.X_OK);
  • 写入本地文件
    src/main/runtime.ts:134
    mkdirSync(binDir, { recursive: true });
  • 写入本地文件
    src/main/runtime.ts:137
    writeFileSync(shimPath, dshShim());
  • 写入本地文件
    src/main/runtime.ts:139
    writeFileSync(shimPath, dshShim(), { mode: 0o755 });
  • 写入本地文件
    src/main/runtime.ts:154
    if (existsSync(bin)) chmodSync(bin, 0o755);
  • 读取本地文件
    src/main/runtime.ts:154
    if (existsSync(bin)) chmodSync(bin, 0o755);
  • 读取本地文件
    src/main/window-state.ts:53
    const raw = JSON.parse(readFileSync(stateFilePath(), 'utf8')) as Partial<WindowState>;
  • 写入本地文件
    src/main/window-state.ts:84
    mkdirSync(path.dirname(stateFilePath()), { recursive: true });
  • 写入本地文件
    src/main/window-state.ts:85
    writeFileSync(stateFilePath(), JSON.stringify(state), 'utf8');
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
| English DSH Desktop 一个 Electron 外壳,用来跑 DeepSeek Harness 的官方、未改动 dsh Web UI —— 支持 Windows、Linux 和 macOS。如果你想自己做一个外壳,它也是参考实现。 真实截图 —— 不是效果图。 外壳里跑的就是官方 dsh Web UI。这张图来自 Electron on HarmonyOS Edition(同一个外壳、同一个 Web UI、同一条数据链路),因为那个版本有现成的设备截图;桌面版加载的 UI 与它完全一致,同样未做改动。 状态 0.2.1 —— 三个平台都能打包;托盘、原生通知、原生窗口边框、剪贴板图片粘贴、窗口状态持久化、F11 都已就位。暂不支持自动更新、代码签名和商店分发。 为什么做这个外壳 三个决定,就是全部设计: | 决定 | 含义 | | 上游零改动 | 渲染进程以同源方式加载 dsh web 自带的 SPA。只打了三个幂等补丁,全是 Electron 兼容性开关(关掉 HMR、关掉原生目录选择器、关掉引导步骤)—— 不 fork,不重写 UI。
展开完整文档(README 剩余 1 节)
| English

DSH Desktop

一个 Electron 外壳,用来跑 DeepSeek Harness 的官方、未改动 dsh Web UI —— 支持 Windows、Linux 和 macOS。如果你想自己做一个外壳,它也是参考实现。

真实截图 —— 不是效果图。 外壳里跑的就是官方 dsh Web UI。这张图来自 Electron on HarmonyOS Edition(同一个外壳、同一个 Web UI、同一条数据链路),因为那个版本有现成的设备截图;桌面版加载的 UI 与它完全一致,同样未做改动。

状态 0.2.1 —— 三个平台都能打包;托盘、原生通知、原生窗口边框、剪贴板图片粘贴、窗口状态持久化、F11 都已就位。暂不支持自动更新、代码签名和商店分发。

为什么做这个外壳

三个决定,就是全部设计:

| 决定 | 含义 |
| 上游零改动 | 渲染进程以同源方式加载 dsh web 自带的 SPA。只打了三个幂等补丁,全是 Electron 兼容性开关(关掉 HMR、关掉原生目录选择器、关掉引导步骤)—— 不 fork,不重写 UI。 |
| 没有 CORS,没有鉴权流程,没有自定义协议,没有 IPC 载体 | dsh Host 在 Electron 主进程内部 启动,它的 webserver 在同一个绑定端口上同时提供 dist/ 和 /api。窗口就是一个浏览器,指向 http://127.0.0.1:<port>/。 |
| Linux 是一等目标 | .deb 和 .rpm 与 Windows 安装包、macOS DMG 一起发布。多数 dsh 桌面外壳只做到 Windows/macOS。 |

功能

| 能力 | 状态 |
| 系统托盘(退出 / 恢复) | ✅ |
| 原生通知,订阅 dsh 会话事件 | ✅ |
| 原生窗口边框(系统最小化 / 最大化 / 关闭) | ✅ |
| 剪贴板图片粘贴 | ✅ |
| 窗口状态持久化(最大化 / 窗口尺寸恢复) | ✅ |
| F11 全屏 | ✅ |
| 全局快捷键 · 开机自启 · 多窗口 | ⏸ 暂缓 |

原生文件选择器复用了 dsh 内置的目录浏览器(三个补丁之一),所以不会弹出系统对话框。

下载

| 平台 | 产物 | 说明 |
| Windows x64 | Setup.exe · 便携 ZIP | Squirrel 安装器,未签名 |
| Linux x64 | .deb · .rpm · ZIP | Debian/Ubuntu 和 Fedora/RHEL |
| macOS arm64 | .dmg · ZIP | 未签名 —— Gatekeeper 需要手动放行 |

HarmonyOS 版本(2in1 / 平板) 放在单独的仓库里。dsh-desktop-hos —— HarmonyOS Edition 上的 Electron —— 沿用同一套外壳架构和同一个未改动的 Web UI,只把 Electron 运行时换成 Electron-on-HarmonyOS 版本;目前还没有面向消费者的安装包(AppGallery 渠道)。dsh-desktop-ark —— HarmonyOS Edition —— 保留同样的进程内 Host,但去掉 Electron:由系统 ArkWeb 渲染 UI,内嵌的 Node 运行时(ohos-node-bridge)运行 dsh;目前是 v0.1.0 脚手架。

这里的一切都是本地 npm run make 的产物:不签名、不公证、不自动更新。如果这些对你很重要,就自己构建 —— 见 Development。

兼容性

| 外壳 | dsh(上游 tag) | Electron | 平台 | 已验证 |
| 0.2.1 | dsh-v0.2.1-rc.2 | 43.0.0 | Windows x64 · Linux x64 · macOS arm64 | 产物由 npm run make 生成;运行时通过 npm start 验证 |

上游 dsh 是开发者预览版,会带破坏性变更。这个外壳一次只锁定一个 tag:升级就是新增 patches/<new-tag>/,再更新 scripts/build-dsh.mjs 里的锁定版本。

同时也是一个参考实现

大多数 dsh 桌面外壳是产品。这个外壳刻意按样本的方式写文档,方便你把其中能用的部分抄进自己的外壳:

- specs/ —— 按实际实现写的规格:host、窗口、托盘、通知、生命周期、preload、应用入口、桌面配置档、插件市场
- patches/dsh-v0.2.1-rc.2/ —— 三个补丁,每个都附了理由
- AGENTS.md、docs/000-产品概念设计.md —— 架构与工作约定
- scripts/build-dsh.mjs · collect-dsh.mjs · fetch-runtime.mjs —— 可复现构建、产物收集、内置运行时通道

工作原理

Electron main process (Node.js, also hosts the dsh Host)
runProfile('desktop', ['--port','0']) → { ctx, port, shutdown }
├─ webserver 127.0.0.1:<free port> — serves dist + /api ├─ apiProxy RPC gateway └─ connection /api + WebSocket renderer: loadURL('http://127.0.0.1:<port>/') ← same-origin

没有 preload 桥,也没有窗口控制通道:渲染进程直接用 dsh 现有的 WebApiClient(HTTP 上行 + WebSocket 下行)访问同源地址。托盘和通知在主进程里订阅 ctx 的会话事件生成。

技术栈

- Electron + Electron Forge(脚手架与打包)
- deepseek-harness(dsh,本项目的同级目录,不是子模块,路径写作 ../deepseek-harness;以本地源码引用的方式消费)—— 当前构建基于 dsh-v0.2.1-rc.2;它的补丁放在 patches/dsh-v0.2.1-rc.2/
- dsh-market(同级目录,路径写作 ../dsh-market;内置的可视化插件市场 —— npm 包 dshmarket)
- TypeScript

开发

集成方式

- 源码引用:dsh 放在同级目录(../deepseek-harness,不是子模块),我们消费它的构建产物。插件市场 dsh-market 同样放在同级目录(../dsh-market,npm 包 dshmarket),它的构建输出会落到 dsh 的 node_modules/dshmarket,并作为内置插件打包进去。构建时两个同级目录缺一不可。
- 宿主集成:src/main/host.ts 动态导入 dsh 的 runProfile(apps/cli 构建产物),在主进程里托管 dsh Host(webserver 绑定 127.0.0.1:<free port>),返回 { ctx, shutdown, port, url } 句柄。
- 同源数据面:渲染进程执行 loadURL(http://127.0.0.1:<port>/),以同源方式加载 dsh Web UI,复用 WebApiClient(HTTP 上行 + WebSocket 下行)—— 零 CORS、零鉴权、零新增载体。
- desktop 配置档:profiles/desktop/(dsh.profile.bundles = [dsh-base, dsh-web-app],并用 cordis.patch.yml 覆盖 web-runtime.printUrl: false),运行时复制到 $DSH_HOME/profiles/desktop。

构建流程(含补丁)

dsh 依赖一些 Node 内部 API(HMR、原生目录对话框),这些在 Electron 下不可用,所以构建前必须先打三个补丁。一条命令全搞定(幂等 —— --reverse --check 能识别已打过的补丁并跳过)。它还会顺带构建同级目录的 ../dsh-market 插件市场:

npm run build:dsh # ① git apply both patches under patches/ → ② pnpm install (if node_modules missing) → ③ build:lib:host + build:lib:client + build:web → ④ build ../dsh-market (npm install if needed + npm run build)

前置条件 —— 同级源码检出。 本项目把 deepseek-harness 和 dsh-market 都当作同级目录消费(不是子模块)。构建前先把它们克隆到本项目旁边:

dsh: pinned tag = dsh-v0.2.1-rc.2 (also set in .github/workflows; matches patches/dsh-v0.2.1-rc.2/)
git clone --branch dsh-v0.2.1-rc.2 https://github.com/deepseek-ai/deepseek-harness.git ../deepseek-harness
git clone --branch v1.26.0 https://github.com/dsh-market/dsh-market.git ../dsh-market

../dsh-market 缺失时 collect-dsh.mjs 会直接报错退出(打包后的应用会把它作为 dsh-dist/node_modules/dshmarket 一起打包);build:dsh 在它缺失时只给警告,并跳过市场部分的构建。
dsh 版本锁定。 本项目基于 deepseek-harness 标签 dsh-v0.2.1-rc.2 构建。补丁按 dsh 版本组织(patches/<dsh-tag>/),scripts/build-dsh.mjs 锁定 patches/dsh-v0.2.1-rc.2/ —— 升级到新 dsh 标签时,要新增对应的 patches/<new-tag>/ 目录,并更新这处锁定。

| 补丁 | 用途 |
| patches/dsh-v0.2.1-rc.2/dsh-disable-hmr.patch | 给 runProfile 加一个 DSH_DISABLE_HMR 开关,跳过只做监听的 HMR(HMR 依赖 --expose-internals) |
| patches/dsh-v0.2.1-rc.2/dsh-disable-native-picker.patch | 在 Electron 下强制目录选择器走浏览模式(原生对话框 worker 会失败,因为它要启动 electron.exe) |
| patches/dsh-v0.2.1-rc.2/dsh-disable-welcome-notice.patch | 去掉客户端的两步 settings.onboarding(带版本号的内测提示、官方 DeepSeek API-key 提示),首次启动直接进入应用;同时把 apply.client.spec.ts 更新为实际注册的步骤集合 |

Electron 兼容问题的根因:dsh 的加载器通过 node-addon-require-builtin 原生模块获取 Node 内部的 ESM 加载器,这在 Electron 下会失败,因为 Electron 的 V8 缺少 GetAlignedPointerFromEmbedderData 符号;开发模式下加载器回退到默认的 ESM 导入,由 host.ts 的 ensureWorkspaceLinks 把工作区包链接进 dsh 根目录的 node_modules 来解决。

常用命令

This project's deps (npm: Electron / Forge / Vite)
npm install

dsh deps (run inside ../deepseek-harness; pnpm workspace)
cd ../deepseek-harness && pnpm i

Development: Vite build + launch Electron, main process hosts dsh Host and loads its Web UI
npm start

Package: prepackage auto-collects (pnpm deploy materializes dsh artifacts into dsh-dist/, extraResource copies into resources/)
npm run package

Distribution artifacts: Windows Squirrel installer / portable ZIP (makers in forge.config.ts)
npm run make

打包产物 out/DSH Desktop-win32-x64/ 已包含 dsh(lib + node_modules + web dist + profile);exe 直接运行 dsh。

Windows 本地构建排错

在 Windows 上网络受限时(GitHub 连不上 / Corepack 受限),npm run package 会踩到三个已知坑。以下是验证过的修法:

1. pnpm 版本不匹配(pnpm --filter 解析到旧版本)

deepseek-harness/package.json 锁定 packageManager: pnpm@11.7.0,但 corepack pnpm --filter <pkg> run ... 在子工作区里解析到别的版本(比如 11.5.2),报错 This project is configured to use 11.7.0 of pnpm。在 nvm 管理的 Node 下 corepack enable 会因 EPERM 失败(没有 node 目录的写权限),所以不会生成 pnpm shim;.npmrc 里的 pm-on-fail=ignore 也不起作用(版本检查在读取配置之前就跑了)。

修法 —— 手写一个 pnpm.cmd shim 调用 corepack,放到用户可写的目录,并把它排到 PATH 最前面:

powershell
$shimDir = "C:\Users\$env:USERNAME\AppData\Local\pnpm-shim"
New-Item -ItemType Directory -Path $shimDir -Force | Out-Null
$corepackCmd = (Get-Command corepack.cmd).Source # e.g. C:\Program Files\nodejs\corepack.cmd
Set-Content -Path (Join-Path $shimDir "pnpm.cmd") -Value @"
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
call "$corepackCmd" pnpm %*
"@ -Encoding ASCII
$env:PATH = "$shimDir;$env:PATH" # prepend before every build

2. fetch-runtime 重复下载(缺少 .versions.json 标记文件)

scripts/fetch-runtime.mjs 靠 runtime/.versions.json 保证幂等。如果首次下载中断(比如 shell 超时),runtime/node/ 和 runtime/pnpm/ 可能已经就位,标记文件却没写入,于是下一次 npm run package 会重新下载 Node + pnpm。

修复:只要 runtime/node/node.exe 和 runtime/pnpm/pnpm.exe 已存在,就手写标记文件跳过下载: powershell

Must exactly match the wanted string the script builds (node / pnpm / platform / arch)

'{"node":"24.11.1","pnpm":"9.15.9","platform":"win32","arch":"x64"}' |
Set-Content -Path .\runtime\.versions.json -Encoding ASCII -NoNewline

3. Electron 二进制下载 ETIMEDOUT(GitHub 被墙)

electron-forge package 阶段要从 github.com 下载对应的 Electron 二进制,网络受限时会报 connect ETIMEDOUT。

修复:改用 npmmirror 国内镜像(环境变量只对当前构建进程生效): powershell $env:ELECTRON_MIRROR = "https://registry.npmmirror.com/-/binary/electron/" $env:ELECTRON_CUSTOM_DIR = "v{{ version }}"
npm run package

三招一起上(pnpm shim 加进 PATH + 标记文件就位 + Electron 镜像),npm run package / npm run make 就能在受限的 Windows 机器上稳定跑通。

目录结构

本项目、deepseek-harness(dsh)和 dsh-market 放在同级目录(不是子模块),通过源码引用集成:

(sibling directories)
├── dsh-desktop/ # This project (Electron desktop shell)
│ ├── docs/ # Product concept design
│ ├── specs/ # Spec documents (as-built; see specs/README.md for index)
│ ├── patches/ # dsh upstream patches (git apply, auto-applied by build:dsh)
│ │ ├── dsh-disable-hmr.patch
│ │ ├── dsh-disable-native-picker.patch
│ │ └── dsh-disable-welcome-notice.patch
│ ├── scripts/ # Build scripts
│ │ ├── build-dsh.mjs # apply patches + install deps + build dsh + dsh-market artifacts
│ │ ├── collect-dsh.mjs # collect dsh artifacts into dsh-dist/ (pnpm deploy + materialize dshmarket)
│ │ └── fetch-runtime.mjs # fetch portable Node + pnpm into runtime/ (packaged install channel)
│ ├── profiles/desktop/ # Custom desktop profile (dsh.profile.bundles + cordis.patch.yml)
│ ├── src/
│ │ ├── main/ # Electron main process (= dsh Host host)
│ │ │ ├── index.ts # single-instance lock → start host → create window → tray/notification/lifecycle
│ │ │ ├── host.ts # runProfile('desktop') → { ctx, shutdown }; plugin link/resolve
│ │ │ ├── runtime.ts # bundled Node/pnpm/dsh shim + PATH injection (market install channel)
│ │ │ ├── windows.ts # BrowserWindow, loadURL(localhost), native frame/security
│ │ │ ├── window-state.ts # persist maximized/bounds; restore on start; F11 fullscreen
│ │ │ ├── tray.ts # system tray (quit/restore)
│ │ │ ├── notifications.ts # subscribe to ctx session/event → native notifications
│ │ │ └── lifecycle.ts # NO_PROXY/CA, crash handling
│ │ ├── preload/index.ts # preload entry (no window-control bridge)
│ │ └── renderer/renderer.ts # minimal renderer entry (fallback loading page)
│ ├── forge.config.ts # Electron Forge config (extraResource copies dsh-dist + runtime)
│ ├── vite..config.ts # Vite configs (main/preload/renderer)
│ ├── index.html # renderer entry (Forge Vite convention: at project root)
│ └── resources/ # app icon, tray icon
│
├── deepseek-harness/ # The wrapped host (dsh, source reference, not a submodule)
│ ├── apps/ # cli (dsh bin, profile-boot), web (Web frontend, build:web produces dist)
│ ├── packages/ # host / client / core / session workspace packages
│ ├── vendor/ # vendored cordis framework packages (cordis / loader / hmr / ...)
│ └── native/ # landlock-run native module (Linux sandbox, cut in MVP)
│
└── dsh-market/ # Plugin marketplace (source reference, not a submodule; npm pkg "dshmarket")
├── src/ # host half (mounts /dsh-market/ routes, spawns dsh plugin)
├── client/ # browser half (settings-page UI; built to client/client.js)
├── lib/ # compiled host output (materialized into dsh-dist/node_modules/dshmarket)
└── cordis.patch.yml # loader insert declaration ({ id: dsh-market, name: dshmarket })

CI 说明: GitHub Actions 在工作流运行期间会克隆两个同级仓库(见 .github/workflows/ci.yml 和 release.yml 中的 Checkout dsh (sibling) 与 Checkout dsh-market (sibling)),因为 actions/checkout 无法把第二个仓库放进 $GITHUB_WORKSPACE。

相关文档

- docs/000-产品概念设计.md — 产品概念设计(架构、数据流、模块拆分、待定问题)
- specs/README.md — 规格文档索引(项目级与模块级规格)
- AGENTS.md — AI 智能体工作约定

参考资料
- deepseek-harness(同级目录 ../deepseek-harness)—— 被包装的宿主;它的 docs/ 目录里有完整架构文档
- dsh-market(同级目录 ../dsh-market)—— 内置的可视化插件市场(npm 包 dshmarket),由 collect-dsh.mjs 打包
- opencode(桌面外壳参考:packages/desktop/)—— 一个类似的「用 Electron 包装智能体宿主」用例
- DSH Desktop 网站—— 三个版本、真机截图和架构故事,一页看全

许可证

MIT © 2026 fellow99
预览分享卡片长什么样 ↓fellow99/dsh-desktop
分享 · DeepSeek Harness Hub
fellow99/dsh-desktop

用桌面窗口运行官方 Web 界面,支持三大平台

回到顶部