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

纯净桌面壳 Icather/dsh-clean-desktop-shell

DeepSeek Harnessv0.1.14
Icather5 天前有提交已提供中文文档扫描:含敏感能力

DeepSeek Harness 的纯净桌面壳DSH 插件形态

39.5/100
综合分
7
GitHub 星标
283
npm 周下载
—/5
用户评分

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-clean-desktop-shell
npm 源 · dsh-clean-desktop-shell 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么[目录]—
dsh 原生插件 · vision
暂无时间戳·判据 →
装得上吗[实装验证]—
曾在 dsh 0.2.1-rc.5 下真实安装成功,但当前 dsh 已更新至 0.2.2-rc.1,本站尚未在新版下复验
L4 · 真实安装等级说明 →
数据截至 2026/10/31·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 5 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

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

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-clean-desktop-shell @ 0.1.14
✓Node 引擎要求 >=20.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖要求 * · 最新 0.2.2-rc.1 兼容
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/6 02:29:09

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 106 处,展示前 89 条)
  • 写入本地文件
    lib/index.js:150
    appendFileSync(logPath, body + '\n')
  • 执行外部命令来自配置/变量
    lib/index.js:161
    const child = spawn(exe, [MAIN_JS], {
  • 执行外部命令固定命令
    lib/common.js:66
    const child = spawn(
  • 读取本地文件
    lib/runtime.js:44
    const meta = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
  • 读取本地文件
    lib/runtime.js:68
    if (existsSync(exe)) {
  • 读取本地文件
    lib/runtime.js:78
    if (existsSync(srcExe) && provisionLocalDist(localSrc, dir)) {
  • 读取本地文件
    lib/runtime.js:84
    if (!existsSync(exe)) {
  • 写入本地文件
    lib/runtime.js:85
    mkdirSync(root, { recursive: true })
  • 读取本地文件
    lib/runtime.js:89
    if (!existsSync(exe)) {
  • 执行外部命令固定命令
    lib/runtime.js:114
    child = spawn('chmod', ['+x', target], { stdio: 'ignore' })
  • 删除本地文件
    lib/runtime.js:130
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    lib/runtime.js:139
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    lib/runtime.js:147
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    lib/runtime.js:156
    rmSync(tmpZip, { force: true })
  • 删除本地文件递归
    lib/runtime.js:159
    rmSync(scratch, { recursive: true, force: true })
  • 删除本地文件递归
    lib/runtime.js:173
    rmSync(scratch, { recursive: true, force: true })
  • 发起网络请求
    lib/runtime.js:196
    const res = await fetch(shasumsUrl, { signal: AbortSignal.timeout(10000) })
  • 读取本地文件
    lib/runtime.js:222
    await pipeline(createReadStream(file), hash)
  • 写入本地文件
    lib/runtime.js:242
    renameSync(payload, dir)
  • 执行外部命令固定命令
    lib/runtime.js:255
    child = spawn('xattr', ['-cr', target], { windowsHide: true, stdio: 'ignore' })
  • 发起网络请求
    lib/runtime.js:294
    const res = await fetch(c.url, { signal: AbortSignal.timeout(3000), method: 'HEAD' })
  • 写入本地文件
    lib/runtime.js:350
    mkdirSync(dest, { recursive: true })
  • 执行外部命令来自配置/变量
    lib/runtime.js:367
    child = spawn(cmd, args, { windowsHide: true, stdio: 'ignore' })
  • 读取本地文件
    lib/icon.js:46
    if (existsSync(rcedit)) return rcedit
  • 读取本地文件
    lib/icon.js:64
    if (!existsSync(ico)) return
  • 读取本地文件
    lib/icon.js:66
    if (existsSync(marker)) return
  • 执行外部命令来自配置/变量
    lib/icon.js:71
    const child = spawn(rcedit, [exe, '--set-icon', ico], {
  • 写入本地文件
    lib/icon.js:80
    writeFileSync(marker, String(Date.now()), 'utf8')
  • 读取本地文件
    electron/config.js:41
    const parsed = JSON.parse(readFileSync(configPath(), 'utf8'))
  • 写入本地文件
    electron/config.js:58
    mkdirSync(dirname(file), { recursive: true })
  • 写入本地文件
    electron/config.js:63
    writeFileSync(tmp, JSON.stringify(cached, null, 2), 'utf8')
  • 写入本地文件
    electron/config.js:65
    renameSync(tmp, file)
  • 删除本地文件
    electron/config.js:70
    rmSync(file, { force: true })
  • 写入本地文件
    electron/config.js:71
    renameSync(tmp, file)
  • 写入本地文件
    electron/config.js:73
    writeFileSync(file, JSON.stringify(cached, null, 2), 'utf8')
  • 读取本地文件
    electron/crashGuard.js:33
    if (statSync(file).size > MAX_BYTES) {
  • 读取本地文件
    electron/crashGuard.js:35
    const tail = readFileSync(file, 'utf8').slice(-KEEP_BYTES)
  • 写入本地文件
    electron/crashGuard.js:36
    writeFileSync(file, tail, 'utf8')
  • 写入本地文件
    electron/crashGuard.js:41
    appendFileSync(file, entry, 'utf8')
  • 发起网络请求
    electron/service.js:117
    const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs), redirect: 'manual' })
  • 执行外部命令来自配置/变量
    electron/service.js:199
    spawned = spawn(command, [...resolved.args, 'web'], {
  • 执行外部命令来自配置/变量
    electron/service.js:382
    const p = spawn(cmd, args, { windowsHide: true })
  • 执行外部命令固定命令
    electron/service.js:408
    const p = spawn('tasklist', ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'], {
  • 执行外部命令来自配置/变量
    electron/service.js:430
    const p = spawn(cmd, args, { windowsHide: true, stdio: 'ignore' })
  • 执行外部命令来自配置/变量
    electron/service.js:544
    const c = spawn(finder, [cmd], { windowsHide: true })
  • 读取本地文件
    electron/service.js:558
    return new Promise((resolve) => access(p, (err) => resolve(!err)))
  • 读取本地文件
    electron/shortcut.js:72
    for (const entry of readdirSync(desktopDir())) {
  • 读取本地文件
    electron/shortcut.js:92
    const ico = existsSync(ICON_ICO) ? ICON_ICO : undefined
  • 读取本地文件
    electron/shortcut.js:121
    icon: existsSync(ICON_ICO) ? ICON_ICO : undefined,
  • 读取本地文件
    electron/update.js:38
    return JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
  • 发起网络请求
    electron/update.js:238
    const res = await fetch(RELEASES_API, {
  • 发起网络请求
    electron/update.js:283
    const res = await fetch(NPM_REGISTRY_API, { signal: AbortSignal.timeout(8000) })
  • 读取本地文件
    electron/update.js:313
    if (!existsSync(join(profileRoot, 'package.json'))) return null
  • 读取本地文件
    electron/update.js:314
    const pm = existsSync(join(profileRoot, 'pnpm-lock.yaml')) ? 'pnpm'
  • 读取本地文件
    electron/update.js:315
    : existsSync(join(profileRoot, 'package-lock.json')) ? 'npm'
  • 读取本地文件
    electron/update.js:316
    : existsSync(join(profileRoot, 'yarn.lock')) ? 'yarn'
  • 读取本地文件
    electron/update.js:317
    : (existsSync(join(profileRoot, 'bun.lockb')) || existsSync(join(profileRoot, 'bun.lock'))) ? 'bun'
  • 执行外部命令固定命令
    electron/update.js:360
    spawn('taskkill', ['/PID', String(child.pid), '/T', '/F'], {
  • 执行外部命令来自配置/变量
    electron/update.js:387
    const child = spawn(cmd, {
  • 读取本地文件
    electron/window.js:57
    const ICON_PATH = existsSync(TASKBAR_ICO)
  • 读取本地文件
    electron/window.js:482
    if (process.platform === 'win32' && existsSync(TASKBAR_ICO)) {
  • 执行外部命令固定命令
    src/host/common.js:66
    const child = spawn(
  • 读取本地文件
    src/host/icon.js:46
    if (existsSync(rcedit)) return rcedit
  • 读取本地文件
    src/host/icon.js:64
    if (!existsSync(ico)) return
  • 读取本地文件
    src/host/icon.js:66
    if (existsSync(marker)) return
  • 执行外部命令来自配置/变量
    src/host/icon.js:71
    const child = spawn(rcedit, [exe, '--set-icon', ico], {
  • 写入本地文件
    src/host/icon.js:80
    writeFileSync(marker, String(Date.now()), 'utf8')
  • 写入本地文件
    src/host/index.js:150
    appendFileSync(logPath, body + '\n')
  • 执行外部命令来自配置/变量
    src/host/index.js:161
    const child = spawn(exe, [MAIN_JS], {
  • 读取本地文件
    src/host/runtime.js:44
    const meta = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8'))
  • 读取本地文件
    src/host/runtime.js:68
    if (existsSync(exe)) {
  • 读取本地文件
    src/host/runtime.js:78
    if (existsSync(srcExe) && provisionLocalDist(localSrc, dir)) {
  • 读取本地文件
    src/host/runtime.js:84
    if (!existsSync(exe)) {
  • 写入本地文件
    src/host/runtime.js:85
    mkdirSync(root, { recursive: true })
  • 读取本地文件
    src/host/runtime.js:89
    if (!existsSync(exe)) {
  • 执行外部命令固定命令
    src/host/runtime.js:114
    child = spawn('chmod', ['+x', target], { stdio: 'ignore' })
  • 删除本地文件
    src/host/runtime.js:130
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    src/host/runtime.js:139
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    src/host/runtime.js:147
    rmSync(tmpZip, { force: true })
  • 删除本地文件
    src/host/runtime.js:156
    rmSync(tmpZip, { force: true })
  • 删除本地文件递归
    src/host/runtime.js:159
    rmSync(scratch, { recursive: true, force: true })
  • 删除本地文件递归
    src/host/runtime.js:173
    rmSync(scratch, { recursive: true, force: true })
  • 发起网络请求
    src/host/runtime.js:196
    const res = await fetch(shasumsUrl, { signal: AbortSignal.timeout(10000) })
  • 读取本地文件
    src/host/runtime.js:222
    await pipeline(createReadStream(file), hash)
  • 写入本地文件
    src/host/runtime.js:242
    renameSync(payload, dir)
  • 执行外部命令固定命令
    src/host/runtime.js:255
    child = spawn('xattr', ['-cr', target], { windowsHide: true, stdio: 'ignore' })
  • 发起网络请求
    src/host/runtime.js:294
    const res = await fetch(c.url, { signal: AbortSignal.timeout(3000), method: 'HEAD' })
  • 写入本地文件
    src/host/runtime.js:350
    mkdirSync(dest, { recursive: true })
  • 执行外部命令来自配置/变量
    src/host/runtime.js:367
    child = spawn(cmd, args, { windowsHide: true, stdio: 'ignore' })
扫描于 2026/11/5(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

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

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 一键启动
  • 后端活性实时监测
  • 托盘快捷启停

DSH 纯净桌面壳:双击就能像普通软件一样一键启动,实时监测后端活性,托盘里快捷启停,零视觉改造。

v0.1.132026-09-12
· 亮点 首启不再被一个装饰性步骤拖住。 任务栏图标补丁(rcedit)此前沿用通用下载预算(600 秒),而且卡在窗口出现之前——GitHub 慢的时候,第一次启动可以十分钟不出窗。现在这一步单独限时 20 秒、整步另有 25 秒硬上限,并与 Electron 运行时下载并行。超时只损失自定义图标,窗口一定会出来。实测(用会挂住的代理卡住该下载):修复前 40 秒内从不弹出,修复后 25.4 秒弹出。 后端掉线不再丢你正在做的事。 响应失败不再被当成进程退出:已加载页面原样保留(草稿、滚动位置、选中内容都在),只在页面内显示连接提示;后端恢复后提示自行消失,全程不重载。只有确认自管进程退出、或你主动停止后端,才切回离线页。 显式声明兼容范围。 补上 engines.node 与 dsh.compatibility(含逐版本实测状态),并把依赖、生命周期脚本、外部服务、失败边界和一次性 profile 的验收记录写进 README——这也是 DSH STORE 上架契约的要求。 · 更新内容 · 修复首次启动可能长时间不出窗:rcedit 下载单独限时 20 秒、整步 25 秒硬上限、与 Electron 运行时下载并行;超时只损失图标。 · 后端响应超时不再直接跳离线页:改为页内提示并保留已加载页面。 · 区分「探测结果」与「确认退出」:探测超时不再被当成退出(保留 1,500 ms 超时)。 · 接入真实客户端连接状态与重连入口(shellAPI.connectionReport / onReconnectRequest);手动与自动重试共用同一次检查。 · macOS:拖拽条由 28px 收窄到 12px,不再吞掉顶部工具栏控件的点击。 · 显式声明 engines.node: ">=20.0.0" 与 dsh.compatibility(0.1.5-rc.1 标记 compatible,其余 unknown),并补充依赖 / 权限 / 外部服务 / 失败边界披露与一次性 profile 验收记录。 · 升级 · 安装包用户:应用内「检查更新」即可(Windows 走 electron-updater)。 · 插件用户:dsh plugin --profile web add dsh-clean-desktop-shell@0.1.13,或把 profile 里的版本约束改到 ^0.1.13 后 pnpm install。 · DSH 版本:0.1.2 及之后(BrowserAuth launch token)与 0.1.2 之前都支持;0.1.5-rc.1 上做过完整端到端验收。 · 致谢 · @lispv —— 插件形态冷启动的 launch-token 认证、标题栏契约、掉线保留页面、macOS 拖拽条点击区(#5、#6,commit 署名保留) · @lzd-loostone —— 保留完整 launch token URL(#4) · @e16a —— 精准定位黑窗根因的 issue(#2) 已加入 CONTRIBUTORS.md。 --- 安装包仍未签名(无代码签名证书),Windows SmartScreen / macOS Gatekeeper 的警告来自此,与代码无关。macOS 侧仍欢迎帮忙验证安装流程。
v0.1.112026-08-31
· macOS 用户请注意 / Attention macOS users 当前开发者没有 macOS 实机,macOS 相关修复尚未经过真机验证: · 插件形态:若打不开窗口,请查看 ~/.dsh/desktop-shell-launch.log 并贴到 Issue。 · .dmg 安装包:未签名、未公证。首次打开若提示「已损坏,无法打开」,请在终端执行: xattr -cr "/Applications/DSH Clean Desktop Shell.app" 然后右键 → 打开。 诚挚邀请有 Mac 环境的开发者参与验证与签名配置;贡献者将加入 CONTRIBUTORS.md。 --- · What changed (v0.1.11) · fix: checkForUpdate() crashed silently on Windows plugin mode (parseVersion ReferenceError after rename to coerceVersion in v0.1.10 maturity overhaul) · fix: tray "检查更新" now correctly routes plugin mode to npm registry check (was falling through to GitHub Releases) · refactor: unify all update-check paths through checkForUpdatesAuto(), removing duplicated inline handler in tray.js
v0.1.72026-08-31
· macOS 用户请注意 / Attention macOS users 当前开发者没有 macOS 实机,v0.1.7 的 macOS 修复尚未经过真机验证: · 插件形态:修复了无法定位 Electron.app 的静默失败;若仍打不开,请查看 ~/.dsh/desktop-shell-launch.log 并贴到 Issue。 · .dmg 安装包:未签名、未公证。首次打开若提示「已损坏,无法打开」,请在终端执行: xattr -cr "/Applications/DSH Clean Desktop Shell.app" 然后右键 → 打开。 诚挚邀请有 Mac 环境的开发者参与验证与签名配置;贡献者将加入 CONTRIBUTORS.md。 --- · What changed · fix: correct Electron.app path on macOS (the silent launch failure) · fix: robust zip extraction with multi-strategy fallback + payload detection · fix: use macOS template tray icon · fix: hide Windows-only shortcut menu on macOS/Linux · improvement: write launch diagnostics to ~/.dsh/desktop-shell-launch.log on failure
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-clean-desktop-shell DeepSeek Harness 的纯净桌面壳(DSH 插件形态) 只做一件事:给已配置好的 DSH Web 加一层干净的桌面窗口——系统托盘、单实例、像普通软件一样用。无毛玻璃、无花哨材质,纯净。 English · 这是什么 dsh-clean-desktop-shell 是一个 DSH 插件形态 的纯净桌面壳:它给已经跑起来的 DSH Web(默认 http://127.0.0.1:3080)套一层原生桌面窗口——系统托盘、单实例,像普通桌面软件一样使用。不做任何视觉改造:不加毛玻璃、不改界面,纯粹是"窗口壳"。 与生态里其他桌面端方案的最大区别: | | 其他桌面端(如 dsh-desktop 系列) | 本插件 | | 形态 | 独立 Electron 应用,自带独立 profile | DSH 插件,挂载进现有 profile | | Profile | 新建 desktop profile,插件/配置要重装 | 复用现有 web profile,零迁移 | | 视觉改造 | 自绘标题栏 / 毛玻璃等 | 零改造,纯净窗口壳 | | 跟随上游 | 固定版本 | 已适配 DSH 0.1.2 BrowserAuth(冷启动自动认证;不接管、不杀外部后端) | 核心亮点
展开完整文档(README 剩余 1 节)
dsh-clean-desktop-shell

DeepSeek Harness 的纯净桌面壳(DSH 插件形态)

只做一件事:给已配置好的 DSH Web 加一层干净的桌面窗口——系统托盘、单实例、像普通软件一样用。无毛玻璃、无花哨材质,纯净。

English ·

这是什么

dsh-clean-desktop-shell 是一个 DSH 插件形态 的纯净桌面壳:它给已经跑起来的 DSH Web(默认 http://127.0.0.1:3080)套一层原生桌面窗口——系统托盘、单实例,像普通桌面软件一样使用。不做任何视觉改造:不加毛玻璃、不改界面,纯粹是"窗口壳"。

与生态里其他桌面端方案的最大区别:

| | 其他桌面端(如 dsh-desktop 系列) | 本插件 |
| 形态 | 独立 Electron 应用,自带独立 profile | DSH 插件,挂载进现有 profile |
| Profile | 新建 desktop profile,插件/配置要重装 | 复用现有 web profile,零迁移 |
| 视觉改造 | 自绘标题栏 / 毛玻璃等 | 零改造,纯净窗口壳 |
| 跟随上游 | 固定版本 | 已适配 DSH 0.1.2 BrowserAuth(冷启动自动认证;不接管、不杀外部后端) |

核心亮点

① 像双击桌面应用一样,一键启动 DSH

不用开终端、不用记命令。双击桌面快捷方式,DSH 窗口立刻弹出,和启动任何一个普通软件一样自然:

- 安装包自动创建桌面快捷方式;插件形态首次运行询问 + 托盘「创建桌面快捷方式」一键补建
- 双击即出窗——窗口不等后端、不做启动等待
- 单实例:重复双击只聚焦已有窗口,绝不重复开壳

② 后端活性实时监测 · 快捷手动自主启停

托盘实时显示后端状态(运行中 / 启动中 / 未运行 / 错误),一键启停:

- 响应监测:保留 1,500 ms 探测超时。响应失败不等于进程退出:短暂或持续失败都保留已加载页面,只显示连接提示。
- 原页重连:结合 HTTP 与客户端连接状态,通过客户端自身的连接服务恢复同步,不自动重载。自动重试沿用 4 秒探测节奏;手动重试共用防重复请求检查。
- 快捷启停:托盘右键一键启动 / 重启 / 关闭后端(带进度弹窗);「关闭后端」真正停掉 3080 端口上的服务,含外部启动的实例

使用

1. 若安装过插件,命令行启动 dsh 自动弹出桌面窗口;也可通过插件创建的桌面快捷方式双击,媲美原生桌面端的体验。
2. 使用原网页端的一切功能。
3. 托盘右键可以进行详细设置。正常连接时保持原网页;连接异常时显示恢复提示。

后端启停等管理操作在托盘右键:

- 启动 / 重启 / 关闭后端(带进度弹窗;关闭会真正停掉 3080 上的服务,包括外部启动的实例)
- 自动探测后端 · 设置后端安装文件夹(默认自动探测定位)
- 刷新窗口 · 创建桌面快捷方式 · 检查更新 · 仓库主页

窗口的可靠性(保留页面的连接恢复):

- 双击启动立即出窗,不等后端就绪
- 启动时尚无可用页面,显示「后端未连接」页;后端启动就绪后加载
- 只有确认自管进程退出或明确停止已识别的后端,才切回离线页;外部后端失联仍按响应故障提示
- 持续故障提供「立即重试」与「重新加载页面」;后者是会丢失未保存页面状态的显式操作
- 离线页内置快捷按钮:重新加载 / 启动后端 / 自动探测后端 / 设置后端安装文件夹

壳不会因探测失败重建已加载文档,但第三方插件自身的断线处理仍可能改变其局部视图。确认退出与显式重载仍会离开当前页面。

macOS 状态(v0.1.7 重要说明)

v0.1.7 修复了插件形态在 macOS 上无法定位 Electron.app 路径的问题(该 bug 导致窗口在 Mac 上完全静默失败)。

但当前开发者没有 Mac 实机,以下事项仍然依赖 Mac 用户验证/贡献:

- .dmg 安装包未签名、未公证:Apple 要求年度开发者计划($99/年)才能给安装包签名+公证。首次打开 .dmg 里的应用,很可能提示「已损坏,无法打开」或「无法验证开发者」。这不是应用本身损坏,是 Gatekeeper 拦截了未签名应用。
- 临时解决:xattr -cr "/Applications/DSH Clean Desktop Shell.app",然后右键 → 打开。
- 长期解决:需要一位有 Apple Developer 账号的 Mac 合作者协助签名/公证,或长期把 .dmg 安装体验写为「需要右键打开 / 执行 xattr」。
- Electron.app 解压后的可执行位、quarantine 扩展属性等只有真机能确认行为是否完全正确。
- 如果窗口还是没弹出来:启动失败时会把诊断信息写到 DSH home 下的 desktop-shell-launch.log:

cat "${DSH_HOME:-$HOME/.dsh}/desktop-shell-launch.log"

把内容贴到 Issue 即可——里面记录了平台、架构、Node 版本、DSH home、运行时目录和具体报错。没有界面时,这是唯一能回传的信息。

诚挚邀请有 Mac 环境、愿意一起打磨的同学参与:能帮忙验证安装流程、补充签名配置、或者把开机自启/登录项做进 Electron 托盘,欢迎直接提 PR 或在 Issue 里 @ 我,我会把你加入 CONTRIBUTORS.md。

安全与权限:它到底做了什么

第三方安全扫描器(如 dsh-xray)会给本项目打出「高能力 + 敏感行为」的评级。这个评级没有误报——列出的每一条都属实,但每一条都有明确且必要的原因。既然要装进你的机器,就该摊开讲清楚。

| 行为 | 为什么必须这么做 | 代码位置 |
| 执行系统命令(spawn) | 壳的核心功能就是启动 / 重启 / 停止 dsh web 后端,以及探测 3080 端口占用。不调用系统命令无法实现。 | electron/service.js |
| 下载约 100MB 的 Electron 运行时 | 首次启动需要。两个源按网络环境自动竞速(3 秒超时):github.com 与 npmmirror.com——后者是国内镜像,CN 网络下通常更快。 | src/host/runtime.js |
| 访问 api.github.com | 仅用于托盘「检查更新」拉取最新 Release 信息。 | electron/update.js |
| 读取环境变量 | 只用于定位路径和功能开关:DSH_HOME(DSH 主目录)、DSH_SHELL_ELECTRON_DIR(复用本地 Electron,跳过下载)、DSH_SHELL_AUTO_LAUNCH=0(关闭自动弹窗)、USERPROFILE / APPDATA(Windows 下定位 dsh.cmd 与快捷方式目录)。 | src/host/common.js、src/host/index.js、electron/shortcut.js |
| 修改 DSH 运行时(cordis.patch.yml) | DSH 官方的插件注册机制,所有 DSH 插件都靠它挂载,并非本项目特有行为。 | cordis.patch.yml |

边界:不上传任何数据、不读取会话内容、不回传遥测。全部网络请求只有上面两类(下载运行时 / 查更新),且都可通过设置 DSH_SHELL_ELECTRON_DIR 完全避免。

安装包的未签名警告(Windows SmartScreen、macOS Gatekeeper)来自缺少代码签名证书,与上述行为无关。

兼容性与运行边界

扫描器给出的「高能力」评级来自上一节那四类能力(文件 / 网络 / 命令 / 凭据)。下面把兼容范围、依赖、外部服务与失败边界摊开声明,供人工审阅——声明不等于验收,逐条注明证据。

兼容范围

| 项 | 声明 | 依据 |
| Node.js | >=20.0.0(engines.node) | host 半边用全局 fetch 与 AbortSignal.timeout;Electron 半边跑在 Electron 33 内嵌的 Node 20.18 上。没有更新 API 的依赖。 |
| DSH | >=0.1.1 <0.2.0(dsh.compatibility.dsh) | 面向 0.1.x 的插件契约;0.1.2 之前没有 BrowserAuth,host 半边对该代有显式守卫(拿不到 authenticatedUrl() 时照常拉起窗口,只是不带 bootstrap URL)。 |

dsh.compatibility.dshReleases 逐版本标注实测状态:

| DSH 版本 | 状态 | 证据 |
| 0.1.5-rc.1 | compatible | 真机端到端:token 横幅 → 插件自动弹壳 → 窗口渲染 UI 并写入 dsh-auth cookie;掉线保留页面、确认退出切离线页均实测通过 |
| 0.1.5-rc.2、0.1.5-alpha.2 | unknown | 未做运行验收 |
| 0.1.1-rc.2 | unknown | 「0.1.2 之前」这条代码路径有独立断言(真实 host 模块 + 无 authenticatedUrl 的 connection),但没在真实该版本上跑完整验收 |

依赖与生命周期脚本

| 类型 | 内容 |
| 运行时依赖 | electron-updater(托盘「检查更新」)、semver(版本比较)。两者都只在 Electron 半边使用;host 半边不加载任何第三方依赖。 |
| peer 依赖 | @deepseek-ai/dsh(可选)——宿主由 DSH 提供,不随本包安装。 |
| 开发依赖 | electron、electron-builder、sharp、png-to-ico(仅构建与图标生成)。 |
| 生命周期脚本 | 无。 本包不声明 preinstall / install / postinstall / prepare;scripts 只有 build / check / dev / icons / pack 这些手动入口。 |
| 安装期脚本例外 | pnpm.allowScripts 放行了 electron 自身的 postinstall(它要下载 Electron 二进制)。这是依赖的脚本、不是本包的,且只在装开发依赖时出现。 |

外部服务

| 端点 | 何时访问 | 失败后果 |
| github.com / npmmirror.com | 首次准备 Electron 运行时,两源 3 秒竞速下载(约 100MB) | 两源都失败 → 窗口不启动,并写入 <DSH_HOME>/desktop-shell-launch.log(含平台、错误原文与替代方案) |
| github.com(rcedit) | 首次给 runtime exe 打任务栏图标(约 1.3MB) | 下载限时 20 秒、整步限时 25 秒,超时只损失自定义图标,不影响出窗;下次启动重试 |
| api.github.com | 托盘「检查更新」/ 自动更新 | 静默失败,不影响使用 |
| 其他 | 无。不上传数据、不读会话内容、无遥测。 | — |

失败边界

- 后端起不来:显示离线页并每 2.5 秒重探,后端一通立即加载。
- 后端掉线:保留已加载页面 + 页内提示(不重载、不丢草稿);只有确认进程退出或用户主动停止才切离线页。
- 非 Windows:任务栏图标补丁直接跳过(patchExeIcon 首行 isWin 判断)。
- 找不到 dsh CLI:托盘「设置后端文件夹」手动指定,或设 DSH_BACKEND_DIR。

一次性 Profile 验收记录

在一台干净的一次性 DSH home + 一次性 profile 上跑完整安装 / 启动 / 卸载循环(不触碰日常 profile),DSH 0.1.5-rc.1、Windows 11:

| 步骤 | 命令 | 结果 |
| 安装 | dsh plugin --profile web add file:<repo> | 退出码 0(pnpm 2.2s);--dump-config 出现插件条目 |
| 启动 | dsh web --no-open | 打印 launch token 横幅;裸 / → 401、带 token → 303 + Set-Cookie: dsh-auth-…、带 cookie → 200;首页 manifest 含 dsh-clean-desktop-shell/client.js(插件在前端已挂载) |
| 插件拉起窗口 | 同上 | host 半边完整走通:inject(['connection']) 触发 → webServer 可解析 → 铸出 launch URL → launchShell() 被调用(用临时探针逐点断言)。窗口是否可见未在本环境验收:验收机是 CI 式无 GPU 沙箱,Electron 报 FATAL: GPU process isn't usable 后退出,与本插件无关(同一台机器上不带任何 GPU 参数的空白 Electron 应用同样退出,带 --in-process-gpu 则正常)。窗口渲染本身在此前用带 GPU 参数的 harness 单独验证过。 |
| 卸载 | dsh plugin --profile web remove dsh-clean-desktop-shell | 退出码 0(pnpm 1.4s);--dump-config 中插件条目归零 |
| 回滚 | 卸载即回滚:dsh.profile.bundles 与 dependencies 同步移除,后端与窗口行为回到未安装状态 | — |

安装

方式一:从 Release 下载安装包(想要独立桌面应用的用户)

- Windows:下载 DSH-Clean-Desktop-Shell-Setup-<版本>.exe
- macOS:下载 DSH-Clean-Desktop-Shell-<版本>.dmg(Intel)或 -arm64.dmg(Apple Silicon)

安装包会自动创建桌面快捷方式,并提供系统托盘等完整桌面体验。

- Windows:首次运行安装包可能触发 SmartScreen 警告——这是未签名程序的正常现象,不是病毒,见下方「Windows SmartScreen 警告说明」。
- macOS:.dmg 未签名/未公证,首次打开可能触发 Gatekeeper。见上方「macOS 状态」。

方式二:作为 DSH 插件安装(DSH 生态用户)

dsh plugin --profile web add dsh-clean-desktop-shell

重启 dsh web 后,桌面壳窗口会自动弹出(首次运行需联网准备 Electron 运行时,约 1-2 分钟)。

方式二得到的是"随 DSH 启动的桌面壳":窗口由插件在 dsh web 启动时自动拉起,不产生独立安装包 / 桌面图标。想要可双击启动、带桌面快捷方式和自动更新的独立应用,请用方式一。两种方式的核心窗口体验一致。

桌面壳需要本机有可用的 dsh web 服务(或配置的远程地址)。见下方「使用」。

Windows SmartScreen 警告说明

为什么会看到警告?

我们的安装包没有代码签名证书(个人开源项目暂未购买,证书年费约数百美元)。Windows 的 Microsoft Defender SmartScreen 是一个信誉系统——它根据"下载量 + 干净运行的记录"判断一个程序是否可信。对下载量少、未签名的 exe,它无法确认信誉,就会警告。这不代表文件有病毒:本项目完全开源,代码可审阅,也可本地构建比对(见下)。

Edge 下载时会看到:

下载面板里该文件被标记为"不常下载的文件",需要手动保留:

1. 悬停下载项,点击右侧的 ... 菜单
2. 选择「保留」(Keep)
3. 弹窗确认,选择「仍要保留」(Keep anyway)

双击安装时会看到:

蓝色对话框「Windows 已保护你的电脑」——Microsoft Defender SmartScreen 阻止了无法识别的应用启动:

1. 点击「更多信息」(More info)
2. 核对文件名确实是 DSH-Clean-Desktop-Shell-Setup-<版本>.exe
3. 点击「仍要运行」(Run anyway)

备选:一次性解除锁定(推荐)

右键安装包 → 属性 → 常规 → 底部勾选「解除锁定」→ 确定。之后双击不再有警告。

或 PowerShell 批量解除:

Unblock-File -Path "$env:USERPROFILE\Downloads\DSH-Clean-Desktop-Shell-Setup-*.exe"

关于文件安全性的说明

安装包由 GitHub Actions 从本仓库源码自动构建(见 .github/workflows/build.yml),代码完全开源可审阅。如仍有疑虑,可自行 git clone 后按「开发」一节本地构建比对,或稍等下载量积累——SmartScreen 信誉度上去后警告会自动消失。

说明:代码签名证书(EV 或 Azure Trusted Signing)可以彻底消除这个警告,但需要付费且对个人开源维护者不划算。本仓库会在条件允许时考虑接入签名。

架构

┌────────────── 内核(dsh web / headless 服务)──────────────┐ │ 会话 · Agent · 插件 · 记忆 都在这层,与界面解耦 │ └───────────────────────────┬──────────────────────────────┘ │ http://127.0.0.1:3080(或远程地址) ▼ ┌───────────────────────────────────────────────────────────┐ │ dsh-clean-desktop-shell(Electron 壳) │ │ 托盘 · 单实例 · 离线自动重连 · 桌面快捷方式 │ │ │ │ 同一份壳代码,两种分发形态: │ │ ├─ 安装包版:独立 exe,双击即用,自动更新 │ │ └─ 插件版:随 dsh web 启动自动弹窗(自管 Electron 运行时)│ └───────────────────────────────────────────────────────────┘

- 壳 / 内核分离:壳只负责窗口、托盘、后端管理;会话、Agent、插件、记忆都在内核层,与界面解耦。
- 默认:加载本地 127.0.0.1:3080(已配置好的 web profile,零迁移)。
- 可配远程:在设置里填入任意远程 DSH 地址,壳只当窗口——手机 / Linux / 其他设备通过浏览器或 PWA 也能接入内核,壳本身不绑定本地服务。
- 同一套壳代码,两种分发形态:安装包版(独立 exe)与插件版(随 dsh web 启动)共用 electron/ 壳代码,仅运行时来源与启动方式不同(见「安装」)。

平台矩阵

| 平台 | 壳 | 状态 |
| Windows | ✅ Electron(无边框 + 原生窗口按钮) | 已发布(NSIS 安装包) |
| macOS | ✅ Electron(hiddenInset) | 已发布(CI 构建 Intel + Apple Silicon DMG) |
| Linux | —(浏览器 / PWA 直连内核) | 不做 |
| Termux / 手机 / 平板 | —(headless / PWA 直连内核) | 由内核远程访问支持 |

开发

npm install
npm run build # 构建插件 bundle
npm run dev # 启动壳(开发模式)
npm run pack # 打包 NSIS (Win) / DMG (mac)

npm run check 运行语法和 Node 自检。用 Electron 运行 scripts/selftest-recovery.mjs 还会验证真实启动失败后的重试、连续手动重试及即时失败不会形成重连循环;建议通过 --user-data-dir 指定临时目录。

以下为 sh/bash 示例;ELECTRON 指向预先安装的 Electron 可执行文件。用独立 user-data 目录运行,不启动日常应用、不发送模型请求:

test -n "$ELECTRON" && "$ELECTRON" --user-data-dir="$(mktemp -d)" scripts/selftest-recovery.mjs

该入口使用临时无执行权限文件与随机端口的本地页面验证恢复边界;不是完整真实会话或性能验收的替代品。

更新历史

0.1.14

- 修复「点击创建桌面快捷方式没反应」:shell.writeShortcutLink 在若干失败场景下是抛异常而不是返回 false,而托盘菜单与首次运行提示两处调用都没有接住它,异常变成无人处理的 Promise rejection,界面上什么都不显示。现在两处都捕获异常并显示错误原文。
- 快捷方式提示会给出实际落盘目录:桌面可能被 OneDrive 重定向(…\OneDrive\桌面),此时快捷方式确实创建成功、只是不在用户习惯查看的「桌面」文件夹里。成功与失败弹窗现在都会写明路径,这个歧义不再存在。
- 兼容性声明新增 dshReleases["0.1.5-rc.3"] = "compatible"——该状态来自一台真实 Electron 窗口对着 0.1.5-rc.3 后端的端到端复验(launch token 交换 → 落到干净根路径 → 真实 UI 渲染 → dsh-auth cookie 落位),未经验证的版本一律保持 unknown。
- 修正 package-lock.json 中陈旧的 version 字段(0.1.10 → 0.1.13)。

0.1.13

- 修复首次启动可能长时间不出窗:任务栏图标补丁(rcedit)此前沿用通用下载预算(600 秒),GitHub 慢时能把窗口拖到十分钟才出现。现在它单独限时 20 秒,整步另有 25 秒硬上限,并与 Electron 运行时下载并行;超时只损失自定义图标,不再影响出窗。
- 显式声明兼容范围:engines.node: ">=20.0.0" 与 dsh.compatibility(含逐版本实测状态),并补齐依赖、生命周期脚本(无)、外部服务、失败边界与一次性 profile 的安装 / 启动 / 卸载验收记录——满足 DSH STORE 的上架契约。
- 后端响应超时不再直接跳离线页:改为页内提示并保留已加载页面,草稿/滚动/选中状态不受影响。
- 区分「探测结果」与「确认退出」:只有进程真的退出或用户主动停止才算后端下线,探测超时不再被当成退出;探测超时保留 1,500 ms。
- 接入真实客户端连接状态与重连入口(shellAPI.connectionReport / onReconnectRequest):HTTP 活着但页面 WebSocket 已断的情况不再被掩盖;手动与自动重试共用同一次检查,避免即时失败反馈成重连循环。

0.1.12

- 适配 DSH 0.1.2 BrowserAuth,插件形态一并修复:插件冷启动时由 host 延迟注入 Connection 服务、等 Loader settle 后铸造本进程 launch URL 交给 Electron,首次进入自动完成 ?token= → Cookie 认证,无需手动重启后端。此前只有「壳自己启动后端」这条路能拿到 token,插件形态(dsh web 自动弹壳)与「先手动跑 dsh web 再开壳」都会停在未认证页。
- Electron 自管后端(启动 / 重启)沿用 stdout launch URL bootstrap:严格匹配 dsh web: 横幅并保留完整 ?token=(只接受 loopback,token 属本机进程机密),对 0.1.2 之前的裸 URL 保留回退解析以免退化成等待超时;外部已运行的 backend 不会被擅自重启或杀掉。
- 修复启动竞态:后端端口在 Loader settle 前即开始应答(4xx),离线页重连探针不再抢先加载裸 URL 而丢掉 token bootstrap。
- 「刷新窗口」与窗口重载改用当前进程的 launch URL:launch token 每次重启都会轮换,写进 config.json 反而会在下次重启后失效。
- 新增桌面标题栏契约:页面 URL 带上 dsh-desktop-mode / dsh-desktop-platform / dsh-desktop-titlebar-inset,供 better-sidebar 等可停靠面板按拖拽条高度避让。
- 兼容旧版 DSH:0.1.2 之前没有 BrowserAuth,也没有 mint launch URL 的接口——此时窗口照常拉起(只是不带 bootstrap URL),不会因为缺少该接口而完全不出窗。

0.1.10

- 版本比较改用 semver(industry-standard semver.coerce + semver.gt),替换手写元组比较。
- 所有 HTTP 超时改为 AbortSignal.timeout(标准自清理 API,无泄漏风险)。
- 配置持久化改为原子写入(tmp + rename),崩溃/断电不会留下截断的 config.json。
- 移除代码中硬编码的 D:\deepseek-harness\prod\... 开发机路径:改用 config backendPath + DSH_BACKEND_DIR 环境变量 + npm 全局目录候选。
- Windows 后端进程停止改用 taskkill /T /F 树杀(.cmd shim 留下的孤儿 node 进程不再占端口);POSIX 先 SIGTERM 再 SIGKILL 优雅降级。
- 快捷方式管理整体替换为 Electron 原生 shell.writeShortcutLink / readShortcutLink,移除 PowerShell + COM 依赖(顺带修复 OneDrive 桌面重定向问题)。
- 新增进程级 crash guard:uncaughtException / unhandledRejection 写入 userData/shell-crash.log(128KB 上限自动截断),便于附在 bug 报告中。
- Electron runtime 下载后新增 SHA-256 完整性校验(对比源站点 SHASUMS256.txt),损坏文件自动跳到下一源重试。
- 冗余加固:后端 stdout/stderr 缓冲 64KB 环形截断;配置字段类型校验并自动丢弃未知键;窗口离线页检测从 includes('error.html') 改为精确 URL 比对。
- 自检脚本 npm run check 扩展到覆盖全部 17 个发布 JS 文件的语法门禁(此前只检查 lib/index.js)。

0.1.9

- 插件形态发现新版本时新增「立即更新」一键更新:从安装位置旁的 lockfile 推断实际使用的包管理器(pnpm/npm/yarn/bun),按命令变体链逐条尝试(含 corepack 兜底),吸收 PATH 与 pnpm 版本差异;更新后校验磁盘版本,成功 / 未变化 / 失败三态弹窗,失败时附已试命令与输出(可复制)。
- 更新弹窗同时内嵌可复制的手动更新命令,并保留 DSH 插件市场入口;Windows 下经 shell:true + windowsHide 执行,兼容 .cmd shim 与 PowerShell / cmd 环境。

0.1.8

- 插件形态(npm 安装)的更新检查改查 npm registry 的 dist-tags.latest,与本地版本同源对比;不再错爬 GitHub /releases/latest(此前 GitHub Latest 标记未及时挪动时会弹出「当前 0.1.7 已是最新(v0.1.6)」的自相矛盾提示)。
- 打包桌面应用仍走 GitHub Releases;修复「已是最新」弹窗括号内重复显示版本号的文案。

0.1.7

- 修复 macOS 上窗口完全打不开的静默失败:Electron 的 macOS 包是 Electron.app 应用包,可执行文件位于 Electron.app/Contents/MacOS/Electron;此前按 Linux 布局去找顶层 electron,导致 Mac 上必然启动失败且无任何提示。
- 解压改为多策略回退(ditto / unzip / tar),并校验产物;解压后补齐可执行位,清除 macOS quarantine 扩展属性。
- 启动失败不再只写日志:诊断信息落盘到 desktop-shell-launch.log,并在提示中给出完整路径。
- macOS 托盘改用模板图,深浅色菜单栏自适应;非 Windows 平台隐藏「创建桌面快捷方式」。
- 新增 CONTRIBUTORS.md,公开招募 Mac 合作开发者(代码签名 / 公证 / 实机验证)。

0.1.6

- 修复插件形态下「检查更新」误报 Electron 运行时版本号的问题。

0.1.5

- 插件 host 侧重构为聚焦模块。
- 补全 package.json 元数据(repository / homepage / bugs),清理遗留的开机自启字段。
- README 调整:使用前置、架构反映两种形态、平台矩阵置顶。

0.1.4

- 分支二(插件市场分发)正式可用:dsh plugin add 装插件 → 重启 dsh web → 桌面壳自动弹出;Electron 运行时由插件自管理(本地复用 / 按网络环境自动选源下载)。
- 桌面快捷方式:首次启动询问创建 + 托盘「创建桌面快捷方式」一键添加(安装包与插件两种形态均支持)。
- 图标:Windows 任务栏 / macOS Dock 均显示鲸鱼图标(裸运行时场景)。
- 移除开机自启(两种形态统一为纯手动启动)。

0.1.2

- Windows 自动更新:托盘「检查更新」改为后台下载 + 进度显示 + 重启安装(electron-updater);macOS 仍为手动下载。
- 移除启动时自动拉起后端(改纯手动,与「关闭后端」不冲突)。
- 新增贡献者全套文件(CONTRIBUTING / 行为准则 / 安全策略 / Issue 与 PR 模板)。
- README:新增 Windows SmartScreen 安装指引;澄清「插件注册 ≠ 安装桌面应用」。

0.1.1

- 后端生命周期:修复 Windows 下启动报 spawn EINVAL、卡「启动中」的问题;「关闭后端」现在能真正停掉后端(含外部启动的实例);启动 / 重启 / 关闭带进度弹窗。
- 窗口可靠性:双击立即出窗;后端关闭窗口立刻切离线黑屏;后端恢复自动重连(Edge 式即时刷新)。
- 离线页自助:重新加载 / 启动后端 / 自动探测后端 / 设置后端安装文件夹。
- 托盘:新增「刷新窗口」;macOS 构建发布(Intel + Apple Silicon DMG)。

0.1.0

- 初始版本:Electron 壳骨架,系统托盘/单实例,DSH 插件挂载。

贡献

欢迎任何形式的贡献——修 bug、加功能、改进文档都行。请先阅读 CONTRIBUTING.md(含项目结构、开发约定、提交规范、PR 流程),并遵守 CODE_OF_CONDUCT.md。安全漏洞请走 SECURITY.md 的私密报告流程。

致谢

- DeepSeek Harness —— 内核本体。
- 架构参考 Hermes Agent Desktop 的壳/内核分离设计。
预览分享卡片长什么样 ↓Icather/dsh-clean-desktop-shell
分享 · DeepSeek Harness Hub
Icather/dsh-clean-desktop-shell

DeepSeek Harness 的纯净桌面壳DSH 插件形态

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部