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

桌面客户端 Oissp/dsh-desktop

DeepSeek Harnessv0.2.0
Oissp46 天前有提交已提供中文文档扫描:高危

在桌面端运行 dsh 引擎,管理会话与凭证

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

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

自动兼容检查未通过:仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Oissp/dsh-desktop
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · desktop
装得上吗
静态安装检查未通过,可能需要源码安装
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 46 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

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

✓npm 包dsh-desktop @ 0.2.0
✓Node 引擎要求 >=22.19.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖要求 0.2.1-rc.2 · 最新 0.2.1-rc.2 兼容
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/20 04:29:30

🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

安装时即执行脚本命令参数由运行时变量拼接读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 124 处,展示前 106 条)
  • 读取本地文件
    scripts/ensure-electron.mjs:29
    if (!existsSync(electronDir)) {
  • 读取本地文件
    scripts/ensure-electron.mjs:37
    if (existsSync(bin)) {
  • 执行外部命令来自配置/变量
    scripts/ensure-electron.mjs:48
    const res = spawnSync(process.execPath, [installScript], {
  • 读取本地文件
    scripts/ensure-electron.mjs:53
    if (res.status === 0 && existsSync(bin)) {
  • 发起网络请求
    adapter/dsh-client.ts:139
    await this.request('session/modelCatalog', {})
  • 发起网络请求
    adapter/dsh-client.ts:193
    return this.request('session/list', { _request: {} })
  • 发起网络请求
    adapter/dsh-client.ts:197
    return this.request('session/create', { request: payload })
  • 发起网络请求
    adapter/dsh-client.ts:201
    return this.request('session/prompt', {
  • 发起网络请求
    adapter/dsh-client.ts:207
    return this.request('session/cancel', { request: payload })
  • 发起网络请求
    adapter/dsh-client.ts:216
    return this.request('session/modelCatalog', {})
  • 写入本地文件
    electron/crash-report.ts:210
    mkdirSync(directory, { recursive: true })
  • 写入本地文件
    electron/crash-report.ts:213
    writeFile(path, content, { encoding: 'utf8', mode: 0o600 }),
  • 读取本地文件
    electron/crash-report.ts:252
    names = readdirSync(directory).filter((n) => CRASH_REPORT_NAME.test(n))
  • 删除本地文件
    electron/crash-report.ts:261
    unlinkSync(join(directory, name))
  • 读取本地文件
    electron/credential-store.ts:22
    if (!existsSync(file)) return {}
  • 读取本地文件
    electron/credential-store.ts:23
    const parsed = JSON.parse(readFileSync(file, 'utf8')) as Record<string, unknown>
  • 写入本地文件
    electron/credential-store.ts:36
    mkdirSync(dirname(file), { recursive: true })
  • 写入本地文件
    electron/credential-store.ts:37
    writeFileSync(file, `${JSON.stringify(map, null, 2)}\n`, 'utf8')
  • 读取本地文件
    electron/dsh-manager.ts:42
    if (existsSync(c)) return c
  • 读取本地文件
    electron/dsh-manager.ts:54
    const pkg = JSON.parse(readFileSync(join(pkgRoot, 'package.json'), 'utf8')) as { version?: string }
  • 执行外部命令表达式求值
    electron/dsh-manager.ts:232
    private async spawn(): Promise<void> {
  • 执行外部命令来自配置/变量
    electron/dsh-manager.ts:245
    const child = spawn(exec, args, {
  • 写入本地文件
    electron/guard-snapshot.ts:38
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    electron/guard-snapshot.ts:49
    if (existsSync(src)) {
  • 读取本地文件
    electron/guard-snapshot.ts:58
    for (const f of readdirSync(dir)) {
  • 删除本地文件递归
    electron/guard-snapshot.ts:59
    rmSync(join(dir, f), { force: true, recursive: true })
  • 读取本地文件
    electron/guard-snapshot.ts:93
    const files = existsSync(lastGood) ? readdirSync(lastGood) : []
  • 读取本地文件
    electron/guard-snapshot.ts:93
    const files = existsSync(lastGood) ? readdirSync(lastGood) : []
  • 写入本地文件
    electron/guard-snapshot.ts:104
    mkdirSync(join(dest, '..'), { recursive: true })
  • 读取本地文件
    electron/guard-snapshot.ts:128
    if (!existsSync(filePath)) return false
  • 读取本地文件
    electron/guard-snapshot.ts:131
    const content = readFileSync(filePath, 'utf8')
  • 写入本地文件
    electron/guard-snapshot.ts:148
    writeFileSync(filePath, rebuilt, 'utf8')
  • 读取本地文件
    electron/log-sink.ts:64
    if (existsSync(dir)) {
  • 读取本地文件
    electron/log-sink.ts:65
    const st = lstatSync(dir)
  • 写入本地文件
    electron/log-sink.ts:68
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 写入本地文件
    electron/log-sink.ts:70
    mkdirSync(dir, { recursive: true, mode: 0o700 })
  • 读取本地文件
    electron/log-sink.ts:97
    for (const f of readdirSync(this.dir)) {
  • 删除本地文件
    electron/log-sink.ts:100
    unlinkSync(join(this.dir, f))
  • 写入本地文件
    electron/log-sink.ts:119
    appendFileSync(path, line, { mode: 0o600 })
  • 读取本地文件
    electron/log-sink.ts:154
    for (const f of readdirSync(this.dir)) {
  • 读取本地文件
    electron/log-sink.ts:171
    const files = readdirSync(this.dir)
  • 读取本地文件
    electron/log-sink.ts:175
    return { name: f, path: p, mtime: statSync(p).mtimeMs }
  • 删除本地文件
    electron/log-sink.ts:182
    unlinkSync(f.path)
  • 删除本地文件
    electron/log-sink.ts:203
    unlinkSync(p)
  • 执行外部命令固定命令
    electron/node-runtime.ts:25
    const out = execFileSync('where', [cmd], { encoding: 'utf8' }).split('\n')[0]?.trim()
  • 执行外部命令固定命令
    electron/node-runtime.ts:32
    const out = execFileSync('sh', ['-c', `command -v ${cmd}`], { encoding: 'utf8' }).trim()
  • 读取本地文件
    electron/node-runtime.ts:59
    if (fromNpm && existsSync(fromNpm)) {
  • 读取本地文件
    electron/node-runtime.ts:66
    if (existsSync(bundled)) {
  • 读取本地文件
    electron/profile-setup.ts:73
    return existsSync(join(pluginTargetDir(dshHome, name), DESKTOP_MANAGED_MARKER))
  • 读取本地文件
    electron/profile-setup.ts:79
    if (!existsSync(join(src, 'index.js'))) {
  • 写入本地文件
    electron/profile-setup.ts:85
    mkdirSync(join(target, '..'), { recursive: true })
  • 写入本地文件
    electron/profile-setup.ts:88
    writeFileSync(join(target, DESKTOP_MANAGED_MARKER), 'desktop-managed\n')
  • 读取本地文件
    electron/profile-setup.ts:90
    if (existsSync(manifestPath)) {
  • 读取本地文件
    electron/profile-setup.ts:91
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
  • 写入本地文件
    electron/profile-setup.ts:96
    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8')
  • 读取本地文件
    electron/profile-setup.ts:110
    if (!existsSync(manifestPath)) {
  • 读取本地文件
    electron/profile-setup.ts:148
    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
  • 写入本地文件
    electron/profile-setup.ts:156
    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8')
  • 删除本地文件递归
    electron/profile-setup.ts:158
    rmSync(pluginTargetDir(dshHome, name), { recursive: true, force: true })
  • 读取本地文件
    electron/settings-store.ts:34
    if (!existsSync(this.file)) return {}
  • 读取本地文件
    electron/settings-store.ts:37
    raw = readFileSync(this.file, 'utf8')
  • 写入本地文件
    electron/settings-store.ts:48
    renameSync(this.file, broken)
  • 写入本地文件
    electron/settings-store.ts:59
    mkdirSync(dirname(this.file), { recursive: true })
  • 写入本地文件
    electron/settings-store.ts:60
    writeFileSync(this.file, JSON.stringify(this.settings, null, 2), 'utf8')
  • 写入剪贴板
    electron/update-lifecycle.ts:289
    clipboard.writeText(debPath ? `sudo dpkg -i "${debPath}"` : 'sudo dpkg -i <下载的 .deb 路径>')
  • 读取本地文件
    electron/update-lifecycle.ts:299
    if (!existsSync(pending)) return null
  • 读取本地文件
    electron/update-lifecycle.ts:300
    const debs = readdirSync(pending).filter((f) => f.endsWith('.deb'))
  • 读取本地文件
    electron/update-lifecycle.ts:303
    debs.sort((a, b) => statSync(join(pending, b)).mtimeMs - statSync(join(pending, a)).mtimeMs)
  • 读取本地文件
    electron/update-state.ts:40
    if (!existsSync(this.file)) return {}
  • 读取本地文件
    electron/update-state.ts:42
    const raw = readFileSync(this.file, 'utf8')
  • 写入本地文件
    electron/update-state.ts:54
    mkdirSync(dirname(this.file), { recursive: true, mode: 0o700 })
  • 写入本地文件
    electron/update-state.ts:56
    writeFileSync(tmp, JSON.stringify(this.data), { mode: 0o600 })
  • 写入本地文件
    electron/update-state.ts:57
    renameSync(tmp, this.file)
  • 读取本地文件
    scripts/after-pack.mjs:32
    if (existsSync(nativeBin)) {
  • 执行外部命令固定命令
    scripts/after-pack.mjs:42
    execFileSync('npm', ['pack', `${scoped}/${pkgName}`, '--pack-destination', projectRoot], {
  • 读取本地文件
    scripts/after-pack.mjs:49
    const tgzFile = readdirSync(projectRoot).find((f) => f.includes(pkgName) && f.endsWith('.tgz'))
  • 删除本地文件递归
    scripts/after-pack.mjs:54
    rmSync(tmpDir, { recursive: true, force: true })
  • 写入本地文件
    scripts/after-pack.mjs:55
    mkdirSync(tmpDir, { recursive: true })
  • 执行外部命令固定命令
    scripts/after-pack.mjs:56
    execFileSync('tar', ['-xzf', tgz, '-C', tmpDir], { cwd: projectRoot, stdio: 'inherit' })
  • 读取本地文件
    scripts/after-pack.mjs:58
    if (!existsSync(unpacked)) throw new Error('tarball 无 package/ 目录')
  • 写入本地文件
    scripts/after-pack.mjs:59
    mkdirSync(scopedDir, { recursive: true })
  • 删除本地文件递归
    scripts/after-pack.mjs:60
    rmSync(pkgDir, { recursive: true, force: true })
  • 删除本地文件递归
    scripts/after-pack.mjs:62
    rmSync(tmpDir, { recursive: true, force: true })
  • 删除本地文件
    scripts/after-pack.mjs:63
    rmSync(tgz, { force: true })
  • 读取本地文件
    scripts/after-pack.mjs:64
    if (!existsSync(nativeBin)) {
  • 读取本地文件
    scripts/after-pack.mjs:77
    const pkg = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8'))
  • 执行外部命令固定命令
    scripts/after-pack.mjs:110
    const all = spawnSync('pnpm', ['list', '--json', '--depth', 'Infinity'], opts)
  • 执行外部命令固定命令
    scripts/after-pack.mjs:111
    const prod = spawnSync('pnpm', ['list', '--prod', '--json', '--depth', 'Infinity'], opts)
  • 读取本地文件
    scripts/after-pack.mjs:227
    if (!existsSync(src)) {
  • 删除本地文件递归
    scripts/after-pack.mjs:250
    rmSync(dest, { recursive: true, force: true })
  • 读取本地文件
    scripts/smoke-test.mjs:32
    if (!existsSync(executable)) {
  • 删除本地文件递归
    scripts/smoke-test.mjs:40
    rmSync(tmpHome, { recursive: true, force: true })
  • 读取本地文件
    scripts/smoke-test.mjs:43
    if (!existsSync(mainJs)) {
  • 读取本地文件
    scripts/smoke-test.mjs:50
    if (!existsSync(join(nmRoot, dep))) {
  • 读取本地文件
    scripts/smoke-test.mjs:62
    if (!existsSync(pkgDir)) {
  • 读取本地文件
    scripts/smoke-test.mjs:64
    } else if (!bin || !existsSync(bin)) {
  • 读取本地文件
    scripts/smoke-test.mjs:74
    if (!existsSync(bundledNode)) {
  • 执行外部命令来自配置/变量
    scripts/smoke-test.mjs:77
    const ver = spawnSync(bundledNode, ['--version'], { encoding: 'utf8' })
  • 执行外部命令来自配置/变量
    scripts/smoke-test.mjs:102
    const child = spawn(executable, ['--no-sandbox', '--disable-gpu'], {
  • 删除本地文件递归
    scripts/smoke-test.mjs:196
    rmSync(tmpHome, { recursive: true, force: true })
  • 读取本地文件
    scripts/verify-deb.mjs:22
    ?? readdirSync('out').map((f) => `out/${f}`).filter((f) => f.endsWith('.deb')).sort()[0]
  • 执行外部命令固定命令
    scripts/verify-deb.mjs:49
    const res = spawnSync(
  • 读取本地文件
    scripts/verify-deb.mjs:58
    console.log(`\n[verify-deb] 校验 ${deb}(${(statSync(deb).size / 1024 / 1024).toFixed(1)} MB)`)
  • 执行外部命令固定命令
    scripts/verify-deb.mjs:83
    const res = spawnSync('dpkg-deb', ['-c', deb], {
  • 读取本地文件
    scripts/verify-deb.mjs:189
    const pkgMeta = JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
  • 发起网络请求
    shared/fetch-timeout.ts:13
    return await fetch(url, { ...init, signal: ctrl.signal })
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

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

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 桌面端运行引擎
  • 管理会话
  • 管理凭证

README

由 DeepSeek 最新模型翻译生成
DSH Desktop DSH Desktop 是 DeepSeek Harness 的桌面客户端(Debian / macOS)。应用内置 dsh 引擎,启动后直接加载官方 Web UI;Electron 负责本地运行时、凭证保护、托盘、自动更新和桌面扩展。 非 DeepSeek 官方产品,与 DeepSeek 无附属关系。 功能 - 内置 dsh 引擎,首次初始化后可直接使用 - 官方 Web UI,支持流式回复、思考过程、工作区、模型和会话管理 - 首启向导配置工作区与模型凭证;引擎崩溃进入恢复模式,可回滚配置快照重启 - 归档会话查看(官方插件面板 plugins/dsh-desktop-archived,标题由桌面侧快照兜底) - 凭证通过 Electron safeStorage 加密保存;启用 CSP、导航限制和单实例锁 - 崩溃环检测 + 配置快照恢复、落盘日志 - 托盘常驻、后台更新检查和下载后安装 - 发布 Debian 13 / amd64 .deb 与 macOS(arm64).dmg / .zip 安装包 安装 从项目的 GitHub Releases 下载对应平台的安装包: - Debian 13 / amd64:dsh-desktop__amd64.deb,然后执行:
展开完整文档(README 剩余 1 节)
DSH Desktop

DSH Desktop 是 DeepSeek Harness 的桌面客户端(Debian / macOS)。应用内置 dsh 引擎,启动后直接加载官方 Web UI;Electron 负责本地运行时、凭证保护、托盘、自动更新和桌面扩展。

非 DeepSeek 官方产品,与 DeepSeek 无附属关系。

功能

- 内置 dsh 引擎,首次初始化后可直接使用
- 官方 Web UI,支持流式回复、思考过程、工作区、模型和会话管理
- 首启向导配置工作区与模型凭证;引擎崩溃进入恢复模式,可回滚配置快照重启
- 归档会话查看(官方插件面板 plugins/dsh-desktop-archived,标题由桌面侧快照兜底)
- 凭证通过 Electron safeStorage 加密保存;启用 CSP、导航限制和单实例锁
- 崩溃环检测 + 配置快照恢复、落盘日志
- 托盘常驻、后台更新检查和下载后安装
- 发布 Debian 13 / amd64 .deb 与 macOS(arm64).dmg / .zip 安装包

安装

从项目的 GitHub Releases 下载对应平台的安装包:

- Debian 13 / amd64:dsh-desktop__amd64.deb,然后执行:

sudo apt install ./dsh-desktop__amd64.deb

- macOS(arm64 / Apple Silicon):dsh-desktop--arm64.dmg,打开后把应用拖入 Applications。

首次启动会初始化 dsh Web profile,时间取决于本机网络与依赖缓存。随后在首启向导中配置模型凭证。

开发

要求:Node.js >=22.19.0、pnpm >=9。项目使用 pnpm 11;推荐通过 Corepack 管理。

corepack enable
pnpm install
pnpm dev

常用命令:

pnpm typecheck # 检查 renderer 与 Electron 两个 TypeScript 项目
pnpm test # 运行 Vitest
pnpm build # 构建 renderer 与 Electron 主进程
pnpm dist # 构建 Debian amd64 .deb 到 out/
pnpm dist:mac # 构建 macOS dmg + zip 到 out/(需在 macOS 上执行)

pnpm dev 会启动 Vite(5173)与 Electron。正式应用界面由本地 dsh Web 服务提供;Vite 页面用于启动、首启向导和引擎故障回退。

架构

React fallback UI (src/) -> preload -> IPC -> Electron main -> adapter -> dsh web engine

- adapter/:dsh Typert Remote 协议适配(HTTP RPC + WebSocket mux)与事件归一化
- shared/:renderer 与主进程共享的稳定类型和 IPC 契约
- electron/:引擎生命周期、IPC、凭证、profile、托盘、更新和桌面桥接
- src/:React 回退 UI(启动、首启向导、恢复页与引擎就绪过渡占位)
- plugins/:注入官方引擎 UI 的伴随插件(归档会话面板)
- scripts/:打包钩子、校验脚本、原生模块定义

License

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

在桌面端运行 dsh 引擎,管理会话与凭证

这是你的仓库?认领条目

回到顶部