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

智能体桌面客户端 tscodeplus/dsh-desktop

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

体积小、速度快的 DeepSeek Harness 桌面端。

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

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

自动兼容检查未通过:仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装。以下命令仍可尝试,但可能失败。
无法用 dsh 插件命令安装(仓库内无 dsh 插件清单)
git clone https://github.com/tscodeplus/dsh-desktop.git
按该仓库 README 的原生方式安装;若作者另行发布了 DSH 插件包,请以其文档为准

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · desktop
装得上吗
作者未把包发布到 npm,只能用源码安装
插件本身没问题,是分发方式不同
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 6 天前
档位由哪些信号合成

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

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

仓库根目录及浅层子目录均无 dsh 插件清单,无法用 dsh 插件安装命令安装

展开查看检查明细 ↓

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

✗npm 包dsh-desktop(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明

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

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/11/2 11:44:52

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

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

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 65 处,展示前 64 条)
  • 读取本地文件
    desktop/sidecar/src/config.ts:44
    const raw = JSON.parse(readFileSync(configPath(), 'utf8')) as Partial<DesktopConfig>;
  • 写入本地文件
    desktop/sidecar/src/config.ts:61
    mkdirSync(dirname(p), { recursive: true });
  • 写入本地文件
    desktop/sidecar/src/config.ts:63
    writeFileSync(tmp, JSON.stringify(cfg, null, 2), 'utf8');
  • 写入本地文件
    desktop/sidecar/src/config.ts:64
    renameSync(tmp, p);
  • 读取密钥环境变量
    desktop/sidecar/src/control-server.ts:205
    const token = process.env.DSHD_CONTROL_TOKEN ?? '';
  • 发起网络请求
    desktop/sidecar/src/control-server.ts:208
    await fetch(`http://127.0.0.1:${port}${pathname}`, {
  • 发起网络请求
    desktop/sidecar/src/control-server.ts:720
    const r = await fetch(url, {
  • 写入本地文件
    desktop/sidecar/src/control-server.ts:761
    mkdirSync(join(home, 'data'), { recursive: true });
  • 写入本地文件
    desktop/sidecar/src/control-server.ts:762
    mkdirSync(join(home, 'logs'), { recursive: true });
  • 发起网络请求
    desktop/sidecar/src/dsh-auth.ts:49
    const res = await fetch(launchUrl, { redirect: 'manual' } as RequestInit);
  • 发起网络请求
    desktop/sidecar/src/dsh-auth.ts:149
    const r = await fetch(base, {
  • 发起网络请求
    desktop/sidecar/src/dsh-auth.ts:167
    const r = await fetch(base, {
  • 发起网络请求
    desktop/sidecar/src/dsh-auth.ts:181
    const r = await fetch(base, { signal: AbortSignal.timeout(2000) });
  • 发起网络请求
    desktop/sidecar/src/engine-updater.ts:201
    const r = await fetch(`http://127.0.0.1:${port}/`, { signal: AbortSignal.timeout(2_000) });
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:31
    if (!existsSync(modulesDir)) return [];
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:35
    const stat = lstatSync(path);
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:37
    if (readdirSync(path).length === 0) {
  • 删除本地文件递归
    desktop/sidecar/src/fallback-repair.ts:38
    rmSync(path, { recursive: true, force: true });
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:47
    entries = readdirSync(modulesDir);
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:57
    if (lstatSync(scope).isSymbolicLink()) continue;
  • 读取本地文件
    desktop/sidecar/src/fallback-repair.ts:60
    inner = readdirSync(scope);
  • 读取本地文件
    desktop/sidecar/src/index.ts:56
    if (existsSync(join(engineDist, 'apps', 'cli', 'lib', 'bin.js'))) {
  • 删除本地文件递归
    desktop/sidecar/src/index.ts:60
    rmSync(join(dshHome, 'engine.prev'), { recursive: true, force: true });
  • 删除本地文件递归
    desktop/sidecar/src/index.ts:61
    rmSync(join(dshHome, 'engine.staging'), { recursive: true, force: true });
  • 执行外部命令来自配置/变量
    desktop/sidecar/src/index.ts:144
    const child = spawn(process.execPath, [entry, ...webArgs], {
  • 执行外部命令固定命令
    desktop/sidecar/src/index.ts:203
    const child = spawn('pnpm', ['dsh', 'web'], {
  • 读取密钥环境变量
    desktop/sidecar/src/index.ts:267
    const controlToken = process.env.DSHD_CONTROL_TOKEN ?? 'dev';
  • 读取本地文件
    desktop/sidecar/src/lan-bind.ts:295
    engineVersion = JSON.parse(readFileSync(join(dshRoot, '.engine-ref.json'), 'utf8'))
  • 读取本地文件
    desktop/sidecar/src/lan-bind.ts:313
    patchText = readFileSync(patchFile, 'utf8');
  • 写入本地文件
    desktop/sidecar/src/lan-bind.ts:323
    copyFileSync(patchFile, backupPath);
  • 写入本地文件
    desktop/sidecar/src/lan-bind.ts:324
    mkdirSync(join(dshHome, 'profiles', 'web'), { recursive: true });
  • 写入本地文件
    desktop/sidecar/src/lan-bind.ts:326
    writeFileSync(tmpFile, migration.text, 'utf8');
  • 写入本地文件
    desktop/sidecar/src/lan-bind.ts:327
    renameSync(tmpFile, patchFile);
  • 发起网络请求
    desktop/sidecar/src/net.ts:20
    const agent = new ProxyAgent(proxy);
  • 执行外部命令固定命令
    desktop/sidecar/src/net.ts:46
    const out = execFileSync('scutil', ['--proxy'], { encoding: 'utf8' });
  • 执行外部命令固定命令
    desktop/sidecar/src/net.ts:70
    const enable = execFileSync('reg', ['query', KEY, '/v', 'ProxyEnable'], { encoding: 'utf8' });
  • 执行外部命令固定命令
    desktop/sidecar/src/net.ts:72
    const server = execFileSync('reg', ['query', KEY, '/v', 'ProxyServer'], { encoding: 'utf8' });
  • 发起网络请求
    desktop/sidecar/src/net.ts:121
    return fetch(url, { ...(init ?? {}), headers });
  • 发起网络请求
    desktop/sidecar/src/net.ts:123
    return fetch(url, {
  • 读取本地文件
    desktop/sidecar/src/patch-migration.ts:137
    engineVersion = JSON.parse(readFileSync(join(dshRoot, '.engine-ref.json'), 'utf8'))
  • 读取本地文件
    desktop/sidecar/src/patch-migration.ts:148
    patchText = readFileSync(patchFile, 'utf8');
  • 写入本地文件
    desktop/sidecar/src/patch-migration.ts:156
    copyFileSync(patchFile, backupPath);
  • 写入本地文件
    desktop/sidecar/src/patch-migration.ts:157
    mkdirSync(dirname(patchFile), { recursive: true });
  • 写入本地文件
    desktop/sidecar/src/patch-migration.ts:159
    writeFileSync(tmpFile, migration.text, 'utf8');
  • 写入本地文件
    desktop/sidecar/src/patch-migration.ts:160
    renameSync(tmpFile, patchFile);
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:124
    if (existsSync(file)) {
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:125
    const st = lstatSync(file);
  • 写入本地文件
    desktop/sidecar/src/plugin-manager.ts:131
    writeFileSync(tmp, content, { mode: 0o755 });
  • 写入本地文件
    desktop/sidecar/src/plugin-manager.ts:132
    renameSync(tmp, file);
  • 写入本地文件
    desktop/sidecar/src/plugin-manager.ts:138
    mkdirSync(dir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    desktop/sidecar/src/plugin-manager.ts:186
    mkdirSync(logsDir, { recursive: true });
  • 写入本地文件
    desktop/sidecar/src/plugin-manager.ts:187
    appendFileSync(join(logsDir, 'dshd-diag.log'), `[${new Date().toISOString()}] [PluginManager] ${msg}\n`);
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:208
    cachedPage = readFileSync(file, 'utf8');
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:427
    if (!existsSync(pkgFile)) return { plugins: [] };
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:430
    plugins = parseProfilePackage(JSON.parse(readFileSync(pkgFile, 'utf8')));
  • 读取本地文件
    desktop/sidecar/src/plugin-manager.ts:438
    if (existsSync(nm)) {
  • 执行外部命令固定命令
    desktop/sidecar/src/plugin-manager.ts:523
    child = spawn('pnpm', ['dsh', 'plugin', '--profile', 'web', job.action, ...args], {
  • 执行外部命令来自配置/变量
    desktop/sidecar/src/plugin-manager.ts:531
    child = spawn(
  • 执行外部命令固定命令
    desktop/sidecar/src/plugin-manager.ts:614
    execFile('taskkill', ['/pid', String(pid), '/T', '/F'], () => {});
  • 读取密钥环境变量
    desktop/sidecar/src/updater.ts:193
    return process.env.DSHD_CONTROL_TOKEN ?? '';
  • 发起网络请求
    desktop/sidecar/src/updater.ts:204
    await fetch(`http://127.0.0.1:${port}${pathname}`, {
  • 执行外部命令固定命令
    desktop/sidecar/src/updater.ts:493
    execFileSync('codesign', ['-dv', process.execPath], {
  • 发起网络请求
    desktop/src-tauri/boot-watch.js:40
    fetch(ctlUrl, { method: 'POST', mode: 'no-cors' }).catch(function () {});
  • 发起网络请求
    desktop/src-tauri/theme-watch.js:30
    fetch(api, {
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

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

功能亮点

  • 体积小
  • 速度快

README

由 DeepSeek 最新模型翻译生成
DSH Desktop 基于 DeepSeek Harness 构建的社区桌面版本 —— 本项目是基于 DeepSeek Harness 构建的社区桌面版本,并非 DeepSeek 官方产品。 English · 中文 DSH Desktop 将官方 DeepSeek Harness(dsh)智能体框架封装为原生桌面应用,支持 Windows (x64) 与 macOS(Intel x64 + Apple Silicon arm64)。项目采用 Tauri 2 + Node.js sidecar 的「壳 + 副进程」架构(该架构参考了 OhMyAgent 并已被验证成熟)。 用户无需执行 npx @deepseek-ai/dsh web 或长期开着终端:安装即用。应用内置运行时启动本地 dsh web 服务,WebView 以同源方式加载 http://127.0.0.1:3080,托盘图标、单实例保护和自动更新等桌面能力开箱即用。 免责声明 本项目是基于 DeepSeek Harness 构建的社区桌面版本,并非 DeepSeek 官方产品。DeepSeek Harness 的核心能力、插件系统与 Web UI 均来自官方开源项目(MIT 协议)。如需通过命令行运行 Harness 或参与核心功能开发,请优先使用官方仓库。
展开完整文档(README 剩余 1 节)
DSH Desktop

基于 DeepSeek Harness 构建的社区桌面版本 —— 本项目是基于 DeepSeek Harness 构建的社区桌面版本,并非 DeepSeek 官方产品。

English · 中文

DSH Desktop 将官方 DeepSeek Harness(dsh)智能体框架封装为原生桌面应用,支持 Windows (x64) 与 macOS(Intel x64 + Apple Silicon arm64)。项目采用 Tauri 2 + Node.js sidecar 的「壳 + 副进程」架构(该架构参考了 OhMyAgent 并已被验证成熟)。

用户无需执行 npx @deepseek-ai/dsh web 或长期开着终端:安装即用。应用内置运行时启动本地 dsh web 服务,WebView 以同源方式加载 http://127.0.0.1:3080,托盘图标、单实例保护和自动更新等桌面能力开箱即用。

免责声明

本项目是基于 DeepSeek Harness 构建的社区桌面版本,并非 DeepSeek 官方产品。DeepSeek Harness 的核心能力、插件系统与 Web UI 均来自官方开源项目(MIT 协议)。如需通过命令行运行 Harness 或参与核心功能开发,请优先使用官方仓库。

特性

- 开箱即用 —— 内置 Node.js 运行时与预构建的 dsh 闭包,无需安装 Node.js、无需命令行;安装后配置 API Key 即可使用
- 支持三平台 —— 每个版本自动构建 Windows x64、macOS Intel (x64)、macOS Apple Silicon (arm64) 三平台安装包
- 支持在线更新 —— 应用内自动检查 GitHub Releases 新版本;Windows 一键下载安装,macOS(未签名)引导打开 Releases 页面
- 引擎通道 —— 内置 dsh 闭包还可从独立的 engine release 在应用内更新;上游 DeepSeek Harness 发版时,已安装的桌面端无需重装即可获得
- Tauri 2 壳 —— 原生、轻量、启动快;Windows 使用 WebView2,macOS 使用 WKWebView
- 仅限本地 —— dsh 只监听 http://127.0.0.1:3080,同源加载,无远程网关
- 健壮的生命周期管理 —— 壳拉起 sidecar、sidecar 拉起 dsh web;心跳检测 + Windows Job Object 保证退出/崩溃/卸载后无孤儿进程
- 系统托盘 + 单实例 —— 最小化到托盘、关闭到托盘、开机自启、防重复启动
- 定制鲸鱼图标 —— 原创鲸鱼标识,白圆底构图独立设计;任务栏/托盘图标清晰,注入式标题栏支持深色模式
- 无边框 + 注入式标题栏 —— 不改上游源码:拖拽区 + 最小化/最大化/关闭按钮悬浮覆盖页面,随主题变色
- 确定性依赖跟随 —— 构建产物与 desktop/dsh-ref.json 钉住的上游 commit 一一对应(单一模式 git-follow,无 fork、无补丁冲突)

工作原理

┌────────────────────────────────────────────────────────────┐
│ Tauri 2 壳(Rust) │ │ 窗口 · 托盘 · 单实例 · 开机自启 · Job Object │ └──────────────────────┬─────────────────────────────────────┘ │ 拉起 / 守护 ┌──────────────────────▼─────────────────────────────────────┐ │ Node.js sidecar(内置 Node 24 运行时) │ │ 拉起 dsh web · 就绪探测 · 控制 API │ │ 心跳 · 自动更新 │ └──────────────────────┬─────────────────────────────────────┘ │ 拉起 ┌──────────────────────▼─────────────────────────────────────┐ │ dsh(DeepSeek Harness,钉住的上游 commit) │ │ http://127.0.0.1:3080(WebView 同源加载 WebUI) │ └────────────────────────────────────────────────────────────┘

关键决策:

- 不 fork、不打上游补丁 —— desktop/scripts/fetch-dsh.cjs 在钉住的 commit 上抓取并构建 dsh;升级 dsh 是一条命令 + 一次回归测试,而不是一次合并
- 内置运行时 + 扁平化闭包 —— 安装包内携带官方 Node 运行时与裁剪后的、按平台匹配的 node_modules 闭包;node-pty / koffi / sharp 等原生二进制按目标平台裁剪
- 仅本地安全模型 —— dsh 本身无鉴权层;应用坚持仅本地监听,不做任何远程访问

安装

从 Releases 页面下载最新安装包:

| 平台 | 安装包 |
| Windows x64 | DSH-Desktop-Setup-<版本>.exe(NSIS,LZMA 压缩) |
| macOS Intel | DSH-Desktop-<版本>.dmg |
| macOS Apple Silicon | DSH-Desktop-<版本>-arm64.dmg |

说明:

- Windows:安装包自带 WebView2 引导程序,按当前用户安装;应用内更新从 GitHub Releases 下载
- macOS:无付费证书(ad-hoc 签名),首次打开 Gatekeeper 会提示 —— 右键 → 打开即可

开发

前置条件

- Node.js 24(与内置运行时一致;dsh 要求 ^22.19 || >=24)
- pnpm 11
- Rust(Windows 用 MSVC 工具链,macOS 用 Xcode CLT)
- Tauri 2 系统依赖(WebView2 / WKWebView)

常用命令

pnpm install # 安装壳 + sidecar 依赖
pnpm dev # Tauri 开发模式(dsh web 运行在 http://127.0.0.1:3080)
pnpm test # 单元测试(vitest)
pnpm lint # TypeScript 类型检查

dsh 默认占用 3080 端口,开发前先清理残留进程:

fuser -k 3080/tcp 2>/dev/null
pkill -f "dsh web" 2>/dev/null

构建安装包

Windows(PowerShell):

cd desktop
.\scripts\build.ps1 # 从 WSL 同步 → fetch dsh → bundle → NSIS

macOS / CI:

cd desktop
npx tauri build --bundles app # 产出 .app;dmg 在 CI 中用 hdiutil 组装

构建完全可复现:desktop/dsh-ref.json 钉住上游 commit,CI 对 dsh 闭包、Node 运行时与 cargo 产物做了缓存。

目录结构

desktop/
src-tauri/ # Rust 壳(窗口、托盘、单实例、配置) sidecar/ # Node sidecar TS(拉起 dsh、控制 API、更新器) scripts/ # fetch-dsh / fetch-node / bundle-deps / build.ps1 / release-meta dsh-ref.json # 钉住的上游 ref(单一模式 git-follow 清单) assets/ # 图标源文件 ui/ # splash / error 页面 .github/workflows/ # 发布矩阵 + 上游监视

贡献

欢迎贡献!有问题或功能建议请开 Issue,改动请提交 Pull Request。请遵守:

- 不修改上游 DeepSeek Harness 源码 —— 依赖变更一律通过 dsh-ref.json
- 保持 desktop/package.json 与 src-tauri/tauri.conf.json 版本一致
- 提交前确保 pnpm test 通过

许可证

MIT —— 见 LICENSE。第三方声明见 THIRD_PARTY_NOTICES.md。

DeepSeek Harness 与 DeepSeek 品牌商标归 DeepSeek AI 所有。本项目是独立的社区项目,与 DeepSeek 无隶属、背书或赞助关系。
预览分享卡片长什么样 ↓tscodeplus/dsh-desktop
分享 · DeepSeek Harness Hub
tscodeplus/dsh-desktop

体积小、速度快的 DeepSeek Harness 桌面端。

回到顶部